def test_health_frequency_jobs(self): self.device_type01.health_denominator = DeviceType.HEALTH_PER_JOB self.device_type01.health_frequency = 2 self.device_type01.save() self.last_hc03.submit_time = timezone.now() - timedelta(hours=2) self.last_hc03.save() Device.get_health_check = _minimal_valid_job self.assertNotEqual(self.device01.get_health_check(), None) self.assertNotEqual(self.device02.get_health_check(), None) self.assertNotEqual(self.device03.get_health_check(), None) # Only device03 is available now self.device01.health = Device.HEALTH_BAD self.device01.save() self.device03.health = Device.HEALTH_GOOD self.device03.save() # Create a job that should be scheduled now j01 = TestJob.objects.create( requested_device_type=self.device_type01, submitter=self.user, definition=_minimal_valid_job(None), ) j02 = TestJob.objects.create( requested_device_type=self.device_type01, submitter=self.user, definition=_minimal_valid_job(None), ) j03 = TestJob.objects.create( requested_device_type=self.device_type01, submitter=self.user, definition=_minimal_valid_job(None), ) schedule(DummyLogger()) self.device03.refresh_from_db() j01.refresh_from_db() self.assertEqual(j01.state, TestJob.STATE_SCHEDULED) self.assertEqual(j01.actual_device, self.device03) j01.go_state_finished(TestJob.HEALTH_COMPLETE) j01.start_time = timezone.now() - timedelta(hours=1) j01.save() schedule(DummyLogger()) self.device03.refresh_from_db() j02.refresh_from_db() self.assertEqual(j02.state, TestJob.STATE_SCHEDULED) self.assertEqual(j02.actual_device, self.device03) j02.go_state_finished(TestJob.HEALTH_COMPLETE) j02.start_time = timezone.now() - timedelta(hours=1) j02.save() schedule(DummyLogger()) self.device03.refresh_from_db() j03.refresh_from_db() self.assertEqual(j03.state, TestJob.STATE_SUBMITTED) current_hc = self.device03.current_job() self.assertTrue(current_hc.health_check) self.assertEqual(current_hc.state, TestJob.STATE_SCHEDULED)
def setUp(self): """ Attempt to setup a valid group with clients and test the protocol """ super().setUp() factory = Factory() self.client_job = factory.create_kvm_job( "sample_jobs/kvm-multinode-client.yaml") self.server_job = factory.create_kvm_job( "sample_jobs/kvm-multinode-server.yaml") self.client_job.logger = DummyLogger() self.server_job.logger = DummyLogger() self.job_id = "100" self.coord = TestCoordinator()
def test_image(self, which_mock): self.deploy_block["kernel"]["type"] = "image" job = self.parser.parse( yaml_safe_dump(self.base_data), self.device, 4212, None, "" ) job.logger = DummyLogger() job.validate() deploy = [ action for action in job.pipeline.actions if action.name == "tftp-deploy" ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == "prepare-tftp-overlay" ][0] prepare = [ action for action in overlay.internal_pipeline.actions if action.name == "prepare-kernel" ][0] uboot_prepare = [ action for action in prepare.internal_pipeline.actions if action.name == "uboot-prepare-kernel" ][0] self.assertEqual("image", uboot_prepare.kernel_type) # bbb-01.yaml does not contain booti parameters, try to convert to a uImage self.assertEqual("bootm", uboot_prepare.bootcommand) self.assertTrue(uboot_prepare.mkimage_conversion)
def test_panda_lxc_template(self): logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) logger = logging.getLogger("unittests") logger.disabled = True logger.propagate = False logger = logging.getLogger("dispatcher") logging.disable(logging.DEBUG) logger.disabled = True logger.propagate = False data = """{% extends 'panda.jinja2' %} {% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command off --port 07' %} {% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command reboot --port 07' %} {% set connection_command = 'telnet serial4 7010' %} {% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command on --port 07' %}""" self.assertTrue(self.validate_data("staging-panda-01", data)) template_dict = prepare_jinja_template("staging-panda-01", data, raw=False) fdesc, device_yaml = tempfile.mkstemp() os.write(fdesc, yaml.dump(template_dict).encode()) panda = NewDevice(device_yaml) lxc_yaml = os.path.join( os.path.dirname(__file__), "sample_jobs", "panda-lxc-aep.yaml" ) with open(lxc_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, panda, 4577, None, "") os.close(fdesc) job.logger = DummyLogger() job.logger.disabled = True job.logger.propagate = False job.validate()
def test_zimage_nobootz(self): # drop bootz from the device for this part of the test del self.device["parameters"]["bootz"] self.deploy_block["kernel"]["type"] = "zimage" job = self.parser.parse(yaml.dump(self.base_data), self.device, 4212, None, "") job.logger = DummyLogger() job.validate() deploy = [ action for action in job.pipeline.actions if action.name == "tftp-deploy" ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == "prepare-tftp-overlay" ][0] prepare = [ action for action in overlay.internal_pipeline.actions if action.name == "prepare-kernel" ][0] uboot_prepare = [ action for action in prepare.internal_pipeline.actions if action.name == "uboot-prepare-kernel" ][0] self.assertEqual("zimage", uboot_prepare.kernel_type) self.assertEqual("bootm", uboot_prepare.bootcommand) self.assertTrue(uboot_prepare.mkimage_conversion)
def test_primary_interface(self, which_mock): with open(self.filename) as yaml_data: alpha_data = yaml_safe_load(yaml_data) for interface in self.device["parameters"]["interfaces"]: # jinja2 processing of tags: [] results in tags: if self.device["parameters"]["interfaces"][interface][ "tags"] == []: self.device["parameters"]["interfaces"][interface][ "tags"] = None parser = JobParser() job = parser.parse(yaml_safe_dump(alpha_data), self.device, 4212, None, "") deploy = [ action for action in job.pipeline.actions if action.name == "tftp-deploy" ][0] prepare = [ action for action in deploy.internal_pipeline.actions if action.name == "prepare-tftp-overlay" ][0] overlay = [ action for action in prepare.internal_pipeline.actions if action.name == "lava-overlay" ][0] vland_overlay = [ action for action in overlay.internal_pipeline.actions if action.name == "lava-vland-overlay" ][0] vland_overlay.validate() job.logger = DummyLogger() job.validate()
def create_kvm_job(self, filename, validate=False): """ Custom function to allow for extra exception handling. """ job_ctx = { "arch": "amd64", "no_kvm": True, } # override to allow unit tests on all types of systems (data, device_dict) = self.create_device("kvm01.jinja2", job_ctx) device = NewDevice(yaml_safe_load(data)) print("####### Device configuration #######") print(data) print("#######") self.validate_data("hi6220-hikey-01", device_dict) kvm_yaml = os.path.join(os.path.dirname(__file__), filename) parser = JobParser() job_data = "" with open(kvm_yaml) as sample_job_data: job_data = yaml_safe_load(sample_job_data.read()) print("########## Test Job Submission validation #######") if validate: validate_job(job_data, strict=False) try: job = parser.parse(yaml.dump(job_data), device, 4212, None, "") job.logger = DummyLogger() except LAVAError as exc: print(exc) return None return job
def test_job_no_tags(self, which_mock): with open(self.filename) as yaml_data: alpha_data = yaml_safe_load(yaml_data) for vlan_key, _ in alpha_data["protocols"][VlandProtocol.name].items(): alpha_data["protocols"][VlandProtocol.name][vlan_key] = { "tags": [] } # removed tags from original job to simulate job where any interface tags will be acceptable self.assertEqual(alpha_data["protocols"][VlandProtocol.name], {"vlan_one": { "tags": [] }}) parser = JobParser() job = parser.parse(yaml_safe_dump(alpha_data), self.device, 4212, None, "") job.logger = DummyLogger() job.validate() vprotocol = [ vprotocol for vprotocol in job.protocols if vprotocol.name == VlandProtocol.name ][0] self.assertTrue(vprotocol.valid) self.assertEqual(vprotocol.names, {"vlan_one": "4212vlanone"}) self.assertFalse(vprotocol.check_timeout(120, {"request": "no call"})) self.assertRaises(JobError, vprotocol.check_timeout, 60, "deploy_vlans") self.assertRaises(JobError, vprotocol.check_timeout, 60, {"request": "deploy_vlans"}) self.assertTrue( vprotocol.check_timeout(120, {"request": "deploy_vlans"})) for vlan_name in job.parameters["protocols"][VlandProtocol.name]: self.assertIn(vlan_name, vprotocol.params) self.assertIn("switch", vprotocol.params[vlan_name]) self.assertIn("port", vprotocol.params[vlan_name])
def create_custom_job(self, template, job_data, job_ctx=None, validate=True): if validate: validate_job(job_data, strict=False) if job_ctx: job_data["context"] = job_ctx else: job_ctx = job_data.get("context") (data, device_dict) = self.create_device(template, job_ctx) device = NewDevice(yaml_safe_load(data)) print("####### Device configuration #######") print(data) print("#######") try: parser = JobParser() job = parser.parse(yaml.dump(job_data), device, 4999, None, "") except (ConfigurationError, TypeError) as exc: print("####### Parser exception ########") print(device) print("#######") raise ConfigurationError("Invalid device: %s" % exc) job.logger = DummyLogger() return job
def test_device_environment_validity(self): # pylint: disable=invalid-name """ Use non-YAML syntax a bit like existing device config syntax. Ensure this syntax is picked up as invalid. """ data = """ # YAML syntax. overrides: DEBEMAIL = "*****@*****.**" DEBFULLNAME: "Neil Williams" """ factory = Factory() job_parser = JobParser() (rendered, _) = factory.create_device("bbb-01.jinja2") device = NewDevice(yaml_safe_load(rendered)) sample_job_file = os.path.join(os.path.dirname(__file__), "sample_jobs/uboot-ramdisk.yaml") with open(sample_job_file) as sample_job_data: job = job_parser.parse(sample_job_data, device, 4212, None, "", env_dut=data) job.logger = DummyLogger() self.assertEqual(job.parameters["env_dut"], data) with self.assertRaises(JobError): job.validate()
def test_uimage(self): self.deploy_block["kernel"]["type"] = "uimage" job = self.parser.parse(yaml.dump(self.base_data), self.device, 4212, None, "") job.logger = DummyLogger() job.validate() deploy = [ action for action in job.pipeline.actions if action.name == "tftp-deploy" ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == "prepare-tftp-overlay" ][0] prepare = [ action for action in overlay.internal_pipeline.actions if action.name == "prepare-kernel" ][0] uboot_prepare = [ action for action in prepare.internal_pipeline.actions if action.name == "uboot-prepare-kernel" ][0] self.assertEqual("uimage", uboot_prepare.kernel_type) self.assertEqual("bootm", uboot_prepare.bootcommand) self.assertFalse(uboot_prepare.mkimage_conversion)
def create_job(self, sample_job, device_file): device = NewDevice(os.path.join(os.path.dirname(__file__), device_file)) j_yaml = os.path.join(os.path.dirname(__file__), sample_job) with open(j_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4212, None, "") job.logger = DummyLogger() return job
def test_without_health_checks(self): # Make sure that get_health_check does return None Device.get_health_check = lambda cls: None self.assertEqual(self.device01.get_health_check(), None) self.assertEqual(self.device02.get_health_check(), None) self.assertEqual(self.device03.get_health_check(), None) # Schedule without health check available_devices = schedule_health_checks(DummyLogger())[0] self.assertEqual(available_devices, {"panda": ["panda01", "panda03"]})
def create_jaq_job(self, filename): device = NewDevice( os.path.join(os.path.dirname(__file__), "devices/jaq-01.yaml")) yaml = os.path.join(os.path.dirname(__file__), filename) with open(yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4212, None, "") job.logger = DummyLogger() return job
def create_b2260_job(self, filename): # FIXME: b2260 Jinja2 template does not have flasher support. device = NewDevice( os.path.join(os.path.dirname(__file__), "devices/b2260-01.yaml")) with open(os.path.join(os.path.dirname(__file__), filename)) as f_in: parser = JobParser() job = parser.parse(f_in, device, 456, None, "") job.logger = DummyLogger() return job
def create_adb_nuc_job(self, filename): # pylint: disable=no-self-use device = NewDevice( os.path.join(os.path.dirname(__file__), "devices/adb-nuc-01.yaml")) job_yaml = os.path.join(os.path.dirname(__file__), filename) with open(job_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4577, None, "") job.logger = DummyLogger() return job
def create_hikey_aep_job(self, filename): device = NewDevice( os.path.join(os.path.dirname(__file__), "devices/hi6220-hikey-01.yaml")) job_yaml = os.path.join(os.path.dirname(__file__), filename) with open(job_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4577, None, "") job.logger = DummyLogger() return job
def create_hikey_bl_job(self, filename): (data, device_dict) = self.create_hikey_bl_device("hi6220-hikey-01") device = NewDevice(yaml_safe_load(data)) self.validate_data("hi6220-hikey-01", device_dict) fastboot_yaml = os.path.join(os.path.dirname(__file__), filename) with open(fastboot_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4212, None, "") job.logger = DummyLogger() return job
def create_x15_bl_job(self, filename): (data, device_dict) = self.create_x15_bl_device("x15-bl-01") device = NewDevice(yaml.safe_load(data)) self.validate_data("x15-bl-01", device_dict) uboot_yaml = os.path.join(os.path.dirname(__file__), filename) with open(uboot_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4213, None, "") job.logger = DummyLogger() return job
def create_qemu_installer_job(self): (rendered, _) = self.create_device("kvm01.jinja2") device = NewDevice(yaml_safe_load(rendered)) sample_job_file = os.path.join( os.path.dirname(__file__), "sample_jobs/qemu-debian-installer.yaml") parser = JobParser() with open(sample_job_file) as sample_job_data: job = parser.parse(sample_job_data, device, 4212, None, "") job.logger = DummyLogger() return job
def test_health_visibility_all_restricted(self): self._check_initial_state() self.device_type01.disable_health_check = False self.device_type01.save() schedule_health_checks(DummyLogger())[0] self._check_hc_scheduled(self.device01) self._check_hc_not_scheduled(self.device02) self._check_hc_scheduled(self.device03)
def test_disabled_hc(self): # Make sure that get_health_check does return something Device.get_health_check = _minimal_valid_job self.assertNotEqual(self.device01.get_health_check(), None) self.assertNotEqual(self.device02.get_health_check(), None) self.assertNotEqual(self.device03.get_health_check(), None) self.device_type01.disable_health_check = True self.device_type01.save() available_devices = schedule_health_checks(DummyLogger())[0] self.assertEqual(available_devices, {"panda": ["panda01", "panda03"]})
def test_without_previous_hc_device_health_unknown(self): # Make sure that get_health_check does return something Device.get_health_check = _minimal_valid_job self.assertNotEqual(self.device01.get_health_check(), None) self.assertNotEqual(self.device02.get_health_check(), None) self.assertNotEqual(self.device03.get_health_check(), None) available_devices = schedule_health_checks(DummyLogger())[0] self.assertEqual(available_devices, {"panda": []}) self._check_hc_scheduled(self.device01) self._check_hc_not_scheduled(self.device02) self._check_hc_scheduled(self.device03)
def test_prompt_from_job(self): # pylint: disable=too-many-locals """ Support setting the prompt after login via the job Loads a known YAML, adds a prompt to the dict and re-parses the job. Checks that the prompt is available in the expect_shell_connection action. """ job = self.factory.create_job("x86-01.jinja2", "sample_jobs/ipxe-ramdisk.yaml") job.validate() bootloader = [ action for action in job.pipeline.actions if action.name == "bootloader-action" ][0] retry = [ action for action in bootloader.internal_pipeline.actions if action.name == "bootloader-retry" ][0] expect = [ action for action in retry.internal_pipeline.actions if action.name == "expect-shell-connection" ][0] check = expect.parameters (rendered, _) = self.factory.create_device("x86-01.jinja2") device = NewDevice(yaml.safe_load(rendered)) extra_yaml = os.path.join(os.path.dirname(__file__), "sample_jobs/ipxe.yaml") with open(extra_yaml) as data: sample_job_string = data.read() parser = JobParser() sample_job_data = yaml.safe_load(sample_job_string) boot = [ item["boot"] for item in sample_job_data["actions"] if "boot" in item ][0] self.assertIsNotNone(boot) sample_job_string = yaml.dump(sample_job_data) job = parser.parse(sample_job_string, device, 4212, None, "") job.logger = DummyLogger() job.validate() bootloader = [ action for action in job.pipeline.actions if action.name == "bootloader-action" ][0] retry = [ action for action in bootloader.internal_pipeline.actions if action.name == "bootloader-retry" ][0] expect = [ action for action in retry.internal_pipeline.actions if action.name == "expect-shell-connection" ][0]
def test_multi_deploy(self): self.assertIsNotNone(self.parsed_data) job = Job(4212, self.parsed_data, None) job.timeout = Timeout("Job", Timeout.parse({"minutes": 2})) pipeline = Pipeline(job=job) device = TestMultiDeploy.FakeDevice() self.assertIsNotNone(device) job.device = device job.logger = DummyLogger() job.pipeline = pipeline counts = {} for action_data in self.parsed_data["actions"]: for name in action_data: counts.setdefault(name, 1) parameters = action_data[name] test_deploy = TestMultiDeploy.TestDeploy( pipeline, parameters, job) self.assertEqual({}, test_deploy.action.data) counts[name] += 1 # check that only one action has the example set self.assertEqual( ["nowhere"], [ detail["deploy"]["example"] for detail in self.parsed_data["actions"] if "example" in detail["deploy"] ], ) self.assertEqual( ["faked", "valid"], [ detail["deploy"]["parameters"] for detail in self.parsed_data["actions"] if "parameters" in detail["deploy"] ], ) self.assertIsInstance(pipeline.actions[0], TestMultiDeploy.TestDeployAction) self.assertIsInstance(pipeline.actions[1], TestMultiDeploy.TestDeployAction) self.assertIsInstance(pipeline.actions[2], TestMultiDeploy.TestDeployAction) job.validate() self.assertEqual([], job.pipeline.errors) job.run() self.assertNotEqual(pipeline.actions[0].data, {"fake-deploy": pipeline.actions[0].parameters}) self.assertEqual(pipeline.actions[1].data, {"fake-deploy": pipeline.actions[2].parameters}) # check that values from previous DeployAction run actions have been cleared self.assertEqual(pipeline.actions[2].data, {"fake-deploy": pipeline.actions[2].parameters})
def test_health_visibility_some_restricted(self): self._check_initial_state() self.device_type01.disable_health_check = False self.device_type01.owners_only = False self.device_type01.save() schedule_health_checks(DummyLogger())[0] self._check_hc_scheduled(self.device01) self._check_hc_not_scheduled(self.device02) # device03 is restricted in setUp self._check_hc_scheduled(self.device03)
def test_health_visibility_owners(self): self._check_initial_state() self.device_type01.disable_health_check = False self.device_type01.owners_only = True self.device_type01.save() schedule_health_checks(DummyLogger())[0] # no health checks can be scheduled for _minimal_valid_job self._check_hc_not_scheduled(self.device01) self._check_hc_not_scheduled(self.device02) self._check_hc_not_scheduled(self.device03)
def test_low_medium_high_with_hc(self): # Enable health checks self.device_type01.health_denominator = DeviceType.HEALTH_PER_HOUR self.device_type01.health_frequency = 24 self.device_type01.save() Device.get_health_check = _minimal_valid_job self.assertNotEqual(self.device01.get_health_check(), None) jobs = [] for p in [ TestJob.LOW, TestJob.MEDIUM, TestJob.HIGH, TestJob.MEDIUM, TestJob.LOW, ]: j = TestJob.objects.create( requested_device_type=self.device_type01, user=self.user, submitter=self.user, is_public=True, definition=_minimal_valid_job(None), priority=p, ) jobs.append(j) # Check that an health check will be scheduled before any jobs log = DummyLogger() schedule(log) self.device01.refresh_from_db() self.assertEqual(self.device01.state, Device.STATE_RESERVED) self._check_job(jobs[0], TestJob.STATE_SUBMITTED) self._check_job(jobs[1], TestJob.STATE_SUBMITTED) self._check_job(jobs[2], TestJob.STATE_SUBMITTED) self._check_job(jobs[3], TestJob.STATE_SUBMITTED) self._check_job(jobs[4], TestJob.STATE_SUBMITTED) current_hc = self.device01.current_job() self.assertEqual(current_hc.state, TestJob.STATE_SCHEDULED) current_hc.go_state_finished(TestJob.HEALTH_COMPLETE) current_hc.save() # Check that the next job is the highest priority schedule(log) self.device01.refresh_from_db() self.assertEqual(self.device01.state, Device.STATE_RESERVED) self._check_job(jobs[0], TestJob.STATE_SUBMITTED) self._check_job(jobs[1], TestJob.STATE_SUBMITTED) self._check_job(jobs[2], TestJob.STATE_SCHEDULED, self.device01) self._check_job(jobs[3], TestJob.STATE_SUBMITTED) self._check_job(jobs[4], TestJob.STATE_SUBMITTED)
def test_juno_deployment(self): factory = RemovableFactory() job = factory.create_job("sample_jobs/juno-uboot-removable.yaml", "../devices/juno-uboot.yaml") job.logger = DummyLogger() job.validate() self.assertEqual(job.pipeline.errors, []) self.assertIn("usb", job.device["parameters"]["media"].keys()) deploy_params = [ methods for methods in job.parameters["actions"] if "deploy" in methods.keys() ][1]["deploy"] self.assertIn("device", deploy_params) self.assertIn(deploy_params["device"], job.device["parameters"]["media"]["usb"]) self.assertIn( "uuid", job.device["parameters"]["media"]["usb"][deploy_params["device"]]) self.assertIn( "device_id", job.device["parameters"]["media"]["usb"][deploy_params["device"]], ) self.assertNotIn( "boot_part", job.device["parameters"]["media"]["usb"][deploy_params["device"]], ) tftp_deploys = [ action for action in job.pipeline.actions if action.name == "tftp-deploy" ] self.assertEqual(len(tftp_deploys), 2) first_deploy = tftp_deploys[0] second_deploy = tftp_deploys[1] self.assertIsNotNone(first_deploy) self.assertIsNotNone(second_deploy) self.assertEqual("openembedded", first_deploy.parameters["namespace"]) self.assertEqual("android", second_deploy.parameters["namespace"]) self.assertNotIn("deployment_data", first_deploy.parameters) self.assertNotIn("deployment_data", second_deploy.parameters) storage_deploy_action = [ action for action in job.pipeline.actions if action.name == "storage-deploy" ][0] download_action = [ action for action in storage_deploy_action.internal_pipeline.actions if action.name == "download-retry" ][0] self.assertIsNotNone(download_action) self.assertEqual("android", storage_deploy_action.parameters["namespace"])
def create_uefi_job(self, filename): device = NewDevice( os.path.join(os.path.dirname(__file__), "devices/mustang-uefi.yaml")) mustang_yaml = os.path.join(os.path.dirname(__file__), filename) with open(mustang_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 0, None, dispatcher_config="") job.logger = DummyLogger() return job