1*9c5db199SXin Li#!/usr/bin/python3 2*9c5db199SXin Li# pylint: disable=missing-docstring 3*9c5db199SXin Li 4*9c5db199SXin Liimport unittest 5*9c5db199SXin Li 6*9c5db199SXin Liimport common 7*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 8*9c5db199SXin Lifrom autotest_lib.frontend import setup_django_environment 9*9c5db199SXin Lifrom autotest_lib.frontend.afe import frontend_test_utils 10*9c5db199SXin Lifrom autotest_lib.frontend.afe import models, model_logic 11*9c5db199SXin Li 12*9c5db199SXin Li 13*9c5db199SXin Liclass AclGroupTest(unittest.TestCase, 14*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 15*9c5db199SXin Li def setUp(self): 16*9c5db199SXin Li self._frontend_common_setup() 17*9c5db199SXin Li 18*9c5db199SXin Li 19*9c5db199SXin Li def tearDown(self): 20*9c5db199SXin Li self._frontend_common_teardown() 21*9c5db199SXin Li 22*9c5db199SXin Li 23*9c5db199SXin Li def _check_acls(self, host, acl_name_list): 24*9c5db199SXin Li actual_acl_names = [acl_group.name for acl_group 25*9c5db199SXin Li in host.aclgroup_set.all()] 26*9c5db199SXin Li self.assertEquals(set(actual_acl_names), set(acl_name_list)) 27*9c5db199SXin Li 28*9c5db199SXin Li 29*9c5db199SXin Li def test_on_host_membership_change(self): 30*9c5db199SXin Li host1, host2 = self.hosts[1:3] 31*9c5db199SXin Li everyone_acl = models.AclGroup.objects.get(name='Everyone') 32*9c5db199SXin Li 33*9c5db199SXin Li host1.aclgroup_set.clear() 34*9c5db199SXin Li self._check_acls(host1, []) 35*9c5db199SXin Li host2.aclgroup_set.add(everyone_acl) 36*9c5db199SXin Li self._check_acls(host2, ['Everyone', 'my_acl']) 37*9c5db199SXin Li 38*9c5db199SXin Li models.AclGroup.on_host_membership_change() 39*9c5db199SXin Li 40*9c5db199SXin Li self._check_acls(host1, ['Everyone']) 41*9c5db199SXin Li self._check_acls(host2, ['my_acl']) 42*9c5db199SXin Li 43*9c5db199SXin Li 44*9c5db199SXin Liclass HostTest(unittest.TestCase, 45*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 46*9c5db199SXin Li def setUp(self): 47*9c5db199SXin Li self._frontend_common_setup() 48*9c5db199SXin Li 49*9c5db199SXin Li 50*9c5db199SXin Li def tearDown(self): 51*9c5db199SXin Li self._frontend_common_teardown() 52*9c5db199SXin Li 53*9c5db199SXin Li 54*9c5db199SXin Li def _get_attributes(self, host): 55*9c5db199SXin Li models.Host.objects.populate_relationships( 56*9c5db199SXin Li [host], models.HostAttribute, 'attribute_list') 57*9c5db199SXin Li return dict((attribute.attribute, attribute.value) 58*9c5db199SXin Li for attribute in host.attribute_list) 59*9c5db199SXin Li 60*9c5db199SXin Li def test_delete_attribute(self): 61*9c5db199SXin Li previous_config = models.RESPECT_STATIC_ATTRIBUTES 62*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = False 63*9c5db199SXin Li host1 = models.Host.objects.create(hostname='test_host1') 64*9c5db199SXin Li host1.set_attribute('test_attribute1', 'test_value1') 65*9c5db199SXin Li 66*9c5db199SXin Li attributes = self._get_attributes(host1) 67*9c5db199SXin Li self.assertEquals(attributes['test_attribute1'], 'test_value1') 68*9c5db199SXin Li 69*9c5db199SXin Li host1.set_or_delete_attribute('test_attribute1', None) 70*9c5db199SXin Li attributes = self._get_attributes(host1) 71*9c5db199SXin Li self.assertNotIn('test_attribute1', attributes.keys()) 72*9c5db199SXin Li 73*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = previous_config 74*9c5db199SXin Li 75*9c5db199SXin Li 76*9c5db199SXin Li def test_delete_static_attribute(self): 77*9c5db199SXin Li previous_config = models.RESPECT_STATIC_ATTRIBUTES 78*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = True 79*9c5db199SXin Li host1 = models.Host.objects.create(hostname='test_host1') 80*9c5db199SXin Li host1.set_attribute('test_attribute1', 'test_value1') 81*9c5db199SXin Li self._set_static_attribute(host1, 'test_attribute1', 'test_value1') 82*9c5db199SXin Li 83*9c5db199SXin Li self.assertRaises( 84*9c5db199SXin Li error.UnmodifiableAttributeException, 85*9c5db199SXin Li host1.set_or_delete_attribute, 86*9c5db199SXin Li 'test_attribute1', None) 87*9c5db199SXin Li 88*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = previous_config 89*9c5db199SXin Li 90*9c5db199SXin Li 91*9c5db199SXin Li def test_set_attribute(self): 92*9c5db199SXin Li previous_config = models.RESPECT_STATIC_ATTRIBUTES 93*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = False 94*9c5db199SXin Li host1 = models.Host.objects.create(hostname='test_host1') 95*9c5db199SXin Li host1.set_attribute('test_attribute1', 'test_value1') 96*9c5db199SXin Li 97*9c5db199SXin Li host1.set_or_delete_attribute('test_attribute1', 'test_new_value1') 98*9c5db199SXin Li 99*9c5db199SXin Li attributes = self._get_attributes(host1) 100*9c5db199SXin Li self.assertEquals(attributes['test_attribute1'], 'test_new_value1') 101*9c5db199SXin Li 102*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = previous_config 103*9c5db199SXin Li 104*9c5db199SXin Li 105*9c5db199SXin Li def test_set_static_attribute(self): 106*9c5db199SXin Li previous_config = models.RESPECT_STATIC_ATTRIBUTES 107*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = True 108*9c5db199SXin Li host1 = models.Host.objects.create(hostname='test_host1') 109*9c5db199SXin Li host1.set_attribute('test_attribute1', 'test_value1') 110*9c5db199SXin Li self._set_static_attribute(host1, 'test_attribute1', 'test_value1') 111*9c5db199SXin Li 112*9c5db199SXin Li self.assertRaises( 113*9c5db199SXin Li error.UnmodifiableAttributeException, 114*9c5db199SXin Li host1.set_or_delete_attribute, 115*9c5db199SXin Li 'test_attribute1', 'test_value2') 116*9c5db199SXin Li 117*9c5db199SXin Li models.RESPECT_STATIC_ATTRIBUTES = previous_config 118*9c5db199SXin Li 119*9c5db199SXin Li 120*9c5db199SXin Li def test_add_host_previous_one_time_host(self): 121*9c5db199SXin Li # ensure that when adding a host which was previously used as a one-time 122*9c5db199SXin Li # host, the status isn't reset, since this can interfere with the 123*9c5db199SXin Li # scheduler. 124*9c5db199SXin Li host = models.Host.create_one_time_host('othost') 125*9c5db199SXin Li self.assertEquals(host.invalid, True) 126*9c5db199SXin Li self.assertEquals(host.status, models.Host.Status.READY) 127*9c5db199SXin Li 128*9c5db199SXin Li host.status = models.Host.Status.RUNNING 129*9c5db199SXin Li host.save() 130*9c5db199SXin Li 131*9c5db199SXin Li host2 = models.Host.add_object(hostname='othost') 132*9c5db199SXin Li self.assertEquals(host2.id, host.id) 133*9c5db199SXin Li self.assertEquals(host2.status, models.Host.Status.RUNNING) 134*9c5db199SXin Li 135*9c5db199SXin Li 136*9c5db199SXin Li def test_check_board_labels_allowed(self): 137*9c5db199SXin Li host = models.Host.create_one_time_host('othost') 138*9c5db199SXin Li # First check with host with no board label. 139*9c5db199SXin Li self.assertEqual(host.check_board_labels_allowed([host]), None) 140*9c5db199SXin Li 141*9c5db199SXin Li # Second check with host with board label 142*9c5db199SXin Li label = models.Label.add_object(name='board:test') 143*9c5db199SXin Li label.host_set.add(host) 144*9c5db199SXin Li self.assertRaises(model_logic.ValidationError, 145*9c5db199SXin Li host.check_board_labels_allowed, [host], 146*9c5db199SXin Li ['board:new_board']) 147*9c5db199SXin Li 148*9c5db199SXin Li 149*9c5db199SXin Liclass SpecialTaskUnittest(unittest.TestCase, 150*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 151*9c5db199SXin Li def setUp(self): 152*9c5db199SXin Li self._frontend_common_setup() 153*9c5db199SXin Li 154*9c5db199SXin Li 155*9c5db199SXin Li def tearDown(self): 156*9c5db199SXin Li self._frontend_common_teardown() 157*9c5db199SXin Li 158*9c5db199SXin Li 159*9c5db199SXin Li def _create_task(self): 160*9c5db199SXin Li return models.SpecialTask.objects.create( 161*9c5db199SXin Li host=self.hosts[0], task=models.SpecialTask.Task.VERIFY, 162*9c5db199SXin Li requested_by=models.User.current_user()) 163*9c5db199SXin Li 164*9c5db199SXin Li 165*9c5db199SXin Li def test_execution_path(self): 166*9c5db199SXin Li task = self._create_task() 167*9c5db199SXin Li self.assertEquals(task.execution_path(), 'hosts/host1/1-verify') 168*9c5db199SXin Li 169*9c5db199SXin Li 170*9c5db199SXin Li def test_status(self): 171*9c5db199SXin Li task = self._create_task() 172*9c5db199SXin Li self.assertEquals(task.status, 'Queued') 173*9c5db199SXin Li 174*9c5db199SXin Li task.update_object(is_active=True) 175*9c5db199SXin Li self.assertEquals(task.status, 'Running') 176*9c5db199SXin Li 177*9c5db199SXin Li task.update_object(is_active=False, is_complete=True, success=True) 178*9c5db199SXin Li self.assertEquals(task.status, 'Completed') 179*9c5db199SXin Li 180*9c5db199SXin Li task.update_object(success=False) 181*9c5db199SXin Li self.assertEquals(task.status, 'Failed') 182*9c5db199SXin Li 183*9c5db199SXin Li 184*9c5db199SXin Li def test_activate(self): 185*9c5db199SXin Li task = self._create_task() 186*9c5db199SXin Li task.activate() 187*9c5db199SXin Li self.assertTrue(task.is_active) 188*9c5db199SXin Li self.assertFalse(task.is_complete) 189*9c5db199SXin Li 190*9c5db199SXin Li 191*9c5db199SXin Li def test_finish(self): 192*9c5db199SXin Li task = self._create_task() 193*9c5db199SXin Li task.activate() 194*9c5db199SXin Li task.finish(True) 195*9c5db199SXin Li self.assertFalse(task.is_active) 196*9c5db199SXin Li self.assertTrue(task.is_complete) 197*9c5db199SXin Li self.assertTrue(task.success) 198*9c5db199SXin Li 199*9c5db199SXin Li 200*9c5db199SXin Li def test_requested_by_from_queue_entry(self): 201*9c5db199SXin Li job = self._create_job(hosts=[0]) 202*9c5db199SXin Li task = models.SpecialTask.objects.create( 203*9c5db199SXin Li host=self.hosts[0], task=models.SpecialTask.Task.VERIFY, 204*9c5db199SXin Li queue_entry=job.hostqueueentry_set.all()[0]) 205*9c5db199SXin Li self.assertEquals(task.requested_by.login, 'autotest_system') 206*9c5db199SXin Li 207*9c5db199SXin Li 208*9c5db199SXin Liclass HostQueueEntryUnittest(unittest.TestCase, 209*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 210*9c5db199SXin Li def setUp(self): 211*9c5db199SXin Li self._frontend_common_setup() 212*9c5db199SXin Li 213*9c5db199SXin Li 214*9c5db199SXin Li def tearDown(self): 215*9c5db199SXin Li self._frontend_common_teardown() 216*9c5db199SXin Li 217*9c5db199SXin Li 218*9c5db199SXin Li def test_execution_path(self): 219*9c5db199SXin Li entry = self._create_job(hosts=[1]).hostqueueentry_set.all()[0] 220*9c5db199SXin Li entry.execution_subdir = 'subdir' 221*9c5db199SXin Li entry.save() 222*9c5db199SXin Li 223*9c5db199SXin Li self.assertEquals(entry.execution_path(), '1-autotest_system/subdir') 224*9c5db199SXin Li 225*9c5db199SXin Li 226*9c5db199SXin Liclass ModelWithInvalidTest(unittest.TestCase, 227*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 228*9c5db199SXin Li def setUp(self): 229*9c5db199SXin Li self._frontend_common_setup() 230*9c5db199SXin Li 231*9c5db199SXin Li 232*9c5db199SXin Li def tearDown(self): 233*9c5db199SXin Li self._frontend_common_teardown() 234*9c5db199SXin Li 235*9c5db199SXin Li 236*9c5db199SXin Li def test_model_with_invalid_delete(self): 237*9c5db199SXin Li self.assertFalse(self.hosts[0].invalid) 238*9c5db199SXin Li self.hosts[0].delete() 239*9c5db199SXin Li self.assertTrue(self.hosts[0].invalid) 240*9c5db199SXin Li self.assertTrue(models.Host.objects.get(id=self.hosts[0].id)) 241*9c5db199SXin Li 242*9c5db199SXin Li 243*9c5db199SXin Li def test_model_with_invalid_delete_queryset(self): 244*9c5db199SXin Li for host in self.hosts: 245*9c5db199SXin Li self.assertFalse(host.invalid) 246*9c5db199SXin Li 247*9c5db199SXin Li hosts = models.Host.objects.all() 248*9c5db199SXin Li hosts.delete() 249*9c5db199SXin Li self.assertEqual(hosts.count(), len(self.hosts)) 250*9c5db199SXin Li 251*9c5db199SXin Li for host in hosts: 252*9c5db199SXin Li self.assertTrue(host.invalid) 253*9c5db199SXin Li 254*9c5db199SXin Li 255*9c5db199SXin Li def test_cloned_queryset_delete(self): 256*9c5db199SXin Li """ 257*9c5db199SXin Li Make sure that a cloned queryset maintains the custom delete() 258*9c5db199SXin Li """ 259*9c5db199SXin Li to_delete = ('host1', 'host2') 260*9c5db199SXin Li 261*9c5db199SXin Li for host in self.hosts: 262*9c5db199SXin Li self.assertFalse(host.invalid) 263*9c5db199SXin Li 264*9c5db199SXin Li hosts = models.Host.objects.all().filter(hostname__in=to_delete) 265*9c5db199SXin Li hosts.delete() 266*9c5db199SXin Li all_hosts = models.Host.objects.all() 267*9c5db199SXin Li self.assertEqual(all_hosts.count(), len(self.hosts)) 268*9c5db199SXin Li 269*9c5db199SXin Li for host in all_hosts: 270*9c5db199SXin Li if host.hostname in to_delete: 271*9c5db199SXin Li self.assertTrue( 272*9c5db199SXin Li host.invalid, 273*9c5db199SXin Li '%s.invalid expected to be True' % host.hostname) 274*9c5db199SXin Li else: 275*9c5db199SXin Li self.assertFalse( 276*9c5db199SXin Li host.invalid, 277*9c5db199SXin Li '%s.invalid expected to be False' % host.hostname) 278*9c5db199SXin Li 279*9c5db199SXin Li 280*9c5db199SXin Li def test_normal_delete(self): 281*9c5db199SXin Li job = self._create_job(hosts=[1]) 282*9c5db199SXin Li self.assertEqual(1, models.Job.objects.all().count()) 283*9c5db199SXin Li 284*9c5db199SXin Li job.delete() 285*9c5db199SXin Li self.assertEqual(0, models.Job.objects.all().count()) 286*9c5db199SXin Li 287*9c5db199SXin Li 288*9c5db199SXin Li def test_normal_delete_queryset(self): 289*9c5db199SXin Li self._create_job(hosts=[1]) 290*9c5db199SXin Li self._create_job(hosts=[2]) 291*9c5db199SXin Li 292*9c5db199SXin Li self.assertEqual(2, models.Job.objects.all().count()) 293*9c5db199SXin Li 294*9c5db199SXin Li models.Job.objects.all().delete() 295*9c5db199SXin Li self.assertEqual(0, models.Job.objects.all().count()) 296*9c5db199SXin Li 297*9c5db199SXin Li 298*9c5db199SXin Liclass SerializationTest(unittest.TestCase, 299*9c5db199SXin Li frontend_test_utils.FrontendTestMixin): 300*9c5db199SXin Li def setUp(self): 301*9c5db199SXin Li self._frontend_common_setup(fill_data=False) 302*9c5db199SXin Li 303*9c5db199SXin Li 304*9c5db199SXin Li def tearDown(self): 305*9c5db199SXin Li self._frontend_common_teardown() 306*9c5db199SXin Li 307*9c5db199SXin Li 308*9c5db199SXin Li def _get_example_response(self): 309*9c5db199SXin Li return {'hosts': [{'aclgroup_set': [{'description': '', 310*9c5db199SXin Li 'id': 1, 311*9c5db199SXin Li 'name': 'Everyone', 312*9c5db199SXin Li 'users': [{ 313*9c5db199SXin Li 'access_level': 100, 314*9c5db199SXin Li 'id': 1, 315*9c5db199SXin Li 'login': 'autotest_system', 316*9c5db199SXin Li 'reboot_after': 0, 317*9c5db199SXin Li 'reboot_before': 1, 318*9c5db199SXin Li 'show_experimental': False}]}], 319*9c5db199SXin Li 'dirty': True, 320*9c5db199SXin Li 'hostattribute_set': [], 321*9c5db199SXin Li 'hostname': '100.107.2.163', 322*9c5db199SXin Li 'id': 2, 323*9c5db199SXin Li 'invalid': False, 324*9c5db199SXin Li 'labels': [{'id': 7, 325*9c5db199SXin Li 'invalid': False, 326*9c5db199SXin Li 'kernel_config': '', 327*9c5db199SXin Li 'name': 'power:battery', 328*9c5db199SXin Li 'only_if_needed': False, 329*9c5db199SXin Li 'platform': False}, 330*9c5db199SXin Li {'id': 9, 331*9c5db199SXin Li 'invalid': False, 332*9c5db199SXin Li 'kernel_config': '', 333*9c5db199SXin Li 'name': 'hw_video_acc_h264', 334*9c5db199SXin Li 'only_if_needed': False, 335*9c5db199SXin Li 'platform': False}, 336*9c5db199SXin Li {'id': 10, 337*9c5db199SXin Li 'invalid': False, 338*9c5db199SXin Li 'kernel_config': '', 339*9c5db199SXin Li 'name': 'hw_video_acc_enc_h264', 340*9c5db199SXin Li 'only_if_needed': False, 341*9c5db199SXin Li 'platform': False}, 342*9c5db199SXin Li {'id': 11, 343*9c5db199SXin Li 'invalid': False, 344*9c5db199SXin Li 'kernel_config': '', 345*9c5db199SXin Li 'name': 'webcam', 346*9c5db199SXin Li 'only_if_needed': False, 347*9c5db199SXin Li 'platform': False}, 348*9c5db199SXin Li {'id': 12, 349*9c5db199SXin Li 'invalid': False, 350*9c5db199SXin Li 'kernel_config': '', 351*9c5db199SXin Li 'name': 'touchpad', 352*9c5db199SXin Li 'only_if_needed': False, 353*9c5db199SXin Li 'platform': False}, 354*9c5db199SXin Li {'id': 13, 355*9c5db199SXin Li 'invalid': False, 356*9c5db199SXin Li 'kernel_config': '', 357*9c5db199SXin Li 'name': 'spring', 358*9c5db199SXin Li 'only_if_needed': False, 359*9c5db199SXin Li 'platform': False}, 360*9c5db199SXin Li {'id': 14, 361*9c5db199SXin Li 'invalid': False, 362*9c5db199SXin Li 'kernel_config': '', 363*9c5db199SXin Li 'name': 'board:daisy', 364*9c5db199SXin Li 'only_if_needed': False, 365*9c5db199SXin Li 'platform': True}, 366*9c5db199SXin Li {'id': 15, 367*9c5db199SXin Li 'invalid': False, 368*9c5db199SXin Li 'kernel_config': '', 369*9c5db199SXin Li 'name': 'board_freq_mem:daisy_1.7GHz', 370*9c5db199SXin Li 'only_if_needed': False, 371*9c5db199SXin Li 'platform': False}, 372*9c5db199SXin Li {'id': 16, 373*9c5db199SXin Li 'invalid': False, 374*9c5db199SXin Li 'kernel_config': '', 375*9c5db199SXin Li 'name': 'bluetooth', 376*9c5db199SXin Li 'only_if_needed': False, 377*9c5db199SXin Li 'platform': False}, 378*9c5db199SXin Li {'id': 17, 379*9c5db199SXin Li 'invalid': False, 380*9c5db199SXin Li 'kernel_config': '', 381*9c5db199SXin Li 'name': 'gpu_family:mali', 382*9c5db199SXin Li 'only_if_needed': False, 383*9c5db199SXin Li 'platform': False}, 384*9c5db199SXin Li {'id': 19, 385*9c5db199SXin Li 'invalid': False, 386*9c5db199SXin Li 'kernel_config': '', 387*9c5db199SXin Li 'name': 'ec:cros', 388*9c5db199SXin Li 'only_if_needed': False, 389*9c5db199SXin Li 'platform': False}, 390*9c5db199SXin Li {'id': 20, 391*9c5db199SXin Li 'invalid': False, 392*9c5db199SXin Li 'kernel_config': '', 393*9c5db199SXin Li 'name': 'storage:mmc', 394*9c5db199SXin Li 'only_if_needed': False, 395*9c5db199SXin Li 'platform': False}, 396*9c5db199SXin Li {'id': 21, 397*9c5db199SXin Li 'invalid': False, 398*9c5db199SXin Li 'kernel_config': '', 399*9c5db199SXin Li 'name': 'hw_video_acc_vp8', 400*9c5db199SXin Li 'only_if_needed': False, 401*9c5db199SXin Li 'platform': False}, 402*9c5db199SXin Li {'id': 22, 403*9c5db199SXin Li 'invalid': False, 404*9c5db199SXin Li 'kernel_config': '', 405*9c5db199SXin Li 'name': 'video_glitch_detection', 406*9c5db199SXin Li 'only_if_needed': False, 407*9c5db199SXin Li 'platform': False}, 408*9c5db199SXin Li {'id': 23, 409*9c5db199SXin Li 'invalid': False, 410*9c5db199SXin Li 'kernel_config': '', 411*9c5db199SXin Li 'name': 'pool:suites', 412*9c5db199SXin Li 'only_if_needed': False, 413*9c5db199SXin Li 'platform': False}, 414*9c5db199SXin Li {'id': 25, 415*9c5db199SXin Li 'invalid': False, 416*9c5db199SXin Li 'kernel_config': '', 417*9c5db199SXin Li 'name': 'daisy-board-name', 418*9c5db199SXin Li 'only_if_needed': False, 419*9c5db199SXin Li 'platform': False}], 420*9c5db199SXin Li 'leased': False, 421*9c5db199SXin Li 'lock_reason': '', 422*9c5db199SXin Li 'lock_time': None, 423*9c5db199SXin Li 'locked': False, 424*9c5db199SXin Li 'protection': 0, 425*9c5db199SXin Li 'shard': {'hostname': '1', 'id': 1}, 426*9c5db199SXin Li 'status': 'Ready', 427*9c5db199SXin Li 'synch_id': None}], 428*9c5db199SXin Li 'jobs': [{'control_file': 'some control file\n\n\n', 429*9c5db199SXin Li 'control_type': 2, 430*9c5db199SXin Li 'created_on': '2014-09-04T13:09:35', 431*9c5db199SXin Li 'dependency_labels': [{'id': 14, 432*9c5db199SXin Li 'invalid': False, 433*9c5db199SXin Li 'kernel_config': '', 434*9c5db199SXin Li 'name': 'board:daisy', 435*9c5db199SXin Li 'only_if_needed': False, 436*9c5db199SXin Li 'platform': True}, 437*9c5db199SXin Li {'id': 23, 438*9c5db199SXin Li 'invalid': False, 439*9c5db199SXin Li 'kernel_config': '', 440*9c5db199SXin Li 'name': 'pool:suites', 441*9c5db199SXin Li 'only_if_needed': False, 442*9c5db199SXin Li 'platform': False}, 443*9c5db199SXin Li {'id': 25, 444*9c5db199SXin Li 'invalid': False, 445*9c5db199SXin Li 'kernel_config': '', 446*9c5db199SXin Li 'name': 'daisy-board-name', 447*9c5db199SXin Li 'only_if_needed': False, 448*9c5db199SXin Li 'platform': False}], 449*9c5db199SXin Li 'email_list': '', 450*9c5db199SXin Li 'hostqueueentry_set': [{'aborted': False, 451*9c5db199SXin Li 'active': False, 452*9c5db199SXin Li 'complete': False, 453*9c5db199SXin Li 'deleted': False, 454*9c5db199SXin Li 'execution_subdir': '', 455*9c5db199SXin Li 'finished_on': None, 456*9c5db199SXin Li 'id': 5, 457*9c5db199SXin Li 'meta_host': { 458*9c5db199SXin Li 'id': 14, 459*9c5db199SXin Li 'invalid': False, 460*9c5db199SXin Li 'kernel_config': '', 461*9c5db199SXin Li 'name': 'board:daisy', 462*9c5db199SXin Li 'only_if_needed': False, 463*9c5db199SXin Li 'platform': True}, 464*9c5db199SXin Li 'host_id': None, 465*9c5db199SXin Li 'started_on': None, 466*9c5db199SXin Li 'status': 'Queued'}], 467*9c5db199SXin Li 'id': 5, 468*9c5db199SXin Li 'jobkeyval_set': [{'id': 10, 469*9c5db199SXin Li 'job_id': 5, 470*9c5db199SXin Li 'key': 'suite', 471*9c5db199SXin Li 'value': 'stub'}, 472*9c5db199SXin Li {'id': 11, 473*9c5db199SXin Li 'job_id': 5, 474*9c5db199SXin Li 'key': 'build', 475*9c5db199SXin Li 'value': 'daisy-release'}, 476*9c5db199SXin Li {'id': 12, 477*9c5db199SXin Li 'job_id': 5, 478*9c5db199SXin Li 'key': 'experimental', 479*9c5db199SXin Li 'value': 'False'}], 480*9c5db199SXin Li 'max_runtime_hrs': 72, 481*9c5db199SXin Li 'max_runtime_mins': 1440, 482*9c5db199SXin Li 'name': 'daisy-experimental', 483*9c5db199SXin Li 'owner': 'autotest', 484*9c5db199SXin Li 'parse_failed_repair': True, 485*9c5db199SXin Li 'priority': 40, 486*9c5db199SXin Li 'reboot_after': 0, 487*9c5db199SXin Li 'reboot_before': 1, 488*9c5db199SXin Li 'run_reset': True, 489*9c5db199SXin Li 'run_verify': False, 490*9c5db199SXin Li 'shard': {'hostname': '1', 'id': 1}, 491*9c5db199SXin Li 'synch_count': 1, 492*9c5db199SXin Li 'test_retry': 0, 493*9c5db199SXin Li 'timeout': 24, 494*9c5db199SXin Li 'timeout_mins': 1440, 495*9c5db199SXin Li 'require_ssp': None}, 496*9c5db199SXin Li {'control_file': 'some control file\n\n\n', 497*9c5db199SXin Li 'control_type': 2, 498*9c5db199SXin Li 'created_on': '2014-09-04T13:09:35', 499*9c5db199SXin Li 'dependency_labels': [{'id': 14, 500*9c5db199SXin Li 'invalid': False, 501*9c5db199SXin Li 'kernel_config': '', 502*9c5db199SXin Li 'name': 'board:daisy', 503*9c5db199SXin Li 'only_if_needed': False, 504*9c5db199SXin Li 'platform': True}, 505*9c5db199SXin Li {'id': 23, 506*9c5db199SXin Li 'invalid': False, 507*9c5db199SXin Li 'kernel_config': '', 508*9c5db199SXin Li 'name': 'pool:suites', 509*9c5db199SXin Li 'only_if_needed': False, 510*9c5db199SXin Li 'platform': False}, 511*9c5db199SXin Li {'id': 25, 512*9c5db199SXin Li 'invalid': False, 513*9c5db199SXin Li 'kernel_config': '', 514*9c5db199SXin Li 'name': 'daisy-board-name', 515*9c5db199SXin Li 'only_if_needed': False, 516*9c5db199SXin Li 'platform': False}], 517*9c5db199SXin Li 'email_list': '', 518*9c5db199SXin Li 'hostqueueentry_set': [{'aborted': False, 519*9c5db199SXin Li 'active': False, 520*9c5db199SXin Li 'complete': False, 521*9c5db199SXin Li 'deleted': False, 522*9c5db199SXin Li 'execution_subdir': '', 523*9c5db199SXin Li 'finished_on': None, 524*9c5db199SXin Li 'id': 7, 525*9c5db199SXin Li 'meta_host': { 526*9c5db199SXin Li 'id': 14, 527*9c5db199SXin Li 'invalid': False, 528*9c5db199SXin Li 'kernel_config': '', 529*9c5db199SXin Li 'name': 'board:daisy', 530*9c5db199SXin Li 'only_if_needed': False, 531*9c5db199SXin Li 'platform': True}, 532*9c5db199SXin Li 'host_id': None, 533*9c5db199SXin Li 'started_on': None, 534*9c5db199SXin Li 'status': 'Queued'}], 535*9c5db199SXin Li 'id': 7, 536*9c5db199SXin Li 'jobkeyval_set': [{'id': 16, 537*9c5db199SXin Li 'job_id': 7, 538*9c5db199SXin Li 'key': 'suite', 539*9c5db199SXin Li 'value': 'stub'}, 540*9c5db199SXin Li {'id': 17, 541*9c5db199SXin Li 'job_id': 7, 542*9c5db199SXin Li 'key': 'build', 543*9c5db199SXin Li 'value': 'daisy-release'}, 544*9c5db199SXin Li {'id': 18, 545*9c5db199SXin Li 'job_id': 7, 546*9c5db199SXin Li 'key': 'experimental', 547*9c5db199SXin Li 'value': 'False'}], 548*9c5db199SXin Li 'max_runtime_hrs': 72, 549*9c5db199SXin Li 'max_runtime_mins': 1440, 550*9c5db199SXin Li 'name': 'daisy-experimental', 551*9c5db199SXin Li 'owner': 'autotest', 552*9c5db199SXin Li 'parse_failed_repair': True, 553*9c5db199SXin Li 'priority': 40, 554*9c5db199SXin Li 'reboot_after': 0, 555*9c5db199SXin Li 'reboot_before': 1, 556*9c5db199SXin Li 'run_reset': True, 557*9c5db199SXin Li 'run_verify': False, 558*9c5db199SXin Li 'shard': {'hostname': '1', 'id': 1}, 559*9c5db199SXin Li 'synch_count': 1, 560*9c5db199SXin Li 'test_retry': 0, 561*9c5db199SXin Li 'timeout': 24, 562*9c5db199SXin Li 'timeout_mins': 1440, 563*9c5db199SXin Li 'require_ssp': None}]} 564*9c5db199SXin Li 565*9c5db199SXin Li 566*9c5db199SXin Li def test_response(self): 567*9c5db199SXin Li heartbeat_response = self._get_example_response() 568*9c5db199SXin Li hosts_serialized = heartbeat_response['hosts'] 569*9c5db199SXin Li jobs_serialized = heartbeat_response['jobs'] 570*9c5db199SXin Li 571*9c5db199SXin Li # Persisting is automatically done inside deserialize 572*9c5db199SXin Li hosts = [models.Host.deserialize(host) for host in hosts_serialized] 573*9c5db199SXin Li jobs = [models.Job.deserialize(job) for job in jobs_serialized] 574*9c5db199SXin Li 575*9c5db199SXin Li generated_heartbeat_response = { 576*9c5db199SXin Li 'hosts': [host.serialize() for host in hosts], 577*9c5db199SXin Li 'jobs': [job.serialize() for job in jobs] 578*9c5db199SXin Li } 579*9c5db199SXin Li example_response = self._get_example_response() 580*9c5db199SXin Li # For attribute-like objects, we don't care about its id. 581*9c5db199SXin Li for r in [generated_heartbeat_response, example_response]: 582*9c5db199SXin Li for job in r['jobs']: 583*9c5db199SXin Li for keyval in job['jobkeyval_set']: 584*9c5db199SXin Li keyval.pop('id') 585*9c5db199SXin Li for host in r['hosts']: 586*9c5db199SXin Li for attribute in host['hostattribute_set']: 587*9c5db199SXin Li keyval.pop('id') 588*9c5db199SXin Li self.assertEqual(generated_heartbeat_response, example_response) 589*9c5db199SXin Li 590*9c5db199SXin Li 591*9c5db199SXin Li def test_update(self): 592*9c5db199SXin Li job = self._create_job(hosts=[1]) 593*9c5db199SXin Li serialized = job.serialize(include_dependencies=False) 594*9c5db199SXin Li serialized['owner'] = 'some_other_owner' 595*9c5db199SXin Li 596*9c5db199SXin Li job.update_from_serialized(serialized) 597*9c5db199SXin Li self.assertEqual(job.owner, 'some_other_owner') 598*9c5db199SXin Li 599*9c5db199SXin Li serialized = job.serialize() 600*9c5db199SXin Li self.assertRaises( 601*9c5db199SXin Li ValueError, 602*9c5db199SXin Li job.update_from_serialized, serialized) 603*9c5db199SXin Li 604*9c5db199SXin Li 605*9c5db199SXin Li def test_sync_aborted(self): 606*9c5db199SXin Li job = self._create_job(hosts=[1]) 607*9c5db199SXin Li serialized = job.serialize() 608*9c5db199SXin Li 609*9c5db199SXin Li serialized['hostqueueentry_set'][0]['aborted'] = True 610*9c5db199SXin Li serialized['hostqueueentry_set'][0]['status'] = 'Running' 611*9c5db199SXin Li 612*9c5db199SXin Li models.Job.deserialize(serialized) 613*9c5db199SXin Li 614*9c5db199SXin Li job = models.Job.objects.get(pk=job.id) 615*9c5db199SXin Li self.assertTrue(job.hostqueueentry_set.all()[0].aborted) 616*9c5db199SXin Li self.assertEqual(job.hostqueueentry_set.all()[0].status, 'Queued') 617*9c5db199SXin Li 618*9c5db199SXin Li 619*9c5db199SXin Liif __name__ == '__main__': 620*9c5db199SXin Li unittest.main() 621