| #!/usr/bin/python |
| # pylint: disable=missing-docstring |
| |
| import unittest |
| |
| import common |
| from autotest_lib.frontend import setup_django_environment |
| from autotest_lib.frontend.afe import frontend_test_utils |
| from autotest_lib.frontend.afe import models, model_logic |
| |
| |
| class AclGroupTest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup() |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def _check_acls(self, host, acl_name_list): |
| actual_acl_names = [acl_group.name for acl_group |
| in host.aclgroup_set.all()] |
| self.assertEquals(set(actual_acl_names), set(acl_name_list)) |
| |
| |
| def test_on_host_membership_change(self): |
| host1, host2 = self.hosts[1:3] |
| everyone_acl = models.AclGroup.objects.get(name='Everyone') |
| |
| host1.aclgroup_set.clear() |
| self._check_acls(host1, []) |
| host2.aclgroup_set.add(everyone_acl) |
| self._check_acls(host2, ['Everyone', 'my_acl']) |
| |
| models.AclGroup.on_host_membership_change() |
| |
| self._check_acls(host1, ['Everyone']) |
| self._check_acls(host2, ['my_acl']) |
| |
| |
| class HostTest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup() |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def test_add_host_previous_one_time_host(self): |
| # ensure that when adding a host which was previously used as a one-time |
| # host, the status isn't reset, since this can interfere with the |
| # scheduler. |
| host = models.Host.create_one_time_host('othost') |
| self.assertEquals(host.invalid, True) |
| self.assertEquals(host.status, models.Host.Status.READY) |
| |
| host.status = models.Host.Status.RUNNING |
| host.save() |
| |
| host2 = models.Host.add_object(hostname='othost') |
| self.assertEquals(host2.id, host.id) |
| self.assertEquals(host2.status, models.Host.Status.RUNNING) |
| |
| |
| def test_check_board_labels_allowed(self): |
| host = models.Host.create_one_time_host('othost') |
| # First check with host with no board label. |
| self.assertEqual(host.check_board_labels_allowed([host]), None) |
| |
| # Second check with host with board label |
| label = models.Label.add_object(name='board:test') |
| label.host_set.add(host) |
| self.assertRaises(model_logic.ValidationError, |
| host.check_board_labels_allowed, [host], |
| ['board:new_board']) |
| |
| |
| class SpecialTaskUnittest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup() |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def _create_task(self): |
| return models.SpecialTask.objects.create( |
| host=self.hosts[0], task=models.SpecialTask.Task.VERIFY, |
| requested_by=models.User.current_user()) |
| |
| |
| def test_execution_path(self): |
| task = self._create_task() |
| self.assertEquals(task.execution_path(), 'hosts/host1/1-verify') |
| |
| |
| def test_status(self): |
| task = self._create_task() |
| self.assertEquals(task.status, 'Queued') |
| |
| task.update_object(is_active=True) |
| self.assertEquals(task.status, 'Running') |
| |
| task.update_object(is_active=False, is_complete=True, success=True) |
| self.assertEquals(task.status, 'Completed') |
| |
| task.update_object(success=False) |
| self.assertEquals(task.status, 'Failed') |
| |
| |
| def test_activate(self): |
| task = self._create_task() |
| task.activate() |
| self.assertTrue(task.is_active) |
| self.assertFalse(task.is_complete) |
| |
| |
| def test_finish(self): |
| task = self._create_task() |
| task.activate() |
| task.finish(True) |
| self.assertFalse(task.is_active) |
| self.assertTrue(task.is_complete) |
| self.assertTrue(task.success) |
| |
| |
| def test_requested_by_from_queue_entry(self): |
| job = self._create_job(hosts=[0]) |
| task = models.SpecialTask.objects.create( |
| host=self.hosts[0], task=models.SpecialTask.Task.VERIFY, |
| queue_entry=job.hostqueueentry_set.all()[0]) |
| self.assertEquals(task.requested_by.login, 'autotest_system') |
| |
| |
| class HostQueueEntryUnittest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup() |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def test_execution_path(self): |
| entry = self._create_job(hosts=[1]).hostqueueentry_set.all()[0] |
| entry.execution_subdir = 'subdir' |
| entry.save() |
| |
| self.assertEquals(entry.execution_path(), '1-autotest_system/subdir') |
| |
| |
| class ModelWithInvalidTest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup() |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def test_model_with_invalid_delete(self): |
| self.assertFalse(self.hosts[0].invalid) |
| self.hosts[0].delete() |
| self.assertTrue(self.hosts[0].invalid) |
| self.assertTrue(models.Host.objects.get(id=self.hosts[0].id)) |
| |
| |
| def test_model_with_invalid_delete_queryset(self): |
| for host in self.hosts: |
| self.assertFalse(host.invalid) |
| |
| hosts = models.Host.objects.all() |
| hosts.delete() |
| self.assertEqual(hosts.count(), len(self.hosts)) |
| |
| for host in hosts: |
| self.assertTrue(host.invalid) |
| |
| |
| def test_cloned_queryset_delete(self): |
| """ |
| Make sure that a cloned queryset maintains the custom delete() |
| """ |
| to_delete = ('host1', 'host2') |
| |
| for host in self.hosts: |
| self.assertFalse(host.invalid) |
| |
| hosts = models.Host.objects.all().filter(hostname__in=to_delete) |
| hosts.delete() |
| all_hosts = models.Host.objects.all() |
| self.assertEqual(all_hosts.count(), len(self.hosts)) |
| |
| for host in all_hosts: |
| if host.hostname in to_delete: |
| self.assertTrue( |
| host.invalid, |
| '%s.invalid expected to be True' % host.hostname) |
| else: |
| self.assertFalse( |
| host.invalid, |
| '%s.invalid expected to be False' % host.hostname) |
| |
| |
| def test_normal_delete(self): |
| job = self._create_job(hosts=[1]) |
| self.assertEqual(1, models.Job.objects.all().count()) |
| |
| job.delete() |
| self.assertEqual(0, models.Job.objects.all().count()) |
| |
| |
| def test_normal_delete_queryset(self): |
| self._create_job(hosts=[1]) |
| self._create_job(hosts=[2]) |
| |
| self.assertEqual(2, models.Job.objects.all().count()) |
| |
| models.Job.objects.all().delete() |
| self.assertEqual(0, models.Job.objects.all().count()) |
| |
| |
| class SerializationTest(unittest.TestCase, |
| frontend_test_utils.FrontendTestMixin): |
| def setUp(self): |
| self._frontend_common_setup(fill_data=False) |
| |
| |
| def tearDown(self): |
| self._frontend_common_teardown() |
| |
| |
| def _get_example_response(self): |
| return {'hosts': [{'aclgroup_set': [{'description': '', |
| 'id': 1, |
| 'name': 'Everyone', |
| 'users': [{ |
| 'access_level': 100, |
| 'id': 1, |
| 'login': 'autotest_system', |
| 'reboot_after': 0, |
| 'reboot_before': 1, |
| 'show_experimental': False}]}], |
| 'dirty': True, |
| 'hostattribute_set': [], |
| 'hostname': '100.107.2.163', |
| 'id': 2, |
| 'invalid': False, |
| 'labels': [{'id': 7, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'power:battery', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 9, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'hw_video_acc_h264', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 10, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'hw_video_acc_enc_h264', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 11, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'webcam', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 12, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'touchpad', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 13, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'spring', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 14, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board:daisy', |
| 'only_if_needed': False, |
| 'platform': True}, |
| {'id': 15, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board_freq_mem:daisy_1.7GHz', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 16, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'bluetooth', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 17, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'gpu_family:mali', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 19, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'ec:cros', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 20, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'storage:mmc', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 21, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'hw_video_acc_vp8', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 22, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'video_glitch_detection', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 23, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'pool:suites', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 25, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'daisy-board-name', |
| 'only_if_needed': False, |
| 'platform': False}], |
| 'leased': False, |
| 'lock_reason': '', |
| 'lock_time': None, |
| 'locked': False, |
| 'protection': 0, |
| 'shard': {'hostname': '1', 'id': 1}, |
| 'status': 'Ready', |
| 'synch_id': None}], |
| 'jobs': [{'control_file': 'some control file\n\n\n', |
| 'control_type': 2, |
| 'created_on': '2014-09-04T13:09:35', |
| 'dependency_labels': [{'id': 14, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board:daisy', |
| 'only_if_needed': False, |
| 'platform': True}, |
| {'id': 23, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'pool:suites', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 25, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'daisy-board-name', |
| 'only_if_needed': False, |
| 'platform': False}], |
| 'email_list': '', |
| 'hostqueueentry_set': [{'aborted': False, |
| 'active': False, |
| 'complete': False, |
| 'deleted': False, |
| 'execution_subdir': '', |
| 'finished_on': None, |
| 'id': 5, |
| 'meta_host': { |
| 'id': 14, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board:daisy', |
| 'only_if_needed': False, |
| 'platform': True}, |
| 'host_id': None, |
| 'started_on': None, |
| 'status': 'Queued'}], |
| 'id': 5, |
| 'jobkeyval_set': [{'id': 10, |
| 'job_id': 5, |
| 'key': 'suite', |
| 'value': 'dummy'}, |
| {'id': 11, |
| 'job_id': 5, |
| 'key': 'build', |
| 'value': 'daisy-release'}, |
| {'id': 12, |
| 'job_id': 5, |
| 'key': 'experimental', |
| 'value': 'False'}], |
| 'max_runtime_hrs': 72, |
| 'max_runtime_mins': 1440, |
| 'name': 'daisy-experimental', |
| 'owner': 'autotest', |
| 'parse_failed_repair': True, |
| 'priority': 40, |
| 'reboot_after': 0, |
| 'reboot_before': 1, |
| 'run_reset': True, |
| 'run_verify': False, |
| 'shard': {'hostname': '1', 'id': 1}, |
| 'synch_count': 1, |
| 'test_retry': 0, |
| 'timeout': 24, |
| 'timeout_mins': 1440, |
| 'require_ssp': None}, |
| {'control_file': 'some control file\n\n\n', |
| 'control_type': 2, |
| 'created_on': '2014-09-04T13:09:35', |
| 'dependency_labels': [{'id': 14, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board:daisy', |
| 'only_if_needed': False, |
| 'platform': True}, |
| {'id': 23, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'pool:suites', |
| 'only_if_needed': False, |
| 'platform': False}, |
| {'id': 25, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'daisy-board-name', |
| 'only_if_needed': False, |
| 'platform': False}], |
| 'email_list': '', |
| 'hostqueueentry_set': [{'aborted': False, |
| 'active': False, |
| 'complete': False, |
| 'deleted': False, |
| 'execution_subdir': '', |
| 'finished_on': None, |
| 'id': 7, |
| 'meta_host': { |
| 'id': 14, |
| 'invalid': False, |
| 'kernel_config': '', |
| 'name': 'board:daisy', |
| 'only_if_needed': False, |
| 'platform': True}, |
| 'host_id': None, |
| 'started_on': None, |
| 'status': 'Queued'}], |
| 'id': 7, |
| 'jobkeyval_set': [{'id': 16, |
| 'job_id': 7, |
| 'key': 'suite', |
| 'value': 'dummy'}, |
| {'id': 17, |
| 'job_id': 7, |
| 'key': 'build', |
| 'value': 'daisy-release'}, |
| {'id': 18, |
| 'job_id': 7, |
| 'key': 'experimental', |
| 'value': 'False'}], |
| 'max_runtime_hrs': 72, |
| 'max_runtime_mins': 1440, |
| 'name': 'daisy-experimental', |
| 'owner': 'autotest', |
| 'parse_failed_repair': True, |
| 'priority': 40, |
| 'reboot_after': 0, |
| 'reboot_before': 1, |
| 'run_reset': True, |
| 'run_verify': False, |
| 'shard': {'hostname': '1', 'id': 1}, |
| 'synch_count': 1, |
| 'test_retry': 0, |
| 'timeout': 24, |
| 'timeout_mins': 1440, |
| 'require_ssp': None}]} |
| |
| |
| def test_response(self): |
| heartbeat_response = self._get_example_response() |
| hosts_serialized = heartbeat_response['hosts'] |
| jobs_serialized = heartbeat_response['jobs'] |
| |
| # Persisting is automatically done inside deserialize |
| hosts = [models.Host.deserialize(host) for host in hosts_serialized] |
| jobs = [models.Job.deserialize(job) for job in jobs_serialized] |
| |
| generated_heartbeat_response = { |
| 'hosts': [host.serialize() for host in hosts], |
| 'jobs': [job.serialize() for job in jobs] |
| } |
| example_response = self._get_example_response() |
| # For attribute-like objects, we don't care about its id. |
| for r in [generated_heartbeat_response, example_response]: |
| for job in r['jobs']: |
| for keyval in job['jobkeyval_set']: |
| keyval.pop('id') |
| for host in r['hosts']: |
| for attribute in host['hostattribute_set']: |
| keyval.pop('id') |
| self.assertEqual(generated_heartbeat_response, example_response) |
| |
| |
| def test_update(self): |
| job = self._create_job(hosts=[1]) |
| serialized = job.serialize(include_dependencies=False) |
| serialized['owner'] = 'some_other_owner' |
| |
| job.update_from_serialized(serialized) |
| self.assertEqual(job.owner, 'some_other_owner') |
| |
| serialized = job.serialize() |
| self.assertRaises( |
| ValueError, |
| job.update_from_serialized, serialized) |
| |
| |
| def test_sync_aborted(self): |
| job = self._create_job(hosts=[1]) |
| serialized = job.serialize() |
| |
| serialized['hostqueueentry_set'][0]['aborted'] = True |
| serialized['hostqueueentry_set'][0]['status'] = 'Running' |
| |
| models.Job.deserialize(serialized) |
| |
| job = models.Job.objects.get(pk=job.id) |
| self.assertTrue(job.hostqueueentry_set.all()[0].aborted) |
| self.assertEqual(job.hostqueueentry_set.all()[0].status, 'Queued') |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |