def test_run_smartctl_with_smartctl_failure(self): self.patch(smartctl, 'list_supported_drives').return_value = [ ['/dev/sda', '-d', 'sat'], ] output = factory.make_string() self.patch(smartctl, 'check_call').side_effect = CalledProcessError( 1, 'smartctl'), mock_popen = self.patch(smartctl, 'Popen') mock_popen.return_value = Popen(['echo', '-n', output], stdout=PIPE) mock_print = self.patch(smartctl, 'print') test = factory.make_name('test') self.assertEquals(1, smartctl.run_smartctl(test)) dashes = '-' * int((80.0 - (2 + len('/dev/sda'))) / 2) header = '%s /dev/sda %s' % (dashes, dashes) self.assertThat( mock_print, MockCallsMatch( call(header), call(), call('Failed to start and wait for smartctl self-test: %s' % test), call(), call(output)))
def test__show_service_start_error(self): url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) mock_call_and_check = self.patch(register_command, 'call_and_check') mock_call_and_check.side_effect = [ call(), call(), ExternalProcessError(1, 'systemctl start', 'mock error'), ] mock_stderr = self.patch(register_command.stderr, 'write') with ExpectedException(SystemExit): register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertThat( mock_stderr, MockCallsMatch( call('Unable to enable and start the maas-rackd service.'), call('\n'), call('Failed with error: mock error.'), call('\n'), ))
def test_returns_true_with_device(self): device = factory.make_name("device") self.mock_check_smart_support.return_value = (device, [42]) device = "%s,42" % device self.assertTrue(smartctl.execute_smartctl(self.blockdevice, self.test)) self.assertThat( self.mock_check_smart_support, MockCallsMatch(call(self.blockdevice), call(self.blockdevice, device)), ) self.assertThat( self.mock_run_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device), ) self.assertThat( self.mock_wait_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device), ) self.assertThat( self.mock_check_smartctl, MockCalledOnceWith(self.blockdevice, device), )
def test_add_bmc_user_rand_password_with_special_chars(self): self.ipmi.username = None self.ipmi.password = None user_number = "User%s" % random.randint(2, 12) password = factory.make_name("password") password_w_spec_chars = factory.make_name("password_w_spec_chars") self.patch(self.ipmi, "_pick_user_number").return_value = user_number self.patch(self.ipmi, "_generate_random_password").side_effect = ( password, password_w_spec_chars, ) mock_bmc_set = self.patch(self.ipmi, "_bmc_set") mock_bmc_set.side_effect = ( None, factory.make_exception(), None, None, None, None, None, ) self.ipmi.add_bmc_user() self.assertEqual("maas", self.ipmi.username) self.assertEqual(password_w_spec_chars, self.ipmi.password) self.assertThat( mock_bmc_set, MockCallsMatch( call(f"{user_number}:Username", "maas"), call(f"{user_number}:Password", password), call(f"{user_number}:Username", "maas"), call(f"{user_number}:Password", password_w_spec_chars), call(f"{user_number}:Enable_User", "Yes"), call(f"{user_number}:Lan_Privilege_Limit", "Administrator"), call(f"{user_number}:Lan_Enable_IPMI_Msgs", "Yes"), ), )
def test_requests_beaconing_when_timer_fires(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop(region.UpdateInterfaces, region.GetDiscoveryState) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed("rpc") reactor = Clock() service = RackNetworksMonitoringService( rpc_service, reactor, enable_monitoring=False, enable_beaconing=True, ) service.beaconing_protocol = Mock() service.beaconing_protocol.queueMulticastBeaconing = Mock() service.getInterfaces = lambda: succeed({}) service._recorded = {} service.startService() yield service.stopService() self.assertThat( service.beaconing_protocol.queueMulticastBeaconing, MockCallsMatch(call(solicitation=True)), )
def test__calls_lsblk_udevadm_then_blockdev_snap_without_sudo(self): self.useFixture(EnvironmentVariableFixture('SNAP', '')) name = factory.make_name('name') model = factory.make_name('model') serial = factory.make_name('serial') size = random.randint(3000 * 1000, 1000 * 1000 * 1000) block_size = random.choice([512, 1024, 4096]) check_output = self.patch(subprocess, "check_output") check_output.side_effect = [ self.make_lsblk_output(name=name, model=model), self.make_udevadm_output(name, serial=serial), b'%d' % size, b'%d' % block_size, ] self.call_gather_physical_block_devices() self.assertThat( check_output, MockCallsMatch( call(("lsblk", "--exclude", "1,2,7", "-d", "-P", "-o", "NAME,RO,RM,MODEL,ROTA,MAJ:MIN")), call(("udevadm", "info", "-q", "all", "-n", name)), call(("blockdev", "--getsize64", "/dev/%s" % name)), call(("blockdev", "--getbsz", "/dev/%s" % name))))
def test_get_bmc_ip_enables_dynamic(self): ip = factory.make_ip_address() mock_bmc_set = self.patch(self.ipmi, "_bmc_set") self.patch(self.ipmi, "_get_bmc_ip").side_effect = ( None, None, None, None, None, None, None, None, ip, ) self.assertEqual(ip, self.ipmi.get_bmc_ip()) self.assertThat( mock_bmc_set, MockCallsMatch( call("Lan_Conf:IP_Address_Source", "Static"), call("Lan_Conf:IP_Address_Source", "Use_DHCP"), ), )
def test_waits(self): blockdevice = factory.make_name("blockdevice") test = factory.make_name("test") device = factory.make_name("device") mock_sleep = self.patch(smartctl, "sleep") mock_run_smartctl = self.patch(smartctl, "run_smartctl") mock_run_smartctl.side_effect = ( "Self-test execution status: (42) Self-test routine in progress", "", "", ) smartctl.wait_smartctl_selftest(blockdevice, test, device) self.assertThat( mock_run_smartctl, MockCallsMatch( call(blockdevice, ["-c"], device), call(blockdevice, ["-c"], device), call(blockdevice, ["--all"], device), ), ) self.assertThat(mock_sleep, MockCalledOnceWith(30))
def test_gets_adaptors(self): adaptor = "adaptor" server = make_server() mac = "xx" api = make_api() mock = self.patch(ucsm, "get_children") def fake_get_children(api, element, class_id): if class_id == "adaptorUnit": return [adaptor] elif class_id == "adaptorHostEthIf": return [Element("ethif", {"mac": mac})] mock.side_effect = fake_get_children macs = get_macs(api, server) self.assertThat( mock, MockCallsMatch( call(api, server, "adaptorUnit"), call(api, adaptor, "adaptorHostEthIf"), ), ) self.assertEqual([mac], macs)
def test_waits_alt(self): blockdevice = factory.make_name("blockdevice") test = factory.make_name("test") device = factory.make_name("device") mock_sleep = self.patch(smartctl, "sleep") mock_run_smartctl = self.patch(smartctl, "run_smartctl") mock_run_smartctl.side_effect = ( "Background %s Self test in progress" % test, "Background %s Self test in progress" % test, "", ) smartctl.wait_smartctl_selftest(blockdevice, test, device) self.assertThat( mock_run_smartctl, MockCallsMatch( call(blockdevice, ["-c"], device), call(blockdevice, ["--all"], device), call(blockdevice, ["--all"], device), ), ) self.assertThat(mock_sleep, MockCalledOnceWith(30))
def test_run_badblocks(self): drive = { 'NAME': factory.make_name('NAME'), 'PATH': factory.make_name('PATH'), 'MODEL': factory.make_name('MODEL'), 'SERIAL': factory.make_name('SERIAL'), } self.patch(badblocks, 'list_drives').return_value = [drive] output = factory.make_string() self.patch(badblocks, 'check_output').return_value = '4096' mock_popen = self.patch(badblocks, 'Popen') mock_popen.return_value = Popen(['echo', '-n', output], stdout=PIPE) mock_print = self.patch(badblocks, 'print') self.assertEquals(0, badblocks.run_badblocks()) dashes = '-' * int((80.0 - (2 + len(drive['PATH']))) / 2) header = '%s %s %s' % (dashes, drive['PATH'], dashes) self.assertThat( mock_print, MockCallsMatch(call(header), call('Model: %s' % drive['MODEL']), call('Serial: %s' % drive['SERIAL']), call(), call(output)))
def test__issue_ipmi_command_issues_power_off_soft_mode(self): context = make_context() context['power_off_mode'] = 'soft' ipmi_chassis_config_command = make_ipmi_chassis_config_command( **context, tmp_config_name=ANY) ipmipower_command = make_ipmipower_command(**context) ipmipower_command += ('--soft', ) ipmi_power_driver = IPMIPowerDriver() env = select_c_utf8_locale() popen_mock = self.patch(ipmi_module, 'Popen') process = popen_mock.return_value process.communicate.side_effect = [(b'', b''), (b'off', b'')] process.returncode = 0 result = ipmi_power_driver._issue_ipmi_command('off', **context) self.expectThat( popen_mock, MockCallsMatch( call(ipmi_chassis_config_command, stdout=PIPE, stderr=PIPE, env=env), call(ipmipower_command, stdout=PIPE, stderr=PIPE, env=env))) self.expectThat(result, Equals('off'))
def test__show_service_stop_error(self): url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) mock_call_and_check = self.patch(register_command, "call_and_check") mock_call_and_check.side_effect = [ ExternalProcessError(1, "systemctl stop", "mock error"), call(), call(), ] mock_stderr = self.patch(register_command.stderr, "write") with ExpectedException(SystemExit): register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertThat( mock_stderr, MockCallsMatch( call("Unable to stop maas-rackd service."), call("\n"), call("Failed with error: mock error."), call("\n"), ), )
def test_get_response_tries_multiple_times(self): handler = views.WebApplicationHandler(3) # An iterable of responses, the last of which will be # an HttpResponseConflict (HTTP 409 - Conflict) error # indicating that the request reached its maximum # number of retry attempts. responses = iter(( HttpResponse(status=200), HttpResponse(status=200), HttpResponse(status=200), )) def set_retry(request): response = next(responses) handler._WebApplicationHandler__retry.add(response) return response get_response = self.patch(WSGIHandler, "get_response") get_response.side_effect = set_retry reset_request = self.patch_autospec(views, "reset_request") reset_request.side_effect = lambda request: request request = make_request() request.path = factory.make_name("path") response = handler.get_response(request) self.assertThat( get_response, MockCallsMatch(call(request), call(request), call(request)), ) self.assertThat(response, IsInstance(HttpResponseConflict)) self.expectThat(response.status_code, Equals(http.client.CONFLICT)) self.expectThat( response.reason_phrase, Equals(http.client.responses[http.client.CONFLICT]), )
def test_create_service(self): products = [{ "$uri": "/api/rbac/v1/product/1", "label": "maas", "name": "MAAS" }] maas = { "$uri": "/api/rbac/v1/service/2", "name": "maas", "description": "", "pending": True, "product": { "$ref": "/api/rbac/v1/product/1" }, } self.mock_responses(products, maas) self.assertEqual(self.client.create_service("maas"), maas) json = {"name": "maas", "product": {"$ref": "/api/rbac/v1/product/1"}} self.assertThat( self.mock_request, MockCallsMatch( mock.call( "GET", "https://rbac.example.com/api/rbac/v1/product", auth=mock.ANY, cookies=mock.ANY, json=None, ), mock.call( "POST", "https://rbac.example.com/api/rbac/v1/service", auth=mock.ANY, cookies=mock.ANY, json=json, ), ), )
def test__set_pxe_boot_sets_pxe(self): amt_power_driver = AMTPowerDriver() ip_address = factory.make_ipv4_address() power_pass = factory.make_name('power_pass') wsman_pxe_options = { 'ChangeBootOrder': (join(dirname(dirname(__file__)), "amt.wsman-pxe.xml"), ('http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/' 'CIM_BootConfigSetting?InstanceID="Intel(r) ' 'AMT: Boot Configuration 0"')), 'SetBootConfigRole': (join(dirname(dirname(__file__)), "amt.wsman-boot-config.xml"), ('http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/' 'CIM_BootService?SystemCreationClassName=' '"CIM_ComputerSystem",SystemName="Intel(r) AMT"' ',CreationClassName="CIM_BootService",Name="Intel(r)' ' AMT Boot Service"')), } wsman_opts = ('--port', '16992', '--hostname', ip_address, '--username', 'admin', '--password', power_pass, '--noverifypeer', '--noverifyhost') _run_mock = self.patch(amt_power_driver, '_run') amt_power_driver._set_pxe_boot(ip_address, power_pass) commands = [] stdins = [] for method, (schema_file, schema_uri) in wsman_pxe_options.items(): with open(schema_file, "rb") as fd: command = 'wsman', 'invoke', '--method', method, schema_uri command += wsman_opts + ('--input', '-') commands.append(command) stdins.append(fd.read()) self.assertThat( _run_mock, MockCallsMatch(call(commands[0], power_pass, stdin=stdins[0]), call(commands[1], power_pass, stdin=stdins[1])))
def test_power_on(self): driver = fence_cdu_module.FenceCDUPowerDriver() environ = select_c_utf8_locale() context = self.make_context() mock = self.patch(fence_cdu_module, 'call_and_check') mock.side_effect = (b"Status: ON\n", b"Status: OFF\n", b"Status: OFF\n", b"Status: ON\n") self.patch(driver, 'sleep') driver.power_on("fake_id", context) self.assertThat( mock, MockCallsMatch( call([ sentinel.fence_cdu, '-a', sentinel.power_address, '-n', sentinel.power_id, '-l', sentinel.power_user, '-p', sentinel.power_pass, '-o', 'status' ], env=environ), call([ sentinel.fence_cdu, '-a', sentinel.power_address, '-n', sentinel.power_id, '-l', sentinel.power_user, '-p', sentinel.power_pass, '-o', 'off' ], env=environ), call([ sentinel.fence_cdu, '-a', sentinel.power_address, '-n', sentinel.power_id, '-l', sentinel.power_user, '-p', sentinel.power_pass, '-o', 'status' ], env=environ), call([ sentinel.fence_cdu, '-a', sentinel.power_address, '-n', sentinel.power_id, '-l', sentinel.power_user, '-p', sentinel.power_pass, '-o', 'on' ], env=environ)))
def test_wrap_redfish_request_retries_404s_trailing_slash(self): driver = RedfishPowerDriver() context = make_context() url = driver.get_url(context) uri = join(url, b"redfish/v1/Systems") headers = driver.make_auth_headers(**context) mock_agent = self.patch(redfish_module, "Agent") mock_agent.return_value.request = Mock() expected_headers = Mock() expected_headers.code = HTTPStatus.NOT_FOUND expected_headers.headers = "Testing Headers" happy_headers = Mock() happy_headers.code = HTTPStatus.OK happy_headers.headers = "Testing Headers" mock_agent.return_value.request.side_effect = [ succeed(expected_headers), succeed(happy_headers), ] mock_readBody = self.patch(redfish_module, "readBody") mock_readBody.return_value = succeed( json.dumps(SAMPLE_JSON_SYSTEMS).encode("utf-8") ) expected_response = SAMPLE_JSON_SYSTEMS response, return_headers = yield driver.redfish_request( b"GET", uri, headers ) self.assertThat( mock_agent.return_value.request, MockCallsMatch( call(b"GET", uri, headers, None), call(b"GET", uri + "/".encode("utf-8"), headers, None), ), ) self.assertEqual(expected_response, response) self.assertEqual(expected_headers.headers, return_headers)
def test_update_authorisation_token_with_token_key(self): # We use only "token_key" portion of the authorisation token # to update the token name. token_name_orig = "Test_Token" token_name_updated = "Test_Token update" mock_create_audit_event = self.patch( account_module, "create_audit_event" ) response_creation = self.client.post( reverse("account_handler"), {"op": "create_authorisation_token", "name": token_name_orig}, ) parsed_creation_response = json_load_bytes(response_creation.content) created_token = ":".join( [ parsed_creation_response["consumer_key"], parsed_creation_response["token_key"], parsed_creation_response["token_secret"], ] ) self.client.post( reverse("account_handler"), { "op": "update_token_name", "token": parsed_creation_response["token_key"], "name": token_name_updated, }, ) response_list = self.client.get( reverse("account_handler"), {"op": "list_authorisation_tokens"} ) parsed_list_response = json_load_bytes(response_list.content) for token in parsed_list_response: if token["token"] == created_token: self.assertEqual(token["name"], token_name_updated) self.assertThat(mock_create_audit_event, MockCallsMatch(ANY, ANY))
def test_power_on_powers_on_blade(self): driver = MicrosoftOCSPowerDriver() context = make_context() system_id = factory.make_name("system_id") mock_power_query = self.patch(driver, "power_query") mock_power_query.return_value = "on" mock_power_off = self.patch(driver, "power_off") mock_set_next_boot_device = self.patch(driver, "set_next_boot_device") mock_get = self.patch(driver, "get") driver.power_on(system_id, context) self.expectThat(mock_power_query, MockCalledOnceWith(system_id, context)) self.expectThat(mock_power_off, MockCalledOnceWith(system_id, context)) self.expectThat( mock_set_next_boot_device, MockCallsMatch(call(context, persistent=True), call(context, pxe=True)), ) self.expectThat( mock_get, MockCalledOnceWith("SetBladeOn", context, ["bladeid=%s" % context["blade_id"]]), )
def test__returns_false_when_unable_to_check_device(self): device = factory.make_name('device') self.mock_check_smart_support.return_value = (device, [42]) self.mock_check_smartctl.side_effect = random.choice([ TimeoutExpired('smartctl', 60), CalledProcessError(42, 'smartctl'), ]), device = '%s,42' % device self.assertFalse(smartctl.execute_smartctl(self.blockdevice, self.test)) self.assertThat( self.mock_check_smart_support, MockCallsMatch( call(self.blockdevice), call(self.blockdevice, device), )) self.assertThat( self.mock_run_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device)) self.assertThat( self.mock_wait_smartctl_selftest, MockCalledOnceWith(self.blockdevice, self.test, device)) self.assertThat(self.mock_check_smartctl, MockCalledOnceWith(self.blockdevice, device))
def test_wipe_quickly_successful(self): tmp_dir = self.make_dir() dev_path = (tmp_dir + "/%s").encode("ascii") self.patch(maas_wipe, "DEV_PATH", dev_path) dev_name = factory.make_name("disk").encode("ascii") file_path = dev_path % dev_name self.make_empty_file(file_path, content=b"T") mock_check_output = self.patch(subprocess, "check_output") wipe_quickly(dev_name) self.assertThat( mock_check_output, MockCalledOnceWith( ["wipefs", "-f", "-a", maas_wipe.DEV_PATH % dev_name] ), ) buf_size = 1024 * 1024 with open(file_path, "rb") as fp: first_buf = fp.read(buf_size) fp.seek(-buf_size, 2) last_buf = fp.read(buf_size) zero_buf = b"\0" * 1024 * 1024 self.assertEqual(zero_buf, first_buf, "First 1 MiB was not wiped.") self.assertEqual(zero_buf, last_buf, "Last 1 MiB was not wiped.") self.assertThat( self.print_flush, MockCallsMatch( call("%s: starting quick wipe." % dev_name.decode("ascii")), call( "%s: successfully quickly wiped." % dev_name.decode("ascii") ), ), )
def test_creates_current_symlink_when_temp_link_exists(self): symlink_real = os.symlink symlink = self.patch(os, "symlink") def os_symlink(src, dst): if symlink.call_count in (1, 2): raise OSError(errno.EEXIST, dst) else: return symlink_real(src, dst) # The first two times that os.symlink() is called, it will raise # OSError with EEXIST; update_current_symlink() handles this and # tries to create a new symlink with a different suffix. symlink.side_effect = os_symlink # Make the choice of provisional symlink less random, so that we can # match against what's happening. from provisioningserver.utils import fs randint = self.patch_autospec(fs, "randint") randint.side_effect = lambda a, b: randint.call_count storage_dir, target_dir = self.make_test_dirs() base_target_dir = os.path.basename(target_dir) self.assertLinkIsUpdated(storage_dir, target_dir) self.assertThat( symlink, MockCallsMatch( call(base_target_dir, os.path.join(storage_dir, ".temp.000001")), call(base_target_dir, os.path.join(storage_dir, ".temp.000002")), call(base_target_dir, os.path.join(storage_dir, ".temp.000003")), ), )
def test_set_ipmi_lan_channel_setting_enables(self): mock_bmc_set = self.patch(self.ipmi, "_bmc_set") mock_bmc_get = self.patch(self.ipmi, "_bmc_get") mock_bmc_get.side_effect = ( ("Section Lan_Channel\n" "\t## Possible values: Disabled/Pre_Boot_Only/" "Always_Available/Shared\n" "\tVolatile_Access_Mode Disabled\n" "EndSection\n"), ("Section Lan_Channel\n" "\t## Possible values: Disabled/Pre_Boot_Only/" "Always_Available/Shared\n" "\tNon_Volatile_Access_Mode Pre_Boot_only\n" "EndSection\n"), ) self.ipmi._set_ipmi_lan_channel_settings() self.assertThat( mock_bmc_set, MockCallsMatch( call("Lan_Channel:Volatile_Access_Mode", "Always_Available"), call("Lan_Channel:Non_Volatile_Access_Mode", "Always_Available"), ), )
def test_run_smartctl_selftest_waits_for_finish(self): storage = factory.make_name('storage') test = factory.make_name('test') self.patch(smartctl, 'sleep') mock_check_call = self.patch(smartctl, "check_call") mock_check_output = self.patch(smartctl, "check_output") mock_check_output.side_effect = [ b'Self-test execution status: ( 249) ' + b'Self-test routine in progress...', b'Self-test execution status: ( 249) ' + b'Self-test routine in progress...', b'Self-test execution status: ( 249) ' + b'Self-test routine in progress...', b'Self-test execution status: ( 73) ' + b'The previous self-test completed having', ] self.assertTrue(smartctl.run_smartctl_selftest(storage, test)) self.assertThat( mock_check_call, MockCalledOnceWith( ['sudo', '-n', 'smartctl', '-s', 'on', '-t', test, storage], timeout=smartctl.TIMEOUT, stdout=DEVNULL, stderr=DEVNULL)) self.assertThat( mock_check_output, MockCallsMatch( call(['sudo', '-n', 'smartctl', '-c', storage], timeout=smartctl.TIMEOUT), call(['sudo', '-n', 'smartctl', '-c', storage], timeout=smartctl.TIMEOUT), call(['sudo', '-n', 'smartctl', '-c', storage], timeout=smartctl.TIMEOUT), call(['sudo', '-n', 'smartctl', '-c', storage], timeout=smartctl.TIMEOUT)))
def test_wipe_quickly_failed(self): dev_name = factory.make_name("disk").encode("ascii") mock_check_output = self.patch(subprocess, "check_output") mock_check_output.side_effect = subprocess.CalledProcessError( 1, "wipefs") mock_os_open = self.patch(builtins, "open") mock_os_open.side_effect = OSError(-2, "No such file or directory") wipe_quickly(dev_name) self.assertThat( self.print_flush, MockCallsMatch( call("%s: starting quick wipe." % dev_name.decode("ascii")), call("%s: wipefs failed (1)" % dev_name.decode("ascii")), call( "%s: OS error while wiping beginning/end of disk (No such file or directory)" % dev_name.decode("ascii")), call("%s: failed to be quickly wiped." % dev_name.decode("ascii")), ), )
def test__power_on(self): driver = RedfishPowerDriver() context = make_context() url = driver.get_url(context) headers = driver.make_auth_headers(**context) node_id = b"1" mock_redfish_request = self.patch(driver, "redfish_request") mock_redfish_request.return_value = (SAMPLE_JSON_SYSTEMS, None) mock_set_pxe_boot = self.patch(driver, "set_pxe_boot") mock_power_query = self.patch(driver, "power_query") mock_power_query.return_value = "on" mock_power = self.patch(driver, "power") yield driver.power_on(node_id, context) self.assertThat(mock_set_pxe_boot, MockCalledOnceWith(url, node_id, headers)) self.assertThat(mock_power_query, MockCalledOnceWith(node_id, context)) self.assertThat( mock_power, MockCallsMatch( call("ForceOff", url, node_id, headers), call("On", url, node_id, headers), ), )
def test_has_useful_string_representation(self): matcher = MockCallsMatch(call(1, 2, a=3), call(4, 5, a=6)) self.assertEqual( "MockCallsMatch([call(1, 2, a=3), call(4, 5, a=6)])", matcher.__str__(), )
def test_probe_and_enlist(self): # Patch VirshSSH list so that some machines are returned # with some fake architectures. user = factory.make_name('user') system_id = factory.make_name('system_id') machines = [factory.make_name('machine') for _ in range(5)] self.patch(virsh.VirshSSH, 'list').return_value = machines fake_arch = factory.make_name('arch') mock_arch = self.patch(virsh.VirshSSH, 'get_arch') mock_arch.return_value = fake_arch domain = factory.make_name('domain') # Patch get_state so that one of the machines is on, so we # can check that it will be forced off. fake_states = [ virsh.VirshVMState.ON, virsh.VirshVMState.OFF, virsh.VirshVMState.OFF, virsh.VirshVMState.ON, virsh.VirshVMState.ON, ] mock_state = self.patch(virsh.VirshSSH, 'get_state') mock_state.side_effect = fake_states # Setup the power parameters that we should expect to be # the output of the probe_and_enlist fake_password = factory.make_string() poweraddr = factory.make_name('poweraddr') called_params = [] fake_macs = [] for machine in machines: macs = [factory.make_mac_address() for _ in range(4)] fake_macs.append(macs) called_params.append({ 'power_address': poweraddr, 'power_id': machine, 'power_pass': fake_password, }) # Patch the get_mac_addresses so we get a known list of # mac addresses for each machine. mock_macs = self.patch(virsh.VirshSSH, 'get_mac_addresses') mock_macs.side_effect = fake_macs # Patch the poweroff and create as we really don't want these # actions to occur, but want to also check that they are called. mock_poweroff = self.patch(virsh.VirshSSH, 'poweroff') mock_create_node = self.patch(virsh, 'create_node') mock_create_node.side_effect = asynchronous( lambda *args, **kwargs: None if machines[4] in args else system_id) mock_commission_node = self.patch(virsh, 'commission_node') # Patch login and logout so that we don't really contact # a server at the fake poweraddr mock_login = self.patch(virsh.VirshSSH, 'login') mock_login.return_value = True mock_logout = self.patch(virsh.VirshSSH, 'logout') mock_get_machine_xml = self.patch(virsh.VirshSSH, 'get_machine_xml') mock_get_machine_xml.side_effect = [ SAMPLE_DUMPXML, SAMPLE_DUMPXML_2, SAMPLE_DUMPXML_3, SAMPLE_DUMPXML_4, SAMPLE_DUMPXML, ] mock_run = self.patch(virsh.VirshSSH, 'run') mock_run.side_effect = self._probe_and_enlist_mock_run # Perform the probe and enlist yield deferToThread(virsh.probe_virsh_and_enlist, user, poweraddr, fake_password, accept_all=True, domain=domain) # Check that login was called with the provided poweraddr and # password. self.expectThat(mock_login, MockCalledOnceWith(poweraddr, fake_password)) # Check that the create command had the correct parameters for # each machine. self.expectThat( mock_create_node, MockCallsMatch( call(fake_macs[0], fake_arch, 'virsh', called_params[0], domain, machines[0]), call(fake_macs[1], fake_arch, 'virsh', called_params[1], domain, machines[1]), call(fake_macs[2], fake_arch, 'virsh', called_params[2], domain, machines[2]), call(fake_macs[3], fake_arch, 'virsh', called_params[3], domain, machines[3]), call(fake_macs[4], fake_arch, 'virsh', called_params[4], domain, machines[4]), )) # The first and last machine should have poweroff called on it, as it # was initial in the on state. self.expectThat(mock_poweroff, MockCallsMatch( call(machines[0]), call(machines[3]), )) self.assertThat(mock_logout, MockCalledOnceWith()) self.expectThat( mock_commission_node, MockCallsMatch( call(system_id, user), call(system_id, user), call(system_id, user), call(system_id, user), ))
def test_report_power_state_reports_all_exceptions(self): logger_twisted = self.useFixture(TwistedLoggerFixture()) logger_maaslog = self.useFixture(FakeLogger("maas")) # Avoid threads here. self.patch(power, "deferToThread", maybeDeferred) exception_type = factory.make_exception_type() exception_message = factory.make_string() exception = exception_type(exception_message) # Pretend the query always fails with `exception`. query = self.patch_autospec(power, self.func) query.side_effect = always_fail_with(exception) # Intercept calls to power_state_update() and send_node_event(). power_state_update = self.patch_autospec(power, "power_state_update") power_state_update.return_value = succeed(None) send_node_event = self.patch_autospec(power, "send_node_event") send_node_event.return_value = succeed(None) self.patch( self.power_driver, "detect_missing_packages" ).return_value = [] system_id = factory.make_name("system_id") hostname = factory.make_name("hostname") context = sentinel.context clock = Clock() d = power.get_power_state( system_id, hostname, self.power_type, context, clock ) d = power.report_power_state(d, system_id, hostname) # Crank through some number of retries. for wait in self.waits: self.assertFalse(d.called) clock.advance(wait) self.assertTrue(d.called) # Finally the exception from the query is raised. self.assertRaises(exception_type, extract_result, d) # The broken power query function patched earlier was called the same # number of times as there are steps in the default waiting policy. expected_call = call(system_id, hostname, self.power_type, context) expected_calls = [expected_call] * self.calls self.assertThat(query, MockCallsMatch(*expected_calls)) expected_message = "%s: Power state could not be queried: %s" % ( hostname, exception_message, ) # An attempt was made to report the failure to the region. self.assertThat( power_state_update, MockCalledOnceWith(system_id, "error") ) # An attempt was made to log a node event with details. self.assertThat( send_node_event, MockCalledOnceWith( EVENT_TYPES.NODE_POWER_QUERY_FAILED, system_id, hostname, exception_message, ), ) # Nothing was logged to the Twisted log. self.assertEqual("", logger_twisted.output) # A brief message is written to maaslog. self.assertEqual(expected_message + "\n", logger_maaslog.output)