Home | History | Annotate | Download | only in afe
      1 #pylint: disable-msg=C0111
      2 #!/usr/bin/python
      3 
      4 import datetime
      5 import common
      6 
      7 from autotest_lib.frontend import setup_django_environment
      8 from autotest_lib.frontend.afe import frontend_test_utils
      9 from autotest_lib.frontend.afe import models, rpc_interface, frontend_test_utils
     10 from autotest_lib.frontend.afe import model_logic, model_attributes
     11 from autotest_lib.client.common_lib import global_config
     12 from autotest_lib.client.common_lib import control_data
     13 from autotest_lib.client.common_lib import error
     14 from autotest_lib.client.common_lib import priorities
     15 from autotest_lib.client.common_lib.test_utils import mock
     16 from autotest_lib.client.common_lib.test_utils import unittest
     17 from autotest_lib.server import frontend
     18 from autotest_lib.server import utils as server_utils
     19 from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
     20 
     21 CLIENT = control_data.CONTROL_TYPE_NAMES.CLIENT
     22 SERVER = control_data.CONTROL_TYPE_NAMES.SERVER
     23 
     24 _hqe_status = models.HostQueueEntry.Status
     25 
     26 
     27 class RpcInterfaceTest(unittest.TestCase,
     28                        frontend_test_utils.FrontendTestMixin):
     29     def setUp(self):
     30         self._frontend_common_setup()
     31         self.god = mock.mock_god()
     32 
     33 
     34     def tearDown(self):
     35         self.god.unstub_all()
     36         self._frontend_common_teardown()
     37         global_config.global_config.reset_config_values()
     38 
     39 
     40     def test_validation(self):
     41         # non-number for a numeric field
     42         self.assertRaises(model_logic.ValidationError,
     43                           rpc_interface.add_atomic_group, name='foo',
     44                           max_number_of_machines='bar')
     45         # omit a required field
     46         self.assertRaises(model_logic.ValidationError, rpc_interface.add_label,
     47                           name=None)
     48         # violate uniqueness constraint
     49         self.assertRaises(model_logic.ValidationError, rpc_interface.add_host,
     50                           hostname='host1')
     51 
     52 
     53     def test_multiple_platforms(self):
     54         platform2 = models.Label.objects.create(name='platform2', platform=True)
     55         self.assertRaises(model_logic.ValidationError,
     56                           rpc_interface. label_add_hosts, id='platform2',
     57                           hosts=['host1', 'host2'])
     58         self.assertRaises(model_logic.ValidationError,
     59                           rpc_interface.host_add_labels,
     60                           id='host1', labels=['platform2'])
     61         # make sure the platform didn't get added
     62         platforms = rpc_interface.get_labels(
     63             host__hostname__in=['host1', 'host2'], platform=True)
     64         self.assertEquals(len(platforms), 1)
     65         self.assertEquals(platforms[0]['name'], 'myplatform')
     66 
     67 
     68     def _check_hostnames(self, hosts, expected_hostnames):
     69         self.assertEquals(set(host['hostname'] for host in hosts),
     70                           set(expected_hostnames))
     71 
     72 
     73     def test_get_hosts(self):
     74         hosts = rpc_interface.get_hosts()
     75         self._check_hostnames(hosts, [host.hostname for host in self.hosts])
     76 
     77         hosts = rpc_interface.get_hosts(hostname='host1')
     78         self._check_hostnames(hosts, ['host1'])
     79         host = hosts[0]
     80         self.assertEquals(sorted(host['labels']), ['label1', 'myplatform'])
     81         self.assertEquals(host['platform'], 'myplatform')
     82         self.assertEquals(host['atomic_group'], None)
     83         self.assertEquals(host['acls'], ['my_acl'])
     84         self.assertEquals(host['attributes'], {})
     85 
     86 
     87     def test_get_hosts_multiple_labels(self):
     88         hosts = rpc_interface.get_hosts(
     89                 multiple_labels=['myplatform', 'label1'])
     90         self._check_hostnames(hosts, ['host1'])
     91 
     92 
     93     def test_get_hosts_exclude_only_if_needed(self):
     94         self.hosts[0].labels.add(self.label3)
     95 
     96         hosts = rpc_interface.get_hosts(hostname__in=['host1', 'host2'],
     97                                         exclude_only_if_needed_labels=True)
     98         self._check_hostnames(hosts, ['host2'])
     99 
    100 
    101     def test_get_hosts_exclude_atomic_group_hosts(self):
    102         hosts = rpc_interface.get_hosts(
    103                 exclude_atomic_group_hosts=True,
    104                 hostname__in=['host4', 'host5', 'host6'])
    105         self._check_hostnames(hosts, ['host4'])
    106 
    107 
    108     def test_get_hosts_exclude_both(self):
    109         self.hosts[0].labels.add(self.label3)
    110 
    111         hosts = rpc_interface.get_hosts(
    112                 hostname__in=['host1', 'host2', 'host5'],
    113                 exclude_only_if_needed_labels=True,
    114                 exclude_atomic_group_hosts=True)
    115         self._check_hostnames(hosts, ['host2'])
    116 
    117 
    118     def test_job_keyvals(self):
    119         keyval_dict = {'mykey': 'myvalue'}
    120         job_id = rpc_interface.create_job(name='test', priority='Medium',
    121                                           control_file='foo',
    122                                           control_type=CLIENT,
    123                                           hosts=['host1'],
    124                                           keyvals=keyval_dict)
    125         jobs = rpc_interface.get_jobs(id=job_id)
    126         self.assertEquals(len(jobs), 1)
    127         self.assertEquals(jobs[0]['keyvals'], keyval_dict)
    128 
    129 
    130     def test_test_retry(self):
    131         job_id = rpc_interface.create_job(name='flake', priority='Medium',
    132                                           control_file='foo',
    133                                           control_type=CLIENT,
    134                                           hosts=['host1'],
    135                                           test_retry=10)
    136         jobs = rpc_interface.get_jobs(id=job_id)
    137         self.assertEquals(len(jobs), 1)
    138         self.assertEquals(jobs[0]['test_retry'], 10)
    139 
    140 
    141     def test_get_jobs_summary(self):
    142         job = self._create_job(hosts=xrange(1, 4))
    143         entries = list(job.hostqueueentry_set.all())
    144         entries[1].status = _hqe_status.FAILED
    145         entries[1].save()
    146         entries[2].status = _hqe_status.FAILED
    147         entries[2].aborted = True
    148         entries[2].save()
    149 
    150         # Mock up tko_rpc_interface.get_status_counts.
    151         self.god.stub_function_to_return(rpc_interface.tko_rpc_interface,
    152                                          'get_status_counts',
    153                                          None)
    154 
    155         job_summaries = rpc_interface.get_jobs_summary(id=job.id)
    156         self.assertEquals(len(job_summaries), 1)
    157         summary = job_summaries[0]
    158         self.assertEquals(summary['status_counts'], {'Queued': 1,
    159                                                      'Failed': 2})
    160 
    161 
    162     def _check_job_ids(self, actual_job_dicts, expected_jobs):
    163         self.assertEquals(
    164                 set(job_dict['id'] for job_dict in actual_job_dicts),
    165                 set(job.id for job in expected_jobs))
    166 
    167 
    168     def test_get_jobs_status_filters(self):
    169         HqeStatus = models.HostQueueEntry.Status
    170         def create_two_host_job():
    171             return self._create_job(hosts=[1, 2])
    172         def set_hqe_statuses(job, first_status, second_status):
    173             entries = job.hostqueueentry_set.all()
    174             entries[0].update_object(status=first_status)
    175             entries[1].update_object(status=second_status)
    176 
    177         queued = create_two_host_job()
    178 
    179         queued_and_running = create_two_host_job()
    180         set_hqe_statuses(queued_and_running, HqeStatus.QUEUED,
    181                            HqeStatus.RUNNING)
    182 
    183         running_and_complete = create_two_host_job()
    184         set_hqe_statuses(running_and_complete, HqeStatus.RUNNING,
    185                            HqeStatus.COMPLETED)
    186 
    187         complete = create_two_host_job()
    188         set_hqe_statuses(complete, HqeStatus.COMPLETED, HqeStatus.COMPLETED)
    189 
    190         started_but_inactive = create_two_host_job()
    191         set_hqe_statuses(started_but_inactive, HqeStatus.QUEUED,
    192                            HqeStatus.COMPLETED)
    193 
    194         parsing = create_two_host_job()
    195         set_hqe_statuses(parsing, HqeStatus.PARSING, HqeStatus.PARSING)
    196 
    197         self._check_job_ids(rpc_interface.get_jobs(not_yet_run=True), [queued])
    198         self._check_job_ids(rpc_interface.get_jobs(running=True),
    199                       [queued_and_running, running_and_complete,
    200                        started_but_inactive, parsing])
    201         self._check_job_ids(rpc_interface.get_jobs(finished=True), [complete])
    202 
    203 
    204     def test_get_jobs_type_filters(self):
    205         self.assertRaises(AssertionError, rpc_interface.get_jobs,
    206                           suite=True, sub=True)
    207         self.assertRaises(AssertionError, rpc_interface.get_jobs,
    208                           suite=True, standalone=True)
    209         self.assertRaises(AssertionError, rpc_interface.get_jobs,
    210                           standalone=True, sub=True)
    211 
    212         parent_job = self._create_job(hosts=[1])
    213         child_jobs = self._create_job(hosts=[1, 2],
    214                                       parent_job_id=parent_job.id)
    215         standalone_job = self._create_job(hosts=[1])
    216 
    217         self._check_job_ids(rpc_interface.get_jobs(suite=True), [parent_job])
    218         self._check_job_ids(rpc_interface.get_jobs(sub=True), [child_jobs])
    219         self._check_job_ids(rpc_interface.get_jobs(standalone=True),
    220                             [standalone_job])
    221 
    222 
    223     def _create_job_helper(self, **kwargs):
    224         return rpc_interface.create_job(name='test', priority='Medium',
    225                                         control_file='control file',
    226                                         control_type=SERVER, **kwargs)
    227 
    228 
    229     def test_one_time_hosts(self):
    230         job = self._create_job_helper(one_time_hosts=['testhost'])
    231         host = models.Host.objects.get(hostname='testhost')
    232         self.assertEquals(host.invalid, True)
    233         self.assertEquals(host.labels.count(), 0)
    234         self.assertEquals(host.aclgroup_set.count(), 0)
    235 
    236 
    237     def test_create_job_duplicate_hosts(self):
    238         self.assertRaises(model_logic.ValidationError, self._create_job_helper,
    239                           hosts=[1, 1])
    240 
    241 
    242     def test_create_unrunnable_metahost_job(self):
    243         self.assertRaises(error.NoEligibleHostException,
    244                           self._create_job_helper, meta_hosts=['unused'])
    245 
    246 
    247     def test_create_hostless_job(self):
    248         job_id = self._create_job_helper(hostless=True)
    249         job = models.Job.objects.get(pk=job_id)
    250         queue_entries = job.hostqueueentry_set.all()
    251         self.assertEquals(len(queue_entries), 1)
    252         self.assertEquals(queue_entries[0].host, None)
    253         self.assertEquals(queue_entries[0].meta_host, None)
    254         self.assertEquals(queue_entries[0].atomic_group, None)
    255 
    256 
    257     def _setup_special_tasks(self):
    258         host = self.hosts[0]
    259 
    260         job1 = self._create_job(hosts=[1])
    261         job2 = self._create_job(hosts=[1])
    262 
    263         entry1 = job1.hostqueueentry_set.all()[0]
    264         entry1.update_object(started_on=datetime.datetime(2009, 1, 2),
    265                              execution_subdir='host1')
    266         entry2 = job2.hostqueueentry_set.all()[0]
    267         entry2.update_object(started_on=datetime.datetime(2009, 1, 3),
    268                              execution_subdir='host1')
    269 
    270         self.task1 = models.SpecialTask.objects.create(
    271                 host=host, task=models.SpecialTask.Task.VERIFY,
    272                 time_started=datetime.datetime(2009, 1, 1), # ran before job 1
    273                 is_complete=True, requested_by=models.User.current_user())
    274         self.task2 = models.SpecialTask.objects.create(
    275                 host=host, task=models.SpecialTask.Task.VERIFY,
    276                 queue_entry=entry2, # ran with job 2
    277                 is_active=True, requested_by=models.User.current_user())
    278         self.task3 = models.SpecialTask.objects.create(
    279                 host=host, task=models.SpecialTask.Task.VERIFY,
    280                 requested_by=models.User.current_user()) # not yet run
    281 
    282 
    283     def test_get_special_tasks(self):
    284         self._setup_special_tasks()
    285         tasks = rpc_interface.get_special_tasks(host__hostname='host1',
    286                                                 queue_entry__isnull=True)
    287         self.assertEquals(len(tasks), 2)
    288         self.assertEquals(tasks[0]['task'], models.SpecialTask.Task.VERIFY)
    289         self.assertEquals(tasks[0]['is_active'], False)
    290         self.assertEquals(tasks[0]['is_complete'], True)
    291 
    292 
    293     def test_get_latest_special_task(self):
    294         # a particular usage of get_special_tasks()
    295         self._setup_special_tasks()
    296         self.task2.time_started = datetime.datetime(2009, 1, 2)
    297         self.task2.save()
    298 
    299         tasks = rpc_interface.get_special_tasks(
    300                 host__hostname='host1', task=models.SpecialTask.Task.VERIFY,
    301                 time_started__isnull=False, sort_by=['-time_started'],
    302                 query_limit=1)
    303         self.assertEquals(len(tasks), 1)
    304         self.assertEquals(tasks[0]['id'], 2)
    305 
    306 
    307     def _common_entry_check(self, entry_dict):
    308         self.assertEquals(entry_dict['host']['hostname'], 'host1')
    309         self.assertEquals(entry_dict['job']['id'], 2)
    310 
    311 
    312     def test_get_host_queue_entries_and_special_tasks(self):
    313         self._setup_special_tasks()
    314 
    315         host = self.hosts[0].id
    316         entries_and_tasks = (
    317                 rpc_interface.get_host_queue_entries_and_special_tasks(host))
    318 
    319         paths = [entry['execution_path'] for entry in entries_and_tasks]
    320         self.assertEquals(paths, ['hosts/host1/3-verify',
    321                                   '2-autotest_system/host1',
    322                                   'hosts/host1/2-verify',
    323                                   '1-autotest_system/host1',
    324                                   'hosts/host1/1-verify'])
    325 
    326         verify2 = entries_and_tasks[2]
    327         self._common_entry_check(verify2)
    328         self.assertEquals(verify2['type'], 'Verify')
    329         self.assertEquals(verify2['status'], 'Running')
    330         self.assertEquals(verify2['execution_path'], 'hosts/host1/2-verify')
    331 
    332         entry2 = entries_and_tasks[1]
    333         self._common_entry_check(entry2)
    334         self.assertEquals(entry2['type'], 'Job')
    335         self.assertEquals(entry2['status'], 'Queued')
    336         self.assertEquals(entry2['started_on'], '2009-01-03 00:00:00')
    337 
    338 
    339     def test_view_invalid_host(self):
    340         # RPCs used by View Host page should work for invalid hosts
    341         self._create_job_helper(hosts=[1])
    342         host = self.hosts[0]
    343         host.delete()
    344 
    345         self.assertEquals(1, rpc_interface.get_num_hosts(hostname='host1',
    346                                                          valid_only=False))
    347         data = rpc_interface.get_hosts(hostname='host1', valid_only=False)
    348         self.assertEquals(1, len(data))
    349 
    350         self.assertEquals(1, rpc_interface.get_num_host_queue_entries(
    351                 host__hostname='host1'))
    352         data = rpc_interface.get_host_queue_entries(host__hostname='host1')
    353         self.assertEquals(1, len(data))
    354 
    355         count = rpc_interface.get_num_host_queue_entries_and_special_tasks(
    356                 host=host.id)
    357         self.assertEquals(1, count)
    358         data = rpc_interface.get_host_queue_entries_and_special_tasks(
    359                 host=host.id)
    360         self.assertEquals(1, len(data))
    361 
    362 
    363     def test_reverify_hosts(self):
    364         hostname_list = rpc_interface.reverify_hosts(id__in=[1, 2])
    365         self.assertEquals(hostname_list, ['host1', 'host2'])
    366         tasks = rpc_interface.get_special_tasks()
    367         self.assertEquals(len(tasks), 2)
    368         self.assertEquals(set(task['host']['id'] for task in tasks),
    369                           set([1, 2]))
    370 
    371         task = tasks[0]
    372         self.assertEquals(task['task'], models.SpecialTask.Task.VERIFY)
    373         self.assertEquals(task['requested_by'], 'autotest_system')
    374 
    375 
    376     def test_repair_hosts(self):
    377         hostname_list = rpc_interface.repair_hosts(id__in=[1, 2])
    378         self.assertEquals(hostname_list, ['host1', 'host2'])
    379         tasks = rpc_interface.get_special_tasks()
    380         self.assertEquals(len(tasks), 2)
    381         self.assertEquals(set(task['host']['id'] for task in tasks),
    382                           set([1, 2]))
    383 
    384         task = tasks[0]
    385         self.assertEquals(task['task'], models.SpecialTask.Task.REPAIR)
    386         self.assertEquals(task['requested_by'], 'autotest_system')
    387 
    388 
    389     def test_parameterized_job(self):
    390         global_config.global_config.override_config_value(
    391                 'AUTOTEST_WEB', 'parameterized_jobs', 'True')
    392 
    393         string_type = model_attributes.ParameterTypes.STRING
    394 
    395         test = models.Test.objects.create(
    396                 name='test', test_type=control_data.CONTROL_TYPE.SERVER)
    397         test_parameter = test.testparameter_set.create(name='key')
    398         profiler = models.Profiler.objects.create(name='profiler')
    399 
    400         kernels = ({'version': 'version', 'cmdline': 'cmdline'},)
    401         profilers = ('profiler',)
    402         profiler_parameters = {'profiler': {'key': ('value', string_type)}}
    403         job_parameters = {'key': ('value', string_type)}
    404 
    405         job_id = rpc_interface.create_parameterized_job(
    406                 name='job', priority=priorities.Priority.DEFAULT, test='test',
    407                 parameters=job_parameters, kernel=kernels, label='label1',
    408                 profilers=profilers, profiler_parameters=profiler_parameters,
    409                 profile_only=False, hosts=('host1',))
    410         parameterized_job = models.Job.smart_get(job_id).parameterized_job
    411 
    412         self.assertEqual(parameterized_job.test, test)
    413         self.assertEqual(parameterized_job.label, self.labels[0])
    414         self.assertEqual(parameterized_job.kernels.count(), 1)
    415         self.assertEqual(parameterized_job.profilers.count(), 1)
    416 
    417         kernel = models.Kernel.objects.get(**kernels[0])
    418         self.assertEqual(parameterized_job.kernels.all()[0], kernel)
    419         self.assertEqual(parameterized_job.profilers.all()[0], profiler)
    420 
    421         parameterized_profiler = models.ParameterizedJobProfiler.objects.get(
    422                 parameterized_job=parameterized_job, profiler=profiler)
    423         profiler_parameters_obj = (
    424                 models.ParameterizedJobProfilerParameter.objects.get(
    425                 parameterized_job_profiler=parameterized_profiler))
    426         self.assertEqual(profiler_parameters_obj.parameter_name, 'key')
    427         self.assertEqual(profiler_parameters_obj.parameter_value, 'value')
    428         self.assertEqual(profiler_parameters_obj.parameter_type, string_type)
    429 
    430         self.assertEqual(
    431                 parameterized_job.parameterizedjobparameter_set.count(), 1)
    432         parameters_obj = (
    433                 parameterized_job.parameterizedjobparameter_set.all()[0])
    434         self.assertEqual(parameters_obj.test_parameter, test_parameter)
    435         self.assertEqual(parameters_obj.parameter_value, 'value')
    436         self.assertEqual(parameters_obj.parameter_type, string_type)
    437 
    438 
    439     def _modify_host_helper(self, on_shard=False, host_on_shard=False):
    440         shard_hostname = 'shard1'
    441         if on_shard:
    442             global_config.global_config.override_config_value(
    443                 'SHARD', 'shard_hostname', shard_hostname)
    444 
    445         host = models.Host.objects.all()[0]
    446         if host_on_shard:
    447             shard = models.Shard.objects.create(hostname=shard_hostname)
    448             host.shard = shard
    449             host.save()
    450 
    451         self.assertFalse(host.locked)
    452 
    453         self.god.stub_class_method(frontend.AFE, 'run')
    454 
    455         if host_on_shard and not on_shard:
    456             mock_afe = self.god.create_mock_class_obj(
    457                     frontend_wrappers.RetryingAFE, 'MockAFE')
    458             self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    459 
    460             mock_afe2 = frontend_wrappers.RetryingAFE.expect_new(
    461                     server=shard_hostname, user=None)
    462             mock_afe2.run.expect_call('modify_host_local', id=host.id,
    463                     locked=True, lock_reason='_modify_host_helper lock',
    464                     lock_time=datetime.datetime(2015, 12, 15))
    465         elif on_shard:
    466             mock_afe = self.god.create_mock_class_obj(
    467                     frontend_wrappers.RetryingAFE, 'MockAFE')
    468             self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    469 
    470             mock_afe2 = frontend_wrappers.RetryingAFE.expect_new(
    471                     server=server_utils.get_global_afe_hostname(), user=None)
    472             mock_afe2.run.expect_call('modify_host', id=host.id,
    473                     locked=True, lock_reason='_modify_host_helper lock',
    474                     lock_time=datetime.datetime(2015, 12, 15))
    475 
    476         rpc_interface.modify_host(id=host.id, locked=True,
    477                                   lock_reason='_modify_host_helper lock',
    478                                   lock_time=datetime.datetime(2015, 12, 15))
    479 
    480         host = models.Host.objects.get(pk=host.id)
    481         if on_shard:
    482             # modify_host on shard does nothing but routing the RPC to master.
    483             self.assertFalse(host.locked)
    484         else:
    485             self.assertTrue(host.locked)
    486         self.god.check_playback()
    487 
    488 
    489     def test_modify_host_on_master_host_on_master(self):
    490         """Call modify_host to master for host in master."""
    491         self._modify_host_helper()
    492 
    493 
    494     def test_modify_host_on_master_host_on_shard(self):
    495         """Call modify_host to master for host in shard."""
    496         self._modify_host_helper(host_on_shard=True)
    497 
    498 
    499     def test_modify_host_on_shard(self):
    500         """Call modify_host to shard for host in shard."""
    501         self._modify_host_helper(on_shard=True, host_on_shard=True)
    502 
    503 
    504     def test_modify_hosts_on_master_host_on_shard(self):
    505         """Ensure calls to modify_hosts are correctly forwarded to shards."""
    506         host1 = models.Host.objects.all()[0]
    507         host2 = models.Host.objects.all()[1]
    508 
    509         shard1 = models.Shard.objects.create(hostname='shard1')
    510         host1.shard = shard1
    511         host1.save()
    512 
    513         shard2 = models.Shard.objects.create(hostname='shard2')
    514         host2.shard = shard2
    515         host2.save()
    516 
    517         self.assertFalse(host1.locked)
    518         self.assertFalse(host2.locked)
    519 
    520         mock_afe = self.god.create_mock_class_obj(frontend_wrappers.RetryingAFE,
    521                                                   'MockAFE')
    522         self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    523 
    524         # The statuses of one host might differ on master and shard.
    525         # Filters are always applied on the master. So the host on the shard
    526         # will be affected no matter what his status is.
    527         filters_to_use = {'status': 'Ready'}
    528 
    529         mock_afe2 = frontend_wrappers.RetryingAFE.expect_new(
    530                 server='shard2', user=None)
    531         mock_afe2.run.expect_call(
    532             'modify_hosts_local',
    533             host_filter_data={'id__in': [shard1.id, shard2.id]},
    534             update_data={'locked': True,
    535                          'lock_reason': 'Testing forward to shard',
    536                          'lock_time' : datetime.datetime(2015, 12, 15) })
    537 
    538         mock_afe1 = frontend_wrappers.RetryingAFE.expect_new(
    539                 server='shard1', user=None)
    540         mock_afe1.run.expect_call(
    541             'modify_hosts_local',
    542             host_filter_data={'id__in': [shard1.id, shard2.id]},
    543             update_data={'locked': True,
    544                          'lock_reason': 'Testing forward to shard',
    545                          'lock_time' : datetime.datetime(2015, 12, 15)})
    546 
    547         rpc_interface.modify_hosts(
    548                 host_filter_data={'status': 'Ready'},
    549                 update_data={'locked': True,
    550                              'lock_reason': 'Testing forward to shard',
    551                              'lock_time' : datetime.datetime(2015, 12, 15) })
    552 
    553         host1 = models.Host.objects.get(pk=host1.id)
    554         self.assertTrue(host1.locked)
    555         host2 = models.Host.objects.get(pk=host2.id)
    556         self.assertTrue(host2.locked)
    557         self.god.check_playback()
    558 
    559 
    560     def test_delete_host(self):
    561         """Ensure an RPC is made on delete a host, if it is on a shard."""
    562         host1 = models.Host.objects.all()[0]
    563         shard1 = models.Shard.objects.create(hostname='shard1')
    564         host1.shard = shard1
    565         host1.save()
    566         host1_id = host1.id
    567 
    568         mock_afe = self.god.create_mock_class_obj(frontend_wrappers.RetryingAFE,
    569                                                  'MockAFE')
    570         self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    571 
    572         mock_afe1 = frontend_wrappers.RetryingAFE.expect_new(
    573                 server='shard1', user=None)
    574         mock_afe1.run.expect_call('delete_host', id=host1.id)
    575 
    576         rpc_interface.delete_host(id=host1.id)
    577 
    578         self.assertRaises(models.Host.DoesNotExist,
    579                           models.Host.smart_get, host1_id)
    580 
    581         self.god.check_playback()
    582 
    583 
    584     def test_modify_label(self):
    585         label1 = models.Label.objects.all()[0]
    586         self.assertEqual(label1.invalid, 0)
    587 
    588         host2 = models.Host.objects.all()[1]
    589         shard1 = models.Shard.objects.create(hostname='shard1')
    590         host2.shard = shard1
    591         host2.labels.add(label1)
    592         host2.save()
    593 
    594         mock_afe = self.god.create_mock_class_obj(frontend_wrappers.RetryingAFE,
    595                                                   'MockAFE')
    596         self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    597 
    598         mock_afe1 = frontend_wrappers.RetryingAFE.expect_new(
    599                 server='shard1', user=None)
    600         mock_afe1.run.expect_call('modify_label', id=label1.id, invalid=1)
    601 
    602         rpc_interface.modify_label(label1.id, invalid=1)
    603 
    604         self.assertEqual(models.Label.objects.all()[0].invalid, 1)
    605         self.god.check_playback()
    606 
    607 
    608     def test_delete_label(self):
    609         label1 = models.Label.objects.all()[0]
    610 
    611         host2 = models.Host.objects.all()[1]
    612         shard1 = models.Shard.objects.create(hostname='shard1')
    613         host2.shard = shard1
    614         host2.labels.add(label1)
    615         host2.save()
    616 
    617         mock_afe = self.god.create_mock_class_obj(frontend_wrappers.RetryingAFE,
    618                                                   'MockAFE')
    619         self.god.stub_with(frontend_wrappers, 'RetryingAFE', mock_afe)
    620 
    621         mock_afe1 = frontend_wrappers.RetryingAFE.expect_new(
    622                 server='shard1', user=None)
    623         mock_afe1.run.expect_call('delete_label', id=label1.id)
    624 
    625         rpc_interface.delete_label(id=label1.id)
    626 
    627         self.assertRaises(models.Label.DoesNotExist,
    628                           models.Label.smart_get, label1.id)
    629         self.god.check_playback()
    630 
    631 
    632 if __name__ == '__main__':
    633     unittest.main()
    634