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