def testStopAfterStartingDutKvmFails(self): """Calling .Stop after a failed .Start undoes partial .Start.""" self.testSuccessfulCreateWithDutDir() # Allow .Start to run, without expectation checking (done in other tests) self._mock_try_create_bridge_device.return_value = (937, self.bridge_name) self._mock_create_tap_device.side_effect = iter( [self.moblab_tap_dev, self.dut_tap_dev]) self._mock_start_kvm.side_effect = iter( [self.moblab_kvm_pid_path, _TestException]) vmsetup = moblab_vm.MoblabVm(self.workspace) with self.assertRaises(_TestException): vmsetup.Start() # Verify .Stop releases global resources. vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Stop() self.assertEqual(self._mock_stop_kvm.call_args_list, [mock.call(self.moblab_kvm_pid_path)]) self.assertEqual( self._mock_remove_tap_device.call_args_list, [mock.call(self.dut_tap_dev), mock.call(self.moblab_tap_dev)]) self.assertEqual(self._mock_remove_network_bridge.call_args_list, [mock.call(self.bridge_name)]) # Verify that final state is persisted across instance discards. vmsetup = moblab_vm.MoblabVm(self.workspace) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def testStopAfterStartUndoesEverythingInStackWithDut(self): """.Stop undoes what .Start did in reverse order.""" self.testSuccessfulCreateWithDutDir() # Allow .Start to run, without expectation checking (done in other tests) self._mock_try_create_bridge_device.return_value = (937, self.bridge_name) self._mock_create_tap_device.side_effect = iter( [self.moblab_tap_dev, self.dut_tap_dev]) self._mock_start_kvm.side_effect = iter( [self.moblab_kvm_pid_path, self.dut_kvm_pid_path]) vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Start() # Verify .Stop releases global resources. vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Stop() self.assertEqual(self._mock_stop_kvm.call_args_list, [ mock.call(self.dut_kvm_pid_path), mock.call(self.moblab_kvm_pid_path) ]) self.assertEqual( self._mock_remove_tap_device.call_args_list, [mock.call(self.dut_tap_dev), mock.call(self.moblab_tap_dev)]) self.assertEqual(self._mock_remove_network_bridge.call_args_list, [mock.call(self.bridge_name)]) # Verify that final state is persisted across instance discards. vmsetup = moblab_vm.MoblabVm(self.workspace) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def testMountMoblabDiskContextAfterStartRaises(self): """Cannot mount a disk if the workspace isn't even initialized.""" self.testSuccessfulStartAfterCreateWithoutDut() vmsetup = moblab_vm.MoblabVm(self.workspace) with self.assertRaises(moblab_vm.MoblabVmError): with vmsetup.MountedMoblabDiskContext(): pass
def Run(self): """The main handler of this CLI.""" self.options.Freeze() cmd = self.options.moblabvm_command if cmd == 'create': # Allow the workspace to not exist. This makes the CLI uniform across the # 'cros moblabvm' commands, without burdening the user with a mkdir before # 'create' osutils.SafeMakedirsNonRoot(self.options.workspace) if not os.path.isdir(self.options.workspace): cros_build_lib.Die('Workspace directory %s does not exist!', self.options.workspace) vm = moblab_vm.MoblabVm(self.options.workspace) if cmd == 'create': if self.options.clean: vm.Destroy() vm.Create(self.options.moblab_image_dir, self.options.dut_image_dir, create_vm_images=not self.options.source_vm_images) elif cmd == 'start': if self.options.restart: vm.Stop() vm.Start() _Describe(vm) elif cmd == 'stop': vm.Stop() elif cmd == 'destroy': vm.Destroy() elif cmd == 'describe': _Describe(vm) else: assert False, 'Unrecognized command %s!' % cmd
def setUp(self): self.builder = 'moblab-generic-vm/R12-3.4.5-67-890' self.image_dir = self.MockDirectory('files/image') self.payload_dir = self.MockDirectory('files/payload') self.results_dir = self.MockDirectory('results') self.vms = moblab_vm.MoblabVm(self.tempdir) self.chroot = chroot_lib.Chroot(path=self.tempdir)
def testRunVmsContextNoFailure(self): """Calls .Start and .Stop in a basic use case.""" vmsetup = moblab_vm.MoblabVm(self.workspace) start = self.PatchObject(moblab_vm.MoblabVm, 'Start') destroy = self.PatchObject(moblab_vm.MoblabVm, 'Destroy') with vmsetup.RunVmsContext(): pass self.assertEqual(start.call_count, 1) self.assertEqual(destroy.call_count, 1)
def testRunVmsContextWithFailure(self): """Calls .Start and .Stop when exception is raised within context.""" vmsetup = moblab_vm.MoblabVm(self.workspace) start = self.PatchObject(moblab_vm.MoblabVm, 'Start') destroy = self.PatchObject(moblab_vm.MoblabVm, 'Destroy') try: with vmsetup.RunVmsContext(): raise ValueError('uh oh!') except ValueError: self.assertEqual(start.call_count, 1) self.assertEqual(destroy.call_count, 1)
def _testSuccessfulStartAfterCreate(self, with_dut): """A successful call to .Start, with or without a dut attached. This helper methods lets us 'parameterize' a longish test. Only change expectations based on the arguments. DO NOT change the interactions with MolabVm. """ self._mock_try_create_bridge_device.return_value = (self._PORT, self.bridge_name) self._mock_create_tap_device.side_effect = iter([self.moblab_tap_dev, self.dut_tap_dev]) # Create a new moblabvm instance. MoblabVm persists everything to disk an # must work seamlessly across instance discards. vmsetup = moblab_vm.MoblabVm(self.workspace, chroot_dir=self.chroot) vmsetup.Start() self.assertTrue(vmsetup.initialized) self.assertTrue(vmsetup.running) self.assertEqual(vmsetup.dut_running, with_dut) self.assertEqual(self._mock_try_create_bridge_device.call_count, 1) self.assertEqual(self._mock_create_tap_device.call_count, 2) # Different suffixes are used for tap devices. self.assertNotEqual( self._mock_create_tap_device.call_args_list[0][0][0], self._mock_create_tap_device.call_args_list[1][0][0], ) self.assertEqual( self._mock_connect_device_to_bridge.call_args_list, [ mock.call('moblabtap', self.bridge_name), mock.call('duttap', self.bridge_name), ]) vm_calls = [mock.call( self.moblab_image_path, self._PORT + 2, self._PORT + 6, self.moblab_tap_dev, mock.ANY, is_moblab=True, disk_path=self.moblab_disk_path, chroot_path=self.chroot)] if with_dut: vm_calls.append(mock.call( self.dut_image_path, self._PORT + 6, self._PORT + 7, self.dut_tap_dev, mock.ANY, is_moblab=False, chroot_path=self.chroot)) self.assertEqual(self._mock_start_vm.call_args_list, vm_calls) if with_dut: # Different SSH ports are used for the two VMs self.assertNotEqual( self._mock_start_vm.call_args_list[0][0][1], self._mock_start_vm.call_args_list[1][0][1], ) # Different MAC addresses are used for secondary networks of two VMs. self.assertNotEqual( self._mock_start_vm.call_args_list[0][0][3], self._mock_start_vm.call_args_list[1][0][3], )
def testSuccessfulCreateNoCreateVm(self): """A successful call to .Create w/o create_vm_images.""" self._mock_create_moblab_disk.return_value = self.moblab_disk_path osutils.SafeMakedirsNonRoot(self.moblab_from_path) osutils.WriteFile( os.path.join(self.moblab_from_path, 'chromiumos_qemu_image.bin'), 'fake_image') vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Create(self.moblab_from_path, create_vm_images=False) self.assertEqual(self._mock_create_vm_image.call_count, 0) self._mock_create_moblab_disk.assert_called_once_with( self.moblab_workdir_path) self.assertTrue(vmsetup.initialized) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def CreateMoblabVm(workspace_dir, chroot_dir, image_dir): """Create the moblab VMs. Assumes that image_dir is in exactly the state it was after building a test image and then converting it to a VM image. Args: workspace_dir (str): Workspace for the moblab VM. chroot_dir (str): Directory containing the chroot for the moblab VM. image_dir (str): Directory containing the VM image. Returns: MoblabVm: The resulting VM. """ vms = moblab_vm.MoblabVm(workspace_dir, chroot_dir=chroot_dir) vms.Create(image_dir, dut_image_dir=image_dir, create_vm_images=False) return vms
def testSuccessfulCreateNoDutDir(self): """A successful call to .Create not using a DUT image.""" self._mock_create_vm_image.return_value = os.path.join( self.moblab_workdir_path, 'chromiumos_qemu_image.bin') self._mock_create_moblab_disk.return_value = self.moblab_disk_path vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Create(self.moblab_from_path) self._mock_create_vm_image.assert_called_once_with( self.moblab_from_path, self.moblab_workdir_path) self._mock_create_moblab_disk.assert_called_once_with( self.moblab_workdir_path) self.assertExists(self.moblab_workdir_path) self.assertNotExists(self.dut_workdir_path) self.assertTrue(vmsetup.initialized) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def _PerformStage(self, workdir, results_dir): """Actually performs this stage. Args: workdir: The workspace directory to use for all temporary files. results_dir: The directory to use to drop test results into. """ dut_target_image = self._SubDutTargetImage() osutils.SafeMakedirsNonRoot(self._Workspace(workdir)) vms = moblab_vm.MoblabVm(self._Workspace(workdir)) try: r = ' reached %s test run timeout.' % self with timeout_util.Timeout(self._PERFORM_TIMEOUT_S, reason_message=r): start_time = datetime.datetime.now() vms.Create(self.GetImageDirSymlink(), self.GetImageDirSymlink()) payload_dir = self._GenerateTestArtifactsInMoblabDisk(vms) vms.Start() elapsed = (datetime.datetime.now() - start_time).total_seconds() RunMoblabTests( moblab_board=self._current_board, moblab_ip=vms.moblab_ssh_port, dut_target_image=dut_target_image, results_dir=results_dir, local_image_cache=payload_dir, timeout_m=(self._PERFORM_TIMEOUT_S - elapsed) // 60, ) vms.Stop() ValidateMoblabTestSuccess(results_dir) except: # Ignore errors while arhiving images, but re-raise the original error. try: vms.Stop() self._ArchiveMoblabVMWorkspace(self._Workspace(workdir)) except Exception as e: logging.error( 'Failed to archive VM images after test failure: %s', e) raise finally: vms.Destroy()
def testSuccessfulCreateWithDutDir(self): """A successful call to .Create using a DUT image.""" self._mock_create_vm_image.side_effect = iter( [self.moblab_image_path, self.dut_image_path]) self._mock_create_moblab_disk.return_value = os.path.join( self.moblab_workdir_path, 'disk') vmsetup = moblab_vm.MoblabVm(self.workspace) vmsetup.Create(self.moblab_from_path, self.dut_from_path) self.assertEqual( self._mock_create_vm_image.call_args_list, [ mock.call(self.moblab_from_path, self.moblab_workdir_path), mock.call(self.dut_from_path, self.dut_workdir_path), ], ) self.assertExists(self.moblab_workdir_path) self.assertExists(self.dut_workdir_path) self._mock_create_moblab_disk.assert_called_once_with( self.moblab_workdir_path) self.assertTrue(vmsetup.initialized) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def testMountMoblabDiskContextInUninitilizedWorkspaceRaises(self): """Cannot mount a disk if the workspace isn't even initialized.""" vmsetup = moblab_vm.MoblabVm(self.workspace) with self.assertRaises(moblab_vm.MoblabVmError): with vmsetup.MountedMoblabDiskContext(): pass
def testStartWithoutCreateRaises(self): """Calling .Start before .Create is an error.""" vmsetup = moblab_vm.MoblabVm(self.workspace) with self.assertRaises(moblab_vm.StartError): vmsetup.Start()
def testSuccessfulMountMoblabDiskContextAfter(self): """MountMoblabDiskContext works OK for initialized, non-running VM.""" self.testSuccessfulCreateNoDutDir() vmsetup = moblab_vm.MoblabVm(self.workspace) with vmsetup.MountedMoblabDiskContext() as mounted_path: self.assertStartsWith(mounted_path, self.tempdir)
def testInstanceInitialization(self): """Sanity check attributes before using the instance for anything.""" vmsetup = moblab_vm.MoblabVm(self.workspace) self.assertFalse(vmsetup.initialized) self.assertFalse(vmsetup.running) self.assertFalse(vmsetup.dut_running)
def testCreateNoCreateVmRaisesWhenSourceImageMissing(self): """A call to .Create w/o create_vm_images expects source image to exist.""" vmsetup = moblab_vm.MoblabVm(self.workspace) with self.assertRaises(moblab_vm.SetupError): vmsetup.Create(self.moblab_from_path, create_vm_images=False)