def test_device_power(self): factory = Factory() (rendered, _) = factory.create_device('bbb-01.jinja2') device = yaml.load(rendered) self.assertNotEqual(device['commands'].get('hard_reset', ''), '') (rendered, _) = factory.create_device('kvm01.jinja2') device = yaml.load(rendered) self.assertNotIn('commands', device)
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.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_device_environment(self): 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 ) job.validate() boot_actions = [ action.internal_pipeline.actions for action in job.pipeline.actions if action.name == 'uboot-action'][0] retry = [action for action in boot_actions if action.name == 'uboot-retry'][0] boot_env = [action for action in retry.internal_pipeline.actions if action.name == 'export-device-env'][0] found = False for line in boot_env.env: if 'DEBFULLNAME' in line: found = True # assert that the string containing a space still contains that space and is quoted self.assertIn('\\\'Neil Williams\\\'', line) self.assertTrue(found)
def test_device_constants(self): factory = Factory() (rendered, _) = factory.create_device('bbb-01.jinja2') device = NewDevice(yaml.safe_load(rendered)) self.assertIn('constants', device) self.assertEqual(device.get_constant('kernel-start-message'), "Linux version [0-9]") self.assertRaises(ConfigurationError, device.get_constant, ('non-existing-const'))
class TestDefinitionHandlers(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.factory = Factory() self.job = self.factory.create_kvm_job('sample_jobs/kvm.yaml') def test_testshell(self): testshell = None for action in self.job.pipeline.actions: self.assertIsNotNone(action.name) if isinstance(action, TestShellRetry): testshell = action.pipeline.actions[0] break self.assertIsInstance(testshell, TestShellAction) self.assertTrue(testshell.valid) if 'timeout' in testshell.parameters: time_int = Timeout.parse(testshell.parameters['timeout']) else: time_int = Timeout.default_duration() self.assertEqual( datetime.timedelta(seconds=time_int).total_seconds(), testshell.timeout.duration) def test_missing_handler(self): (rendered, _) = self.factory.create_device('kvm01.jinja2') device = NewDevice(yaml.load(rendered)) kvm_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/kvm.yaml') parser = JobParser() with open(kvm_yaml) as sample_job_data: data = yaml.load(sample_job_data) data['actions'][2]['test']['definitions'][0][ 'from'] = 'unusable-handler' try: job = parser.parse(yaml.dump(data), device, 4212, None, "") job.logger = DummyLogger() except JobError: pass except Exception as exc: # pylint: disable=broad-except self.fail(exc) else: self.fail('JobError not raised') def test_eventpatterns(self): testshell = None for action in self.job.pipeline.actions: self.assertIsNotNone(action.name) if isinstance(action, TestShellRetry): testshell = action.pipeline.actions[0] break self.assertTrue(testshell.valid) self.assertFalse(testshell.check_patterns('exit', None, '')) self.assertRaises(InfrastructureError, testshell.check_patterns, 'eof', None, '') self.assertTrue(testshell.check_patterns('timeout', None, ''))
def test_empty_device_environment(self): factory = Factory() data = None 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) self.assertEqual( job.parameters['env_dut'], None )
def test_new_device(self): factory = Factory() (rendered, _) = factory.create_device('kvm01.jinja2') kvm01 = yaml.load(rendered) try: self.assertIsNotNone(kvm01['actions']) except Exception: self.fail("missing actions block for device") try: self.assertIsNotNone(kvm01['actions']['boot']) except Exception: self.fail("missing boot block for device") try: self.assertIsNotNone(kvm01['actions']['deploy']) except Exception: self.fail("missing boot block for device") self.assertTrue('qemu' in kvm01['actions']['boot']['methods']) self.assertTrue('image' in kvm01['actions']['deploy']['methods'])
class TestBootloaderAction(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.factory = Factory() def test_simulated_action(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe-ramdisk.yaml') self.assertIsNotNone(job) description_ref = self.pipeline_reference('ipxe.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) self.assertIsNone(job.validate()) def test_tftp_pipeline(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe-ramdisk.yaml') self.assertEqual([action.name for action in job.pipeline.actions], [ 'tftp-deploy', 'bootloader-action', 'lava-test-retry', 'finalize' ]) tftp = [ action for action in job.pipeline.actions if action.name == 'tftp-deploy' ][0] self.assertTrue( tftp.get_namespace_data(action=tftp.name, label='tftp', key='ramdisk')) self.assertIsNotNone(tftp.internal_pipeline) self.assertEqual( [action.name for action in tftp.internal_pipeline.actions], [ 'download-retry', 'download-retry', 'download-retry', 'prepare-tftp-overlay', 'lxc-create-udev-rule-action', 'deploy-device-env' ]) self.assertIn('ramdisk', [ action.key for action in tftp.internal_pipeline.actions if hasattr(action, 'key') ]) self.assertIn('kernel', [ action.key for action in tftp.internal_pipeline.actions if hasattr(action, 'key') ]) def test_device_x86(self): job = self.factory.create_job('x86-02.jinja2', 'sample_jobs/ipxe-ramdisk.yaml') self.assertEqual( job.device['commands']['connections']['uart0']['connect'], 'telnet bumblebee 8003') self.assertEqual(job.device['commands'].get('interrupt', ' '), ' ') methods = job.device['actions']['boot']['methods'] self.assertIn('ipxe', methods) self.assertEqual( methods['ipxe']['parameters'].get('bootloader_prompt'), 'iPXE>') def test_bootloader_action(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe-ramdisk.yaml') job.validate() self.assertEqual(job.pipeline.errors, []) self.assertIn('ipxe', job.device['actions']['boot']['methods']) params = job.device['actions']['boot']['methods']['ipxe']['parameters'] boot_message = params.get( 'boot_message', job.device.get_constant('kernel-start-message')) self.assertIsNotNone(boot_message) bootloader_action = [ action for action in job.pipeline.actions if action.name == 'bootloader-action' ][0] bootloader_retry = [ action for action in bootloader_action.internal_pipeline.actions if action.name == 'bootloader-retry' ][0] commands = [ action for action in bootloader_retry.internal_pipeline.actions if action.name == 'bootloader-commands' ][0] self.assertEqual(commands.character_delay, 500) for action in job.pipeline.actions: action.validate() if isinstance(action, BootloaderAction): self.assertIn('method', action.parameters) self.assertEqual('ipxe', action.parameters['method']) self.assertEqual( 'reboot: Restarting system', action.parameters.get('parameters', {}).get( 'shutdown-message', job.device.get_constant('shutdown-message'))) if isinstance(action, TftpAction): self.assertIn('ramdisk', action.parameters) self.assertIn('kernel', action.parameters) self.assertIn('to', action.parameters) self.assertEqual('tftp', action.parameters['to']) self.assertTrue(action.valid) def test_overlay_action(self): # pylint: disable=too-many-locals parameters = { 'device_type': 'x86', 'job_name': 'ipxe-pipeline', 'job_timeout': '15m', 'action_timeout': '5m', 'priority': 'medium', 'actions': { 'boot': { 'method': 'ipxe', 'commands': 'ramdisk', 'prompts': ['linaro-test', 'root@debian:~#'] }, 'deploy': { 'ramdisk': 'initrd.gz', 'kernel': 'zImage', } } } (rendered, _) = self.factory.create_device('x86-01.jinja2') device = NewDevice(yaml.safe_load(rendered)) job = Job(4212, parameters, None) job.device = device pipeline = Pipeline(job=job, parameters=parameters['actions']['boot']) job.pipeline = pipeline overlay = BootloaderCommandOverlay() pipeline.add_action(overlay) ip_addr = dispatcher_ip(None) kernel = parameters['actions']['deploy']['kernel'] ramdisk = parameters['actions']['deploy']['ramdisk'] substitution_dictionary = { '{SERVER_IP}': ip_addr, '{RAMDISK}': ramdisk, '{KERNEL}': kernel, '{LAVA_MAC}': "00:00:00:00:00:00" } params = device['actions']['boot']['methods'] params['ipxe']['ramdisk']['commands'] = substitute( params['ipxe']['ramdisk']['commands'], substitution_dictionary) commands = params['ipxe']['ramdisk']['commands'] self.assertIs(type(commands), list) self.assertIn("dhcp net0", commands) self.assertIn( "set console console=ttyS0,115200n8 lava_mac=00:00:00:00:00:00", commands) self.assertIn("set extraargs ip=dhcp", commands) self.assertNotIn( "kernel tftp://{SERVER_IP}/{KERNEL} ${extraargs} ${console}", commands) self.assertNotIn("initrd tftp://{SERVER_IP}/{RAMDISK}", commands) self.assertIn("boot", commands) def test_download_action(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe.yaml') for action in job.pipeline.actions: action.validate() self.assertTrue(action.valid) job.validate() self.assertEqual(job.pipeline.errors, []) deploy = None overlay = None extract = None for action in job.pipeline.actions: if action.name == 'tftp-deploy': deploy = action if deploy: for action in deploy.internal_pipeline.actions: if action.name == 'prepare-tftp-overlay': overlay = action if overlay: for action in overlay.internal_pipeline.actions: if action.name == 'extract-nfsrootfs': extract = action test_dir = overlay.get_namespace_data(action='test', label='results', key='lava_test_results_dir') self.assertIsNotNone(test_dir) self.assertIn('/lava-', test_dir) self.assertIsNotNone(extract) self.assertEqual(extract.timeout.duration, 120) def test_reset_actions(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe.yaml') bootloader_action = None bootloader_retry = None reset_action = None for action in job.pipeline.actions: action.validate() self.assertTrue(action.valid) if action.name == 'bootloader-action': bootloader_action = action names = [ r_action.name for r_action in bootloader_action.internal_pipeline.actions ] self.assertIn('connect-device', names) self.assertIn('bootloader-retry', names) for action in bootloader_action.internal_pipeline.actions: if action.name == 'bootloader-retry': bootloader_retry = action names = [ r_action.name for r_action in bootloader_retry.internal_pipeline.actions ] self.assertIn('reset-device', names) self.assertIn('bootloader-interrupt', names) self.assertIn('expect-shell-connection', names) self.assertIn('bootloader-commands', names) for action in bootloader_retry.internal_pipeline.actions: if action.name == 'reset-device': reset_action = action names = [ r_action.name for r_action in reset_action.internal_pipeline.actions ] self.assertIn('pdu-reboot', names) @unittest.skipIf(infrastructure_error('telnet'), "telnet not installed") 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_xz_nfs(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe-nfs.yaml') # this job won't validate as the .xz nfsrootfs URL is a fiction self.assertRaises(JobError, job.validate) tftp_deploy = [ action for action in job.pipeline.actions if action.name == 'tftp-deploy' ][0] prepare = [ action for action in tftp_deploy.internal_pipeline.actions if action.name == 'prepare-tftp-overlay' ][0] nfs = [ action for action in prepare.internal_pipeline.actions if action.name == 'extract-nfsrootfs' ][0] self.assertIn('compression', nfs.parameters['nfsrootfs']) self.assertEqual(nfs.parameters['nfsrootfs']['compression'], 'xz') def test_ipxe_with_monitor(self): job = self.factory.create_job('x86-01.jinja2', 'sample_jobs/ipxe-monitor.yaml') job.validate() description_ref = self.pipeline_reference('ipxe-monitor.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False))
class TestLxcWithDevices(StdoutTestCase): def setUp(self): super().setUp() self.factory = LxcFactory() self.job = self.factory.create_bbb_lxc_job('sample_jobs/bbb-lxc.yaml') def test_lxc_feedback(self): # pylint: disable=too-many-locals self.assertIsNotNone(self.job) # validate with two test actions, lxc and device self.job.validate() drone_test = [ action for action in self.job.pipeline.actions if action.name == 'lava-test-retry' ][0] self.assertNotEqual(10, drone_test.connection_timeout.duration) drone_shell = [ action for action in drone_test.internal_pipeline.actions if action.name == 'lava-test-shell' ][0] self.assertEqual(10, drone_shell.connection_timeout.duration) def test_lxc_with_device(self): # pylint: disable=too-many-locals self.assertIsNotNone(self.job) # validate with two test actions, lxc and device self.job.validate() lxc_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/bbb-lxc.yaml') with open(lxc_yaml) as sample_job_data: data = yaml.safe_load(sample_job_data) lxc_deploy = [ action for action in self.job.pipeline.actions if action.name == 'lxc-deploy' ][0] overlay = [ action for action in lxc_deploy.internal_pipeline.actions if action.name == 'lava-overlay' ][0] test_def = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] self.assertIsNotNone(test_def.level, test_def.test_list) runner = [ action for action in test_def.internal_pipeline.actions if action.name == 'test-runscript-overlay' ][0] self.assertIsNotNone(runner.testdef_levels) tftp_deploy = [ action for action in self.job.pipeline.actions if action.name == 'tftp-deploy' ][0] prepare = [ action for action in tftp_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] test_def = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] namespace = test_def.parameters.get('namespace') self.assertIsNotNone(namespace) test_actions = [ action for action in self.job.parameters['actions'] if 'test' in action ] for action in test_actions: if 'namespace' in action['test']: if action['test']['namespace'] == namespace: self.assertEqual(action['test']['definitions'][0]['name'], 'smoke-tests-bbb') namespace_tests = [ action['test']['definitions'] for action in test_actions if 'namespace' in action['test'] and action['test']['namespace'] == namespace ] self.assertEqual(len(namespace_tests), 1) self.assertEqual(len(test_actions), 2) self.assertEqual('smoke-tests-bbb', namespace_tests[0][0]['name']) self.assertEqual('smoke-tests-bbb', test_def.test_list[0][0]['name']) self.assertIsNotNone(test_def.level, test_def.test_list) runner = [ action for action in test_def.internal_pipeline.actions if action.name == 'test-runscript-overlay' ][0] self.assertIsNotNone(runner.testdef_levels) # remove the second test action data['actions'].pop() test_actions = [ action for action in data['actions'] if 'test' in action ] self.assertEqual(len(test_actions), 1) self.assertEqual(test_actions[0]['test']['namespace'], 'probe') parser = JobParser() (rendered, _) = self.factory.create_device('bbb-01.jinja2') device = NewDevice(yaml.safe_load(rendered)) job = parser.parse(yaml.dump(data), device, 4577, None, "") job.logger = DummyLogger() job.validate() lxc_deploy = [ action for action in self.job.pipeline.actions if action.name == 'lxc-deploy' ][0] overlay = [ action for action in lxc_deploy.internal_pipeline.actions if action.name == 'lava-overlay' ][0] test_def = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] self.assertIsNotNone(test_def.level, test_def.test_list) runner = [ action for action in test_def.internal_pipeline.actions if action.name == 'test-runscript-overlay' ][0] self.assertIsNotNone(runner.testdef_levels) def test_lxc_with_static_device(self): # pylint: disable=too-many-locals self.job = self.factory.create_hikey_aep_job( 'sample_jobs/hi6220-hikey.yaml') self.job.validate() lxc_boot = [ action for action in self.job.pipeline.actions if action.name == 'lxc-boot' ][0] lxc_static = [ action for action in lxc_boot.internal_pipeline.actions if action.name == 'lxc-add-static' ][0] self.assertIsNotNone(lxc_static) self.assertIsInstance(self.job.device.get('static_info'), list) self.assertEqual(len(self.job.device.get('static_info')), 1) for board in self.job.device.get('static_info'): self.assertIsInstance(board, dict) self.assertIn('board_id', board) self.assertEqual(board['board_id'], 'S/NO62200001') description_ref = self.pipeline_reference('hi6220-hikey.yaml', job=self.job) self.assertEqual(description_ref, self.job.pipeline.describe(False)) def test_lxc_without_lxctest(self): # pylint: disable=too-many-locals lxc_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/bbb-lxc-notest.yaml') with open(lxc_yaml) as sample_job_data: data = yaml.safe_load(sample_job_data) parser = JobParser() (rendered, _) = self.factory.create_device('bbb-01.jinja2') device = NewDevice(yaml.safe_load(rendered)) job = parser.parse(yaml.dump(data), device, 4577, None, "") job.logger = DummyLogger() job.validate() lxc_deploy = [ action for action in job.pipeline.actions if action.name == 'lxc-deploy' ][0] names = [ action.name for action in lxc_deploy.internal_pipeline.actions ] self.assertNotIn('prepare-tftp-overlay', names) namespace1 = lxc_deploy.parameters.get('namespace') tftp_deploy = [ action for action in job.pipeline.actions if action.name == 'tftp-deploy' ][0] prepare = [ action for action in tftp_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] test_def = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] namespace = test_def.parameters.get('namespace') self.assertIsNotNone(namespace) self.assertIsNotNone(namespace1) self.assertNotEqual(namespace, namespace1) self.assertNotEqual(self.job.pipeline.describe(False), job.pipeline.describe(False)) test_actions = [ action for action in job.parameters['actions'] if 'test' in action ] for action in test_actions: if 'namespace' in action['test']: if action['test']['namespace'] == namespace: self.assertEqual(action['test']['definitions'][0]['name'], 'smoke-tests-bbb') else: self.fail("Found a test action not from the tftp boot") namespace_tests = [ action['test']['definitions'] for action in test_actions if 'namespace' in action['test'] and action['test']['namespace'] == namespace ] self.assertEqual(len(namespace_tests), 1) self.assertEqual(len(test_actions), 1) description_ref = self.pipeline_reference('bbb-lxc-notest.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) def test_adb_nuc_job(self): self.factory = LxcFactory() job = self.factory.create_adb_nuc_job('sample_jobs/adb-nuc.yaml') description_ref = self.pipeline_reference('adb-nuc.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) def test_iot_lxc(self): self.factory = Factory() job = self.factory.create_job('frdm-k64f-01.jinja2', 'sample_jobs/frdm-k64f-lxc.yaml') job.validate() self.assertIsNotNone([ action for action in job.pipeline.actions if action.name == 'lxc-deploy' ]) self.assertIsNotNone([ action for action in job.pipeline.actions if action.name == 'lxc-boot' ]) description_ref = self.pipeline_reference('frdm-k64f-lxc.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False))
class TestRemovable(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.factory = Factory() def test_device_parameters(self): """ Test that the correct parameters have been set for the device """ (rendered, _) = self.factory.create_device('cubie2.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) self.assertIsNotNone(cubie['parameters']['media'].get('usb')) self.assertIsNotNone(cubie.get('commands')) self.assertIsNotNone(cubie.get('actions')) self.assertIsNotNone(cubie['actions'].get('deploy')) self.assertIsNotNone(cubie['actions']['deploy'].get('methods')) self.assertIn('usb', cubie['actions']['deploy']['methods']) self.assertIsNotNone(cubie['actions'].get('boot')) self.assertIsNotNone(cubie['actions']['boot'].get('methods')) self.assertIn('u-boot', cubie['actions']['boot']['methods']) u_boot_params = cubie['actions']['boot']['methods']['u-boot'] self.assertIn('usb', u_boot_params) self.assertIn('commands', u_boot_params['usb']) self.assertIn('parameters', u_boot_params) self.assertIn('bootloader_prompt', u_boot_params['parameters']) def _check_valid_job(self, device, test_file): self.maxDiff = None # pylint: disable=invalid-name job_parser = JobParser() sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs/{}'.format(test_file)) with open(sample_job_file) as sample_job_data: job = job_parser.parse(sample_job_data, device, 4212, None, "") job.logger = DummyLogger() try: job.validate() except JobError: self.fail(job.pipeline.errors) description_ref = self.pipeline_reference(test_file, job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) return job def _check_job_parameters(self, device, job, agent_key): mass_storage = None # deploy for action in job.pipeline.actions: if isinstance(action, DeployAction): if isinstance(action, MassStorage): self.assertTrue(action.valid) agent = action.parameters[agent_key]['tool'] self.assertTrue(agent.startswith('/')) # needs to be a full path but on the device, so avoid os.path self.assertIn(action.parameters['device'], job.device['parameters']['media']['usb']) mass_storage = action self.assertIsNotNone(mass_storage) self.assertIn('device', mass_storage.parameters) self.assertIn(mass_storage.parameters['device'], device['parameters']['media']['usb']) self.assertIsNotNone(mass_storage.get_namespace_data(action='storage-deploy', label='u-boot', key='device')) u_boot_params = device['actions']['boot']['methods']['u-boot'] self.assertEqual(mass_storage.get_namespace_data(action='uboot-retry', label='bootloader_prompt', key='prompt'), u_boot_params['parameters']['bootloader_prompt']) def test_job_parameters(self): """ Test that the job parameters match expected structure """ (rendered, _) = self.factory.create_device('cubie1.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) job = self._check_valid_job(cubie, 'cubietruck-removable.yaml') self._check_job_parameters(cubie, job, 'download') def test_writer_job_parameters(self): """ Test that the job parameters with a writer tool match expected structure """ (rendered, _) = self.factory.create_device('cubie1.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) job = self._check_valid_job(cubie, 'cubietruck-removable-with-writer.yaml') self._check_job_parameters(cubie, job, 'writer') def _check_deployment(self, device, test_file): job_parser = JobParser() job = self._check_valid_job(device, test_file) self.assertIn('usb', 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'], device['parameters']['media']['usb']) self.assertIn('uuid', device['parameters']['media']['usb'][deploy_params['device']]) self.assertIn('device_id', device['parameters']['media']['usb'][deploy_params['device']]) self.assertNotIn('boot_part', device['parameters']['media']['usb'][deploy_params['device']]) deploy_action = [action for action in job.pipeline.actions if action.name == 'storage-deploy'][0] tftp_deploy_action = [action for action in job.pipeline.actions if action.name == 'tftp-deploy'][0] self.assertIsNotNone(deploy_action) test_dir = deploy_action.get_namespace_data(action='test', label='results', key='lava_test_results_dir', parameters=tftp_deploy_action.parameters) self.assertIsNotNone(test_dir) self.assertIn('/lava-', test_dir) self.assertIsInstance(deploy_action, MassStorage) img_params = deploy_action.parameters.get('images', deploy_action.parameters) self.assertIn('image', img_params) dd_action = [action for action in deploy_action.internal_pipeline.actions if action.name == 'dd-image'][0] self.assertEqual( dd_action.boot_params[dd_action.parameters['device']]['uuid'], 'usb-SanDisk_Ultra_20060775320F43006019-0:0') self.assertIsNotNone(dd_action.get_namespace_data(action=dd_action.name, label='u-boot', key='boot_part')) self.assertIsNotNone(dd_action.get_namespace_data(action='uboot-from-media', label='uuid', key='boot_part')) self.assertEqual('0', '%s' % dd_action.get_namespace_data(action=dd_action.name, label='u-boot', key='boot_part')) self.assertIsInstance(dd_action.get_namespace_data(action='uboot-from-media', label='uuid', key='boot_part'), str) self.assertEqual('0:1', dd_action.get_namespace_data(action='uboot-from-media', label='uuid', key='boot_part')) self.assertIsNotNone(dd_action.get_namespace_data( action='uboot-prepare-kernel', label='bootcommand', key='bootcommand')) def test_deployment(self): (rendered, _) = self.factory.create_device('cubie1.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) self._check_deployment(cubie, 'cubietruck-removable.yaml') def test_writer_deployment(self): (rendered, _) = self.factory.create_device('cubie1.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) self._check_deployment(cubie, 'cubietruck-removable-with-writer.yaml') 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 test_mustang_deployment(self): factory = RemovableFactory() job = factory.create_job('sample_jobs/mustang-secondary-media.yaml', '../devices/mustang-media.yaml') job.validate() description_ref = self.pipeline_reference('mustang-media.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) self.assertIn('sata', 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']['sata']) self.assertIn('uuid', job.device['parameters']['media']['sata'][deploy_params['device']]) self.assertIn('device_id', job.device['parameters']['media']['sata'][deploy_params['device']]) self.assertEqual('hd0', job.device['parameters']['media']['sata'][deploy_params['device']]['grub_interface']) grub_deploys = [action for action in job.pipeline.actions if action.name == 'grub-main-action'] self.assertEqual(len(grub_deploys), 2) first_deploy = grub_deploys[0] second_deploy = grub_deploys[1] self.assertEqual('nfsdeploy', first_deploy.parameters['namespace']) self.assertEqual('satadeploy', second_deploy.parameters['namespace']) def test_secondary_media(self): factory = RemovableFactory() job = factory.create_job('sample_jobs/mustang-secondary-media.yaml', '../devices/mustang-media.yaml') job.validate() grub_nfs = [action for action in job.pipeline.actions if action.name == 'grub-main-action' and action.parameters['namespace'] == 'nfsdeploy'][0] media_action = [action for action in grub_nfs.internal_pipeline.actions if action.name == 'bootloader-from-media'][0] self.assertEqual(None, media_action.get_namespace_data(action='download-action', label='file', key='kernel')) self.assertEqual(None, media_action.get_namespace_data(action='compress-ramdisk', label='file', key='ramdisk')) self.assertEqual(None, media_action.get_namespace_data(action='download-action', label='file', key='dtb')) self.assertEqual(None, media_action.get_namespace_data(action=media_action.name, label='file', key='root')) grub_main = [action for action in job.pipeline.actions if action.name == 'grub-main-action' and action.parameters['namespace'] == 'satadeploy'][0] media_action = [action for action in grub_main.internal_pipeline.actions if action.name == 'bootloader-from-media'][0] self.assertIsInstance(media_action, BootloaderSecondaryMedia) self.assertIsNotNone(media_action.get_namespace_data(action='download-action', label='file', key='kernel')) self.assertIsNotNone(media_action.get_namespace_data(action='compress-ramdisk', label='file', key='ramdisk')) self.assertIsNotNone(media_action.get_namespace_data(action='download-action', label='file', key='ramdisk')) self.assertEqual('', media_action.get_namespace_data(action='download-action', label='file', key='dtb')) self.assertIsNotNone(media_action.get_namespace_data(action=media_action.name, label='uuid', key='root')) self.assertIsNotNone(media_action.get_namespace_data(action=media_action.name, label='uuid', key='boot_part')) @unittest.skipIf(infrastructure_error('mkimage'), "u-boot-tools not installed") def test_primary_media(self): """ Test that definitions of secondary media do not block submissions using primary media """ job_parser = JobParser() (rendered, _) = self.factory.create_device('bbb-01.jinja2') bbb = 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, bbb, 4212, None, "") job.logger = DummyLogger() job.validate() self.assertEqual(job.pipeline.errors, []) self.assertIn('usb', bbb['parameters']['media'].keys()) def test_substitutions(self): """ Test substitution of secondary media values into u-boot commands Unlike most u-boot calls, removable knows in advance all the values it needs to substitute into the boot commands for the secondary deployment as these are fixed by the device config and the image details from the job submission. """ job_parser = JobParser() (rendered, _) = self.factory.create_device('cubie1.jinja2') cubie = NewDevice(yaml.safe_load(rendered)) sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs/cubietruck-removable.yaml') with open(sample_job_file) as sample_job_data: job = job_parser.parse(sample_job_data, cubie, 4212, None, "") job.logger = DummyLogger() job.validate() boot_params = [ methods for methods in job.parameters['actions'] if 'boot' in methods.keys()][1]['boot'] self.assertIn('ramdisk', boot_params) self.assertIn('kernel', boot_params) self.assertIn('dtb', boot_params) self.assertIn('root_uuid', boot_params) self.assertIn('boot_part', boot_params) self.assertNotIn('type', boot_params) self.assertGreater(len(job.pipeline.actions), 1) self.assertIsNotNone(job.pipeline.actions[1].internal_pipeline) u_boot_action = [action for action in job.pipeline.actions if action.name == 'uboot-action'][1] overlay = [action for action in u_boot_action.internal_pipeline.actions if action.name == 'bootloader-overlay'][0] self.assertIsNotNone(overlay.get_namespace_data(action='storage-deploy', label='u-boot', key='device')) methods = cubie['actions']['boot']['methods'] self.assertIn('u-boot', methods) self.assertIn('usb', methods['u-boot']) self.assertIn('commands', methods['u-boot']['usb']) commands_list = methods['u-boot']['usb']['commands'] device_id = u_boot_action.get_namespace_data(action='storage-deploy', label='u-boot', key='device') self.assertIsNotNone(device_id) kernel_type = u_boot_action.parameters['kernel_type'] bootcommand = map_kernel_uboot(kernel_type, device_params=cubie.get('parameters')) substitutions = { '{BOOTX}': "%s %s %s %s" % ( bootcommand, cubie['parameters'][bootcommand]['kernel'], cubie['parameters'][bootcommand]['ramdisk'], cubie['parameters'][bootcommand]['dtb'],), '{RAMDISK}': boot_params['ramdisk'], '{KERNEL}': boot_params['kernel'], '{DTB}': boot_params['dtb'], '{ROOT}': boot_params['root_uuid'], '{ROOT_PART}': "%s:%s" % ( cubie['parameters']['media']['usb'][device_id]['device_id'], u_boot_action.parameters['boot_part'] ) } self.assertEqual('bootz 0x42000000 0x43300000 0x43000000', substitutions['{BOOTX}']) self.assertEqual('/boot/initrd.img-3.16.0-4-armmp-lpae.u-boot', substitutions['{RAMDISK}']) commands = substitute(commands_list, substitutions) print(commands) self.assertEqual( commands, [ 'usb start', 'setenv autoload no', 'load usb 0:0:1 {KERNEL_ADDR} /boot/vmlinuz-3.16.0-4-armmp-lpae', 'load usb 0:0:1 {RAMDISK_ADDR} /boot/initrd.img-3.16.0-4-armmp-lpae.u-boot', 'setenv initrd_size ${filesize}', 'load usb 0:0:1 {DTB_ADDR} /boot/dtb-3.16.0-4-armmp-lpae', 'console=ttyS0,115200n8 root=UUID=159d17cc-697c-4125-95a0-a3775e1deabe ip=dhcp', 'bootz 0x42000000 0x43300000 0x43000000' ] )
class TestChecksum(StdoutTestCase): def setUp(self): super().setUp() self.factory = Factory() self.job = self.factory.create_kvm_job('sample_jobs/kvm-inline.yaml') def test_download_checksum_match_success(self): self.assertEqual(len(self.job.pipeline.describe()), 4) deployimagesaction = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] downloadretryaction = [ action for action in deployimagesaction.internal_pipeline.actions if action.name == 'download-retry' ][0] httpdownloadaction = [ action for action in downloadretryaction.internal_pipeline.actions if action.name == 'http-download' ][0] # Just a small image httpdownloadaction.url = 'http://images.validation.linaro.org/unit-tests/rootfs.gz' httpdownloadaction.parameters.update({ 'images': { 'rootfs': { 'url': httpdownloadaction.url, 'md5sum': '6ea432ac3c23210c816551782346ed1c', 'sha256sum': '1a76b17701b9fdf6346b88eb49b0143a9c6912701b742a6e5826d6856edccd21' } } }) httpdownloadaction.validate() httpdownloadaction.run(None, None) def test_download_checksum_match_fail(self): self.assertEqual(len(self.job.pipeline.describe()), 4) deployimagesaction = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] downloadretryaction = [ action for action in deployimagesaction.internal_pipeline.actions if action.name == 'download-retry' ][0] httpdownloadaction = [ action for action in downloadretryaction.internal_pipeline.actions if action.name == 'http-download' ][0] # Just a small image httpdownloadaction.url = 'http://images.validation.linaro.org/unit-tests/rootfs.gz' httpdownloadaction.parameters.update({ 'images': { 'rootfs': { 'url': httpdownloadaction.url, 'md5sum': 'df1bd1598699e7a89d2e111111111111', 'sha256sum': '92d6ff900d0c3656ab3f214ce6efd708f898fc5e259111111111111111111111' } } }) httpdownloadaction.validate() self.assertRaises(JobError, httpdownloadaction.run, None, None) def test_download_no_images_no_checksum(self): self.assertEqual(len(self.job.pipeline.describe()), 4) deployimagesaction = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] downloadretryaction = [ action for action in deployimagesaction.internal_pipeline.actions if action.name == 'download-retry' ][0] httpdownloadaction = [ action for action in downloadretryaction.internal_pipeline.actions if action.name == 'http-download' ][0] # Just a small image httpdownloadaction.url = 'http://images.validation.linaro.org/unit-tests/rootfs.gz' del httpdownloadaction.parameters['images'] httpdownloadaction.parameters.update( {'rootfs': { 'url': httpdownloadaction.url }}) httpdownloadaction.validate() httpdownloadaction.run(None, None) def test_download_no_images_match_success(self): self.assertEqual(len(self.job.pipeline.describe()), 4) deployimagesaction = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] downloadretryaction = [ action for action in deployimagesaction.internal_pipeline.actions if action.name == 'download-retry' ][0] httpdownloadaction = [ action for action in downloadretryaction.internal_pipeline.actions if action.name == 'http-download' ][0] # Just a small image httpdownloadaction.url = 'http://images.validation.linaro.org/unit-tests/rootfs.gz' del httpdownloadaction.parameters['images'] httpdownloadaction.parameters.update({ 'rootfs': { 'url': httpdownloadaction.url, 'md5sum': '6ea432ac3c23210c816551782346ed1c', 'sha256sum': '1a76b17701b9fdf6346b88eb49b0143a9c6912701b742a6e5826d6856edccd21' } }) httpdownloadaction.validate() httpdownloadaction.run(None, None) def test_download_no_images_match_fail(self): self.assertEqual(len(self.job.pipeline.describe()), 4) deployimagesaction = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] downloadretryaction = [ action for action in deployimagesaction.internal_pipeline.actions if action.name == 'download-retry' ][0] httpdownloadaction = [ action for action in downloadretryaction.internal_pipeline.actions if action.name == 'http-download' ][0] # Just a small image httpdownloadaction.url = 'http://images.validation.linaro.org/unit-tests/rootfs.gz' del httpdownloadaction.parameters['images'] httpdownloadaction.parameters.update({ 'rootfs': { 'url': httpdownloadaction.url, 'md5sum': '6ea432ac3c232122222221782346ed1c', 'sha256sum': '1a76b17701b9fdf63444444444444444446912701b742a6e5826d6856edccd21' } }) httpdownloadaction.validate() self.assertRaises(JobError, httpdownloadaction.run, None, None) def test_no_test_action_validate(self): self.assertEqual(len(self.job.pipeline.describe()), 4) del self.job.pipeline.actions[2] try: self.job.pipeline.validate_actions() except JobError as exc: self.fail(exc) except InfrastructureError as exc: check_missing_path(self, exc, 'qemu-system-x86_64') for action in self.job.pipeline.actions: self.assertEqual([], action.errors) def test_uboot_checksum(self): (rendered, _) = self.factory.create_device('bbb-01.jinja2') device = NewDevice(yaml.safe_load(rendered)) bbb_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/bbb-ramdisk-nfs.yaml') with open(bbb_yaml) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, device, 4212, None, "") deploy = [ action for action in job.pipeline.actions if action.name == 'tftp-deploy' ][0] download = [ action for action in deploy.internal_pipeline.actions if action.name == 'download-retry' ][0] helper = [ action for action in download.internal_pipeline.actions if action.name == 'file-download' ][0] remote = helper.parameters[helper.key] md5sum = remote.get('md5sum') self.assertIsNone(md5sum) sha256sum = remote.get('sha256sum') self.assertIsNotNone(sha256sum)
class TestKVMInlineTestDeploy(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.factory = Factory() self.job = self.factory.create_kvm_job('sample_jobs/kvm-inline.yaml') def test_deploy_job(self): self.assertEqual(self.job.pipeline.job, self.job) for action in self.job.pipeline.actions: if isinstance(action, DeployAction): self.assertEqual(action.job, self.job) def test_validate(self): try: self.job.pipeline.validate_actions() except JobError as exc: self.fail(exc) except InfrastructureError: pass for action in self.job.pipeline.actions: self.assertEqual([], action.errors) def test_extra_options(self): (rendered, _) = self.factory.create_device('kvm01.jinja2') device = NewDevice(yaml.safe_load(rendered)) kvm_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/kvm-inline.yaml') with open(kvm_yaml) as sample_job_data: job_data = yaml.safe_load(sample_job_data) device['actions']['boot']['methods']['qemu']['parameters'][ 'extra'] = yaml.safe_load(""" - -smp - 1 - -global - virtio-blk-device.scsi=off - -device virtio-scsi-device,id=scsi - --append "console=ttyAMA0 root=/dev/vda rw" """) self.assertIsInstance( device['actions']['boot']['methods']['qemu']['parameters']['extra'] [1], int) parser = JobParser() job = parser.parse(yaml.dump(job_data), device, 4212, None, "") job.logger = DummyLogger() job.validate() boot_image = [ action for action in job.pipeline.actions if action.name == 'boot-image-retry' ][0] boot_qemu = [ action for action in boot_image.internal_pipeline.actions if action.name == 'boot-qemu-image' ][0] qemu = [ action for action in boot_qemu.internal_pipeline.actions if action.name == 'execute-qemu' ][0] self.assertIsInstance(qemu.sub_command, list) [self.assertIsInstance(item, str) for item in qemu.sub_command] # pylint: disable=expression-not-assigned self.assertIn('virtio-blk-device.scsi=off', qemu.sub_command) self.assertIn('1', qemu.sub_command) self.assertNotIn(1, qemu.sub_command) def test_pipeline(self): description_ref = self.pipeline_reference('kvm-inline.yaml') self.assertEqual(description_ref, self.job.pipeline.describe(False)) self.assertEqual(len(self.job.pipeline.describe()), 4) inline_repo = None for action in self.job.pipeline.actions: if isinstance(action, DeployAction): self.assertIsNotNone(action.internal_pipeline.actions[1]) overlay = action.pipeline.actions[1] self.assertIsNotNone(overlay.internal_pipeline.actions[1]) testdef = overlay.internal_pipeline.actions[2] self.assertIsNotNone(testdef.internal_pipeline.actions[0]) inline_repo = testdef.internal_pipeline.actions[0] break # Test the InlineRepoAction directly self.assertIsNotNone(inline_repo) location = mkdtemp() # other actions have not been run, so fake up inline_repo.set_namespace_data(action='test', label='results', key='lava_test_results_dir', value=location) inline_repo.set_namespace_data(action='test', label='test-definition', key='overlay_dir', value=location) inline_repo.set_namespace_data(action='test', label='shared', key='location', value=location) inline_repo.set_namespace_data(action='test', label='test-definiton', key='overlay_dir', value=location) inline_repo.run(None, None) yaml_file = os.path.join( location, '0/tests/0_smoke-tests-inline/inline/smoke-tests-basic.yaml') self.assertTrue(os.path.exists(yaml_file)) with open(yaml_file, 'r') as f_in: testdef = yaml.safe_load(f_in) expected_testdef = { 'metadata': { 'description': 'Basic system test command for Linaro Ubuntu images', 'devices': [ 'panda', 'panda-es', 'arndale', 'vexpress-a9', 'vexpress-tc2' ], 'format': 'Lava-Test Test Definition 1.0', 'name': 'smoke-tests-basic', 'os': ['ubuntu'], 'scope': ['functional'], 'yaml_line': 39 }, 'run': { 'steps': [ 'lava-test-case linux-INLINE-pwd --shell pwd', 'lava-test-case linux-INLINE-uname --shell uname -a', 'lava-test-case linux-INLINE-vmstat --shell vmstat', 'lava-test-case linux-INLINE-ifconfig --shell ifconfig -a', 'lava-test-case linux-INLINE-lscpu --shell lscpu', 'lava-test-case linux-INLINE-lsusb --shell lsusb', 'lava-test-case linux-INLINE-lsb_release --shell lsb_release -a' ], 'yaml_line': 53 }, 'yaml_line': 38 } self.assertEqual(set(testdef), set(expected_testdef))
class TestDefinitionHandlers(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.factory = Factory() self.job = self.factory.create_job('qemu01.jinja2', 'sample_jobs/kvm.yaml') with open( os.path.join(os.path.dirname(__file__), 'testdefs', 'params.yaml'), 'r') as params: self.testdef = yaml.safe_load(params) def test_testdef(self): testdef = overlay = None for action in self.job.pipeline.actions: self.assertIsNotNone(action.name) if isinstance(action, DeployAction): overlay = action.pipeline.actions[2] testdef = overlay.internal_pipeline.actions[2] self.assertEqual(len(overlay.internal_pipeline.actions), 5) self.assertIsInstance(testdef, TestDefinitionAction) testdef.validate() self.assertEqual(testdef.run_levels, { 'smoke-tests': 0, 'singlenode-advanced': 0 }) if not testdef.valid: # python3 compatible print(testdef.errors) # pylint: disable=superfluous-parens self.assertTrue(testdef.valid) for repo_action in testdef.internal_pipeline.actions: if isinstance(repo_action, GitRepoAction): self.assertEqual( repo_action.default_pattern, "(?P<test_case_id>.*-*)\\s+:\\s+(?P<result>(PASS|pass|FAIL|fail|SKIP|skip|UNKNOWN|unknown))" ) self.assertEqual( repo_action.default_fixupdict, { 'PASS': '******', 'FAIL': 'fail', 'SKIP': 'skip', 'UNKNOWN': 'unknown' }) self.assertTrue(hasattr(repo_action, 'accepts')) self.assertTrue(hasattr(repo_action, 'priority')) elif isinstance(repo_action, TestOverlayAction): self.assertTrue(hasattr(repo_action, 'test_uuid')) self.assertFalse(hasattr(repo_action, 'accepts')) self.assertFalse(hasattr(repo_action, 'priority')) else: self.fail( "%s does not match GitRepoAction or TestOverlayAction" % type(repo_action)) repo_action.validate() # FIXME # if hasattr(repo_action, 'uuid'): # repo_action.data['test'] = {repo_action.uuid: {}} # repo_action.store_testdef(self.testdef, 'git', 'abcdef') # self.assertEqual( # repo_action.data['test'][repo_action.uuid]['testdef_pattern'], # self.testdef['parse']) self.assertTrue(repo_action.valid) # FIXME: needs deployment_data to be visible during validation # self.assertNotEqual(repo_action.runner, None) self.assertIsNotNone( testdef.parameters['deployment_data']['lava_test_results_dir']) def test_name(self): deploy = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == 'lava-overlay' ][0] testdef = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] testdef.validate() self.assertEqual([], testdef.errors) (rendered, _) = self.factory.create_device('kvm01.jinja2') device = yaml.load(rendered) kvm_yaml = os.path.join(os.path.dirname(__file__), 'sample_jobs/kvm.yaml') parser = JobParser() with open(kvm_yaml, 'r') as sample_job_data: content = yaml.load(sample_job_data) data = [ block['test'] for block in content['actions'] if 'test' in block ][0] definitions = [ block for block in data['definitions'] if 'path' in block ][0] definitions['name'] = 'smoke tests' job = parser.parse(yaml.dump(content), device, 4212, None, "") deploy = [ action for action in job.pipeline.actions if action.name == 'deployimages' ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == 'lava-overlay' ][0] testdef = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] testdef.validate() self.assertNotEqual([], testdef.errors) self.assertIn( 'Invalid characters found in test definition name: smoke tests', job.pipeline.errors) def test_vcs_parameters(self): deploy = [ action for action in self.job.pipeline.actions if action.name == 'deployimages' ][0] overlay = [ action for action in deploy.internal_pipeline.actions if action.name == 'lava-overlay' ][0] testdef = [ action for action in overlay.internal_pipeline.actions if action.name == 'test-definition' ][0] git_repos = [ action for action in testdef.internal_pipeline.actions if action.name == 'git-repo-action' ] for git_repo in git_repos: if git_repo.parameters[ 'repository'] == 'http://git.linaro.org/lava-team/lava-functional-tests.git': self.assertIn('revision', git_repo.parameters) self.assertIn('branch', git_repo.parameters) else: self.assertNotIn('revision', git_repo.parameters) self.assertNotIn('branch', git_repo.parameters) def test_overlay(self): script_list = [ 'lava-add-keys', 'lava-add-sources', 'lava-background-process-start', 'lava-background-process-stop', 'lava-echo-ipv4', 'lava-install-packages', 'lava-installed-packages', 'lava-os-build', 'lava-probe-channel', 'lava-probe-ip', 'lava-target-ip', 'lava-target-mac', 'lava-target-storage', 'lava-test-case', 'lava-test-event', 'lava-test-feedback', 'lava-test-reference', 'lava-test-runner', 'lava-test-set', 'lava-test-shell', 'lava-test-raise', 'lava-common-functions' ] overlay = None for action in self.job.pipeline.actions: if isinstance(action, DeployAction): for child in action.pipeline.actions: if isinstance(child, OverlayAction): overlay = child break self.assertIsInstance(overlay, OverlayAction) # Generic scripts scripts_to_copy = glob.glob( os.path.join(overlay.lava_test_dir, 'lava-*')) distro_support_dir = '%s/distro/%s' % (overlay.lava_test_dir, 'debian') for script in glob.glob(os.path.join(distro_support_dir, 'lava-*')): scripts_to_copy.append(script) check_list = list( set([os.path.basename(scr) for scr in scripts_to_copy])) self.assertCountEqual(check_list, script_list) self.assertEqual( overlay.xmod, stat.S_IRWXU | stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
class TestVland(StdoutTestCase): # pylint: disable=too-many-public-methods def setUp(self): super().setUp() self.filename = os.path.join(os.path.dirname(__file__), 'sample_jobs/bbb-group-vland-alpha.yaml') self.beta_filename = os.path.join( os.path.dirname(__file__), 'sample_jobs/bbb-group-vland-beta.yaml') self.factory = Factory() (rendered, _) = self.factory.create_device('bbb-01.jinja2') self.device = NewDevice(yaml.safe_load(rendered)) self.job_id = "100" def test_file_structure(self): with open(self.filename) as yaml_data: alpha_data = yaml.safe_load(yaml_data) self.assertIn('protocols', alpha_data) self.assertTrue(VlandProtocol.accepts(alpha_data)) level_tuple = Protocol.select_all(alpha_data) self.assertEqual(len(level_tuple), 2) self.assertEqual(VlandProtocol, [ item[0] for item in sorted(level_tuple, key=lambda data: data[1]) ][1]) vprotocol = VlandProtocol(alpha_data, self.job_id) self.assertIn( 'arbit', vprotocol.base_group, ) self.assertNotIn( 'group', vprotocol.base_group, ) vprotocol.set_up() self.assertIn('port', vprotocol.settings) self.assertIn('poll_delay', vprotocol.settings) self.assertIn('vland_hostname', vprotocol.settings) self.assertEqual( vprotocol.base_message, { "port": vprotocol.settings['port'], "poll_delay": vprotocol.settings["poll_delay"], "host": vprotocol.settings['vland_hostname'], "client_name": socket.gethostname(), }) for name in vprotocol.names: vlan = vprotocol.params[name] self.assertIn('tags', vlan) def test_device(self): self.assertIsNotNone(self.device) self.assertIn('eth0', self.device['parameters']['interfaces']) self.assertIn('eth1', self.device['parameters']['interfaces']) self.assertIn('sysfs', self.device['parameters']['interfaces']['eth0']) self.assertIn('mac', self.device['parameters']['interfaces']['eth0']) self.assertIn('switch', self.device['parameters']['interfaces']['eth0']) self.assertIn('port', self.device['parameters']['interfaces']['eth0']) self.assertIn('tags', self.device['parameters']['interfaces']['eth0']) self.assertIn('sysfs', self.device['parameters']['interfaces']['eth1']) self.assertIn('mac', self.device['parameters']['interfaces']['eth1']) self.assertIn('switch', self.device['parameters']['interfaces']['eth1']) self.assertIn('port', self.device['parameters']['interfaces']['eth1']) self.assertIn('tags', self.device['parameters']['interfaces']['eth1']) self.assertIsInstance( self.device['parameters']['interfaces']['eth1']['tags'], list) self.assertIsNone( self.device['parameters']['interfaces']['eth0']['tags']) csv_list = [] for interface in self.device['parameters']['interfaces']: csv_list.extend([ self.device['parameters']['interfaces'][interface]['sysfs'], self.device['parameters']['interfaces'][interface]['mac'], interface ]) self.assertEqual( set(csv_list), { '/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/eth1', '00:24:d7:9b:c0:8c', 'eth1', '/sys/devices/pci0000:00/0000:00:19.0/net/eth0', 'f0:de:f1:46:8c:21', 'eth0' }) tag_list = [] for interface in self.device['parameters']['interfaces']: if interface == 'eth0': continue for tag in self.device['parameters']['interfaces'][interface][ 'tags']: tag_list.extend([interface, tag]) self.assertEqual(set(tag_list), {'RJ45', '100M', 'eth1', '10M'}) def test_configure(self): with open(self.filename) as yaml_data: alpha_data = yaml.safe_load(yaml_data) self.assertIn('protocols', alpha_data) self.assertTrue(VlandProtocol.accepts(alpha_data)) vprotocol = VlandProtocol(alpha_data, self.job_id) vprotocol.set_up() with open(self.filename) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, self.device, 4212, None, "") ret = vprotocol.configure(self.device, job) if not ret: print(vprotocol.errors) self.assertTrue(ret) nodes = {} for name in vprotocol.names: vlan = vprotocol.params[name] # self.assertNotIn('tags', vlan) uid = ' '.join([vlan['switch'], str(vlan['port'])]) nodes[uid] = name self.assertEqual(len(nodes.keys()), len(vprotocol.names)) self.assertIn('vlan_one', vprotocol.names) self.assertNotIn('vlan_two', vprotocol.names) self.assertIn('switch', vprotocol.params['vlan_one']) self.assertIn('port', vprotocol.params['vlan_one']) self.assertIsNotNone(vprotocol.multinode_protocol) (rendered, _) = self.factory.create_device('bbb-01.jinja2') bbb2 = NewDevice(yaml.safe_load(rendered)) bbb2['parameters']['interfaces']['eth0']['switch'] = '192.168.0.2' bbb2['parameters']['interfaces']['eth0']['port'] = '6' bbb2['parameters']['interfaces']['eth1']['switch'] = '192.168.0.2' bbb2['parameters']['interfaces']['eth1']['port'] = '4' self.assertEqual( vprotocol.params, { 'vlan_one': { 'switch': '192.168.0.2', 'iface': 'eth1', 'port': 7, 'tags': ['100M', 'RJ45', '10M'] } }) # already configured the vland protocol in the same job self.assertTrue(vprotocol.configure(bbb2, job)) self.assertEqual( vprotocol.params, { 'vlan_one': { 'switch': '192.168.0.2', 'iface': 'eth1', 'port': 7, 'tags': ['100M', 'RJ45', '10M'] } }) self.assertTrue(vprotocol.valid) self.assertEqual(vprotocol.names, {'vlan_one': '4212vlanone'}) def test_job(self): with open(self.filename) as yaml_data: alpha_data = yaml.safe_load(yaml_data) self.assertIn('protocols', alpha_data) self.assertIn(VlandProtocol.name, alpha_data['protocols']) with open(self.filename) as sample_job_data: parser = JobParser() job = parser.parse(sample_job_data, self.device, 4212, None, "") job.logger = DummyLogger() description_ref = self.pipeline_reference('bbb-group-vland-alpha.yaml', job=job) self.assertEqual(description_ref, job.pipeline.describe(False)) job.validate() self.assertNotEqual([], [ protocol.name for protocol in job.protocols if protocol.name == MultinodeProtocol.name ]) ret = { "message": { "kvm01": { "vlan_name": "name", "vlan_tag": 6 } }, "response": "ack" } self.assertEqual(('name', 6), ( ret['message']['kvm01']['vlan_name'], ret['message']['kvm01']['vlan_tag'], )) self.assertIn('protocols', job.parameters) self.assertIn(VlandProtocol.name, job.parameters['protocols']) self.assertIn(MultinodeProtocol.name, job.parameters['protocols']) 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]: if vlan_name == 'yaml_line': continue self.assertIn(vlan_name, vprotocol.params) self.assertIn('switch', vprotocol.params[vlan_name]) self.assertIn('port', vprotocol.params[vlan_name]) self.assertIn('iface', vprotocol.params[vlan_name]) params = job.parameters['protocols'][vprotocol.name] names = [] for key, _ in params.items(): if key == 'yaml_line': continue names.append(",".join([key, vprotocol.params[key]['iface']])) # this device only has one interface with interface tags self.assertEqual(names, ['vlan_one,eth1']) def test_vland_overlay(self): 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.dump(alpha_data), self.device, 4212, None, "") job.logger = DummyLogger() job.validate() tftp_deploy = [ action for action in job.pipeline.actions if action.name == 'tftp-deploy' ][0] prepare = [ action for action in tftp_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 = [ action for action in overlay.internal_pipeline.actions if action.name == 'lava-vland-overlay' ][0] self.assertTrue(os.path.exists(vland.lava_vland_test_dir)) vland_files = os.listdir(vland.lava_vland_test_dir) self.assertIn('lava-vland-names', vland_files) self.assertIn('lava-vland-tags', vland_files) self.assertIn('lava-vland-self', vland_files) def test_job_no_tags(self): 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.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]: if vlan_name == 'yaml_line': continue self.assertIn(vlan_name, vprotocol.params) self.assertIn('switch', vprotocol.params[vlan_name]) self.assertIn('port', vprotocol.params[vlan_name]) def test_job_bad_tags(self): 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': ['spurious'] } # replaced tags from original job to simulate job where an unsupported tag is specified self.assertEqual(alpha_data['protocols'][VlandProtocol.name], {'vlan_one': { 'tags': ['spurious'] }}) parser = JobParser() job = parser.parse(yaml.dump(alpha_data), self.device, 4212, None, "") job.logger = DummyLogger() self.assertRaises(JobError, job.validate) def test_primary_interface(self): 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.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() # pylint: disable=protected-access def demo(self): with open(self.filename) as yaml_data: alpha_data = yaml.safe_load(yaml_data) vprotocol = VlandProtocol(alpha_data, 422) vprotocol.settings = vprotocol.read_settings() self.assertIn('port', vprotocol.settings) self.assertIn('poll_delay', vprotocol.settings) self.assertIn('vland_hostname', vprotocol.settings) vprotocol.base_message = { "port": vprotocol.settings['port'], "poll_delay": vprotocol.settings["poll_delay"], "host": vprotocol.settings['vland_hostname'], "client_name": socket.gethostname(), } count = 0 print("\nTesting vland live using connections.") for friendly_name in vprotocol.parameters['protocols'][vprotocol.name]: print("Processing VLAN: %s" % friendly_name) vprotocol.names[ friendly_name] = vprotocol.base_group + '%02d' % count count += 1 vprotocol.vlans[friendly_name], tag = vprotocol._create_vlan( friendly_name) print("[%s] Created vlan with id %s" % (friendly_name, vprotocol.vlans[friendly_name])) print("[%s] tag: %s" % (friendly_name, tag)) for hostname in vprotocol.parameters['protocols'][ vprotocol.name][friendly_name]: params = vprotocol.parameters['protocols'][ vprotocol.name][friendly_name][hostname] print("[%s] to use switch %s and port %s" % (friendly_name, params['switch'], params['port'])) self.assertIn('switch', params) self.assertIn('port', params) self.assertIsNotNone(params['switch']) self.assertIsNotNone(params['port']) switch_id = vprotocol._lookup_switch_id(params['switch']) self.assertIsNotNone(switch_id) print("[%s] Using switch ID %s" % (friendly_name, switch_id)) port_id = vprotocol._lookup_port_id(switch_id, params['port']) print("%s Looked up port ID %s for %s" % (friendly_name, port_id, params['port'])) vprotocol._set_port_onto_vlan(vprotocol.vlans[friendly_name], port_id) vprotocol.ports.append(port_id) print("Finalising - tearing down vlans") vprotocol.finalise_protocol()