You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
5.4 KiB
171 lines
5.4 KiB
# Copyright 2019 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import contextlib
|
|
import datetime
|
|
import unittest
|
|
|
|
import common
|
|
# import has side-effects, must appear before any django imports.
|
|
from autotest_lib.frontend import setup_django_environment
|
|
|
|
from autotest_lib.frontend import setup_test_environment
|
|
from autotest_lib.frontend.afe import models
|
|
|
|
|
|
class ShardHeartbeatTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self._tag_creator = _TagCreator('ShardHeartbeatTest')
|
|
setup_test_environment.set_up()
|
|
|
|
|
|
def tearDown(self):
|
|
setup_test_environment.tear_down()
|
|
|
|
|
|
def testJobsWithDepsIsFilteredByShardLabel(self):
|
|
label = self._create_label()
|
|
shard = self._create_shard(label)
|
|
job = self._create_job_with_label(label)
|
|
# Should not be assigned.
|
|
self._create_job_with_label(self._create_label())
|
|
|
|
assigned = models.Job.assign_to_shard(shard, [])
|
|
self.assertEqual(set(assigned), {job})
|
|
|
|
|
|
def testJobsForHostsIsFilteredByShardLabel(self):
|
|
label = self._create_label()
|
|
shard = self._create_shard(label)
|
|
job = self._create_job_for_host(self._create_host(label))
|
|
# Should not be assigned.
|
|
self._create_job_for_host(self._create_host(self._create_label()))
|
|
|
|
assigned = models.Job.assign_to_shard(shard, [])
|
|
self.assertEqual(set(assigned), {job})
|
|
|
|
|
|
def testJobsWithKnownIDsIsIgnored(self):
|
|
label = self._create_label()
|
|
shard = self._create_shard(label)
|
|
known_job = self._create_job_with_label(label)
|
|
new_job = self._create_job_with_label(label)
|
|
assigned_jobs = models.Job.assign_to_shard(shard, [known_job.id])
|
|
self.assertEqual(set(assigned_jobs), {new_job})
|
|
|
|
|
|
def testOldJobsAreIgnoredWhenOptionEnabled(self):
|
|
with self._ignore_jobs_older_than(2):
|
|
label = self._create_label()
|
|
shard = self._create_shard(label)
|
|
job = self._create_job_with_label(label)
|
|
# Should not be assigned.
|
|
self._create_job_with_label(label, datetime.timedelta(hours=3))
|
|
assigned = models.Job.assign_to_shard(shard, [])
|
|
self.assertEqual(set(assigned), {job})
|
|
|
|
|
|
def testOldJobsAreNotIgnoredWhenOptionDisabled(self):
|
|
with self._ignore_jobs_older_than(0):
|
|
label = self._create_label()
|
|
shard = self._create_shard(label)
|
|
job = self._create_job_with_label(label,
|
|
datetime.timedelta(hours=3))
|
|
assigned = models.Job.assign_to_shard(shard, [])
|
|
self.assertEqual(set(assigned), {job})
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def _ignore_jobs_older_than(self, value):
|
|
old = models.Job.SKIP_JOBS_CREATED_BEFORE
|
|
try:
|
|
models.Job.SKIP_JOBS_CREATED_BEFORE = value
|
|
yield
|
|
finally:
|
|
models.Job.SKIP_JOBS_CREATED_BEFORE = old
|
|
|
|
|
|
def _create_job_for_host(self, host, pending_age=None):
|
|
"""Create a job for the given host created pending_age ago.
|
|
|
|
@param host: A models.Host object.
|
|
@param pending_age: A datetime.datetime object.
|
|
@return: A models.Job object.
|
|
"""
|
|
job = models.Job.objects.create(
|
|
name=self._tag_creator.next(),
|
|
created_on=_past_timestamp(pending_age),
|
|
)
|
|
hqe = models.HostQueueEntry.objects.create(
|
|
job=job,
|
|
host_id=host.id,
|
|
status=models.HostQueueEntry.Status.QUEUED,
|
|
)
|
|
return job
|
|
|
|
|
|
def _create_job_with_label(self, label, pending_age=None):
|
|
"""Create a job for the given label created pending_age ago.
|
|
|
|
@param host: A models.Label object.
|
|
@param pending_age: A datetime.datetime object.
|
|
@return: A models.Job object.
|
|
"""
|
|
job = models.Job.objects.create(
|
|
name=self._tag_creator.next(),
|
|
created_on=_past_timestamp(pending_age),
|
|
)
|
|
job.dependency_labels.add(label)
|
|
hqe = models.HostQueueEntry.objects.create(
|
|
job=job,
|
|
meta_host_id=label.id,
|
|
status=models.HostQueueEntry.Status.QUEUED,
|
|
)
|
|
return job
|
|
|
|
|
|
def _create_host(self, label):
|
|
"""Create a models.Host with the given models.Label."""
|
|
host = models.Host.objects.create(hostname=self._tag_creator.next())
|
|
host.labels.add(label)
|
|
return host
|
|
|
|
|
|
def _create_label(self):
|
|
"""Create a models.Label."""
|
|
return models.Label.objects.create(name=self._tag_creator.next())
|
|
|
|
|
|
def _create_shard(self, label):
|
|
"""Create a models.Shard with the givem models.Label."""
|
|
shard = models.Shard.objects.create(hostname=self._tag_creator.next())
|
|
shard.labels.add(label)
|
|
return shard
|
|
|
|
|
|
class _TagCreator(object):
|
|
"""Create unique but deterministic str tags by calling next()."""
|
|
def __init__(self, prefix):
|
|
self._prefix = prefix
|
|
self._count = 0
|
|
|
|
def next(self):
|
|
self._count += 1
|
|
return self._prefix + str(self._count)
|
|
|
|
|
|
def _past_timestamp(delta=None):
|
|
"""Compute datetime.datetime given timedelta in the past.
|
|
|
|
@param delta: A datetime.timedelta object.
|
|
@return: A datetime.datetime object.
|
|
"""
|
|
now = datetime.datetime.now()
|
|
if delta is None:
|
|
return now
|
|
return now - delta
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main() |