def test_query_all_nodes_swallows_Exception(self): node1, node2 = self.make_nodes(2) error_message = factory.make_name("error") error_type = factory.make_exception_type() new_state_2 = self.pick_alternate_state(node2["power_state"]) get_power_state = self.patch(power, "get_power_state") get_power_state.side_effect = [ fail(error_type(error_message)), succeed(new_state_2), ] suppress_reporting(self) maaslog = FakeLogger("maas.power", level=logging.DEBUG) twistlog = TwistedLoggerFixture() with maaslog, twistlog: yield power.query_all_nodes([node1, node2]) self.assertDocTestMatches( """\ hostname-...: Failed to refresh power state: %s hostname-...: Power state has changed from ... to ... """ % error_message, maaslog.output, )
def test_upgrade_does_not_change_other_errors(self): error_type = factory.make_exception_type() error = error_type() self.expectThat(error, Not(IsInstance(ExternalProcessError))) ExternalProcessError.upgrade(error) self.expectThat(error, Not(IsInstance(ExternalProcessError))) self.expectThat(error.__class__, Is(error_type))
def test_secure_erase_sets_security_password_hdparm(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) mock_check_output = self.patch(subprocess, "check_output") # Fail to get disk info just to exit early. exception_type = factory.make_exception_type() self.patch( maas_wipe, "get_hdparm_security_info" ).side_effect = exception_type() self.assertRaises(exception_type, secure_erase_hdparm, dev_name) self.assertThat( mock_check_output, MockCalledOnceWith( [ b"hdparm", b"--user-master", b"u", b"--security-set-pass", b"maas", file_path, ] ), )
def test_refresh_clears_up_temporary_directory(self): ScriptsBroken = factory.make_exception_type() def find_temporary_directories(): with tempfile.TemporaryDirectory() as tmpdir: tmpdir = Path(tmpdir).absolute() return { str(entry) for entry in tmpdir.parent.iterdir() if entry.is_dir() and entry != tmpdir } tmpdirs_during = set() tmpdir_during = None def runscripts(*args, tmpdir): self.assertThat(tmpdir, DirExists()) nonlocal tmpdirs_during, tmpdir_during tmpdirs_during |= find_temporary_directories() tmpdir_during = tmpdir raise ScriptsBroken("Foom") self.patch(refresh, "runscripts", runscripts) tmpdirs_before = find_temporary_directories() self.assertRaises(ScriptsBroken, refresh.refresh, sentinel.system_id, sentinel.consumer_key, sentinel.token_key, sentinel.token_secret) tmpdirs_after = find_temporary_directories() self.assertThat(tmpdirs_before, Not(Contains(tmpdir_during))) self.assertThat(tmpdirs_during, Contains(tmpdir_during)) self.assertThat(tmpdirs_after, Not(Contains(tmpdir_during)))
def test_raises_last_exception_after_all_retries_fail(self): wait_time = [random.randrange(1, 10) for _ in range(3)] driver = make_power_driver(wait_time=wait_time) exception_types = list( factory.make_exception_type((PowerError, )) for _ in wait_time) self.patch(driver, "power_query").side_effect = exception_types with ExpectedException(exception_types[-1]): yield driver.query(sentinel.system_id, sentinel.context)
def test_upgrade_does_not_change_CalledProcessError_subclasses(self): error_type = factory.make_exception_type(bases=(CalledProcessError,)) error = factory.make_CalledProcessError() error.__class__ = error_type # Change the class. self.expectThat(error, Not(IsInstance(ExternalProcessError))) ExternalProcessError.upgrade(error) self.expectThat(error, Not(IsInstance(ExternalProcessError))) self.expectThat(error.__class__, Is(error_type))
def test_handles_driver_raising_any_Exception(self): fake_driver = MagicMock() fake_driver.name = factory.make_name("pod") fake_exception_type = factory.make_exception_type() fake_exception_msg = factory.make_name("error") fake_exception = fake_exception_type(fake_exception_msg) fake_driver.discover.return_value = fail(fake_exception) self.patch(PodDriverRegistry, "get_item").return_value = fake_driver with ExpectedException( exceptions.PodActionFail, re.escape("Failed talking to pod: " + fake_exception_msg)): yield pods.discover_pod(fake_driver.name, {})
def test_opened_configuration_file_does_not_save_on_unclean_exit(self): config_file = os.path.join(self.make_dir(), "config") config_key = factory.make_name("key") config_value = factory.make_name("value") exception_type = factory.make_exception_type() # Set a configuration option, then crash. with ExpectedException(exception_type): with ConfigurationFile.open_for_update(config_file) as config: config[config_key] = config_value raise exception_type() # No value has been saved for `config_key`. with ConfigurationFile.open(config_file) as config: self.assertRaises(KeyError, lambda: config[config_key])
def test__savepoint_restores_hooks_only_on_dirty_exit(self): d1 = Deferred() d2 = Deferred() dhooks = DeferredHooks() dhooks.add(d1) exception_type = factory.make_exception_type() with ExpectedException(exception_type): with dhooks.savepoint(): dhooks.add(d2) raise exception_type() self.expectThat(list(dhooks.hooks), Equals([d1]))
def test__logs_errors(self): events = [] namespace = factory.make_name("namespace") legacy_logger = LegacyLogger(namespace, self, events.append) message = factory.make_name("message") exception_type = factory.make_exception_type() keywords = { factory.make_name("key"): factory.make_name("value") for _ in range(3) } try: raise exception_type() except exception_type: legacy_logger.err(None, message, **keywords) expected = { 'log_failure': MatchesAll( IsInstance(Failure), AfterPreprocessing( (lambda failure: failure.value), IsInstance(exception_type), ), ), 'log_format': Equals('{_why}'), 'log_level': Equals(logger.LogLevel.critical), 'log_logger': Is(legacy_logger), 'log_namespace': Equals(namespace), 'log_source': Is(self), 'log_time': IsInstance(float), '_why': Equals(message), } expected.update( {key: Equals(value) for key, value in keywords.items()}) self.assertThat(events, HasLength(1)) self.assertThat(events[0], MatchesDict(expected)) # Twisted 16.6.0 (see issue #8858) now includes a traceback, # so we only match on the beginning of the string. self.assertThat( logger.formatEventAsClassicLogText(events[0], formatTimeStatic), StartsWith("<when> [%s#critical] %s\n" % (namespace, message)))
def test_sync_does_propagate_ioerror(self): io_error = factory.make_exception_type(bases=(IOError, )) mock_sync = self.patch(download_descriptions.BasicMirrorWriter, "sync") mock_sync.side_effect = io_error() boot_images_dict = BootImageMapping() dumper = RepoDumper(boot_images_dict) with FakeLogger("maas.import-images", level=logging.INFO) as maaslog: self.assertRaises(io_error, dumper.sync, sentinel.reader, sentinel.path) self.assertDocTestMatches("...error...syncing boot images...", maaslog.output)
def test_handles_driver_raising_any_Exception(self): fake_driver = MagicMock() fake_driver.name = factory.make_name("pod") fake_exception_type = factory.make_exception_type() fake_exception_msg = factory.make_name("error") fake_exception = fake_exception_type(fake_exception_msg) fake_driver.decompose.return_value = fail(fake_exception) pod_id = random.randint(1, 10) pod_name = factory.make_name("pod") self.patch(PodDriverRegistry, "get_item").return_value = fake_driver with ExpectedException( exceptions.PodActionFail, re.escape("Failed talking to pod: " + fake_exception_msg)): yield pods.decompose_machine(fake_driver.name, {}, pod_id=pod_id, name=pod_name)
def test_failure_in_added_task_does_not_crash_service(self): things = [] # This will be populated by tasks. exception_type = factory.make_exception_type() def be_bad(): raise exception_type("I'm bad, so bad.") service = DatabaseTasksService() service.startService() try: service.addTask(things.append, 1) service.addTask(be_bad) service.addTask(things.append, 2) finally: service.stopService() self.assertThat(things, Equals([1, 2]))
def test_failure_in_deferred_task_does_not_crash_service(self): things = [] # This will be populated by tasks. exception_type = factory.make_exception_type() def be_bad(): raise exception_type("I'm being very naughty.") service = DatabaseTasksService() service.startService() try: service.deferTask(things.append, 1).wait(30) self.assertRaises(exception_type, service.deferTask(be_bad).wait, 30) service.deferTask(things.append, 2).wait(30) finally: service.stopService() self.assertThat(things, Equals([1, 2]))
def test_handles_driver_raising_any_Exception(self): fake_driver = MagicMock() fake_exception_type = factory.make_exception_type() fake_exception_msg = factory.make_name("error") fake_exception = fake_exception_type(fake_exception_msg) fake_driver.get_commissioning_data.return_value = fail(fake_exception) self.patch(PodDriverRegistry, "get_item").return_value = fake_driver with ExpectedException( exceptions.PodActionFail, re.escape("Failed talking to pod: " + fake_exception_msg), ): yield pods.send_pod_commissioning_results( pod_type=factory.make_name("type"), context={}, pod_id=random.randint(1, 10), name=factory.make_name("name"), system_id=factory.make_name("system_id"), consumer_key=factory.make_name("consumer_key"), token_key=factory.make_name("token_key"), token_secret=factory.make_name("token_secret"), metadata_url=urlparse(factory.make_url()), )
def test_get_reader_converts_other_exceptions_to_tftp_error(self): exception_type = factory.make_exception_type() exception_message = factory.make_string() client = Mock() client.localIdent = factory.make_name("system_id") client.return_value = fail(exception_type(exception_message)) client_service = Mock() client_service.getClientNow.return_value = succeed(client) backend = TFTPBackend(self.make_dir(), client_service) with TwistedLoggerFixture() as logger: with ExpectedException(BackendError, re.escape(exception_message)): yield backend.get_reader(b'pxelinux.cfg/default') # The original exception is logged. self.assertDocTestMatches( """\ TFTP back-end failed. Traceback (most recent call last): ... maastesting.factory.TestException#... """, logger.output)
def test_failed_run_deletes_snapshot(self): # Patch out things that we don't want running during the test. Patch # at a low level, so that we exercise all the function calls that a # unit test might not put to the test. self.patch_maaslog() self.patch(boot_resources, "call_and_check") self.patch(boot_resources, "service_monitor") args = self.make_working_args() # Cause the import to fail. exception_type = factory.make_exception_type() mock_download = self.patch(boot_resources, "download_all_boot_resources") mock_download.side_effect = exception_type() # Run the import code. self.assertRaises(exception_type, boot_resources.main, args) # Verify the reuslts. self.assertThat(os.path.join(self.storage, "cache"), Not(DirExists())) self.assertThat(os.path.join(self.storage, "current"), Not(DirExists()))
def test__sets_self_as_process_group_leader(self): exception_type = factory.make_exception_type() os = self.patch(avahi_module, "os") os.setpgrp.side_effect = exception_type self.assertRaises(exception_type, run, []) self.assertThat(os.setpgrp, MockCalledOnceWith())
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)