def test__returns_None_when_node_not_found(self): logger = self.useFixture(FakeLogger("maas", logging.DEBUG)) client = self.patch(windows_module, "getRegionClient").return_value client.side_effect = always_fail_with(NoSuchNode()) mac = factory.make_mac_address() d = windows_module.request_node_info_by_mac_address(mac) self.assertThat(extract_result(d), Is(None)) self.assertDocTestMatches( "Node doesn't exist for MAC address: %s" % mac, logger.output)
def test_unhandled_errors_do_not_cause_disconnection(self): self.patch(common.log, "debug") protocol = common.RPCProtocol() protocol.makeConnection(StringTransport()) # Ensure that the superclass dispatchCommand() will fail. dispatchCommand = self.patch(amp.AMP, "dispatchCommand") dispatchCommand.side_effect = always_fail_with(ZeroDivisionError()) # Push a command box into the protocol. seq = b"%d" % random.randrange(0, 2**32) cmd = factory.make_string().encode("ascii") box = amp.AmpBox(_ask=seq, _command=cmd) with TwistedLoggerFixture() as logger: protocol.ampBoxReceived(box) # The transport is still connected. self.expectThat(protocol.transport.disconnecting, Is(False)) # The error has been logged on the originating side of the AMP # session, along with an explanatory message. The message includes a # command reference. cmd_ref = common.make_command_ref(box) self.assertDocTestMatches( """\ Unhandled failure dispatching AMP command. This is probably a bug. Please ensure that this error is handled within application code or declared in the signature of the %s command. [%s] Traceback (most recent call last): ... """ % (cmd, cmd_ref), logger.output, ) # A simpler error message has been transmitted over the wire. It # includes the same command reference as logged locally. protocol.transport.io.seek(0) observed_boxes_sent = amp.parse(protocol.transport.io) expected_boxes_sent = [ amp.AmpBox( _error=seq, _error_code=amp.UNHANDLED_ERROR_CODE, _error_description=(b"Unknown Error [%s]" % cmd_ref.encode("ascii")), ) ] self.assertThat(observed_boxes_sent, Equals(expected_boxes_sent))
def test_logs_failures(self): rack_controllers = [factory.make_RackController()] clients = self.patch_clients(rack_controllers) clients[0].side_effect = always_fail_with( ZeroDivisionError("splendid day for a spot of cricket")) tag_name = factory.make_name("tag") tag_definition = factory.make_name("definition") tag_nsmap = {} work = [] for rack, client in zip(rack_controllers, clients): work.append({ "system_id": rack.system_id, "hostname": rack.hostname, "client": client, "tag_name": tag_name, "tag_definition": tag_definition, "tag_nsmap": tag_nsmap, "credentials": factory.make_name("creds"), "nodes": [{ "system_id": factory.make_Node().system_id } for _ in range(3)], }) with FakeLogger("maas") as log: [d] = _do_populate_tags(work) self.assertIsNone(extract_result(d)) self.assertDocTestMatches( "Tag tag-... (definition-...) could not be evaluated ... (...): " "splendid day for a spot of cricket", log.output, )
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)
def patch_authenticate_for_error(self, client, exception): authenticate = self.patch_autospec(client, "authenticateCluster") authenticate.side_effect = always_fail_with(exception)
def test__returns_None_when_node_not_found(self): client = self.patch(windows_module, "getRegionClient").return_value client.side_effect = always_fail_with(NoSuchNode()) mac = factory.make_mac_address() d = windows_module.request_node_info_by_mac_address(mac) self.assertThat(extract_result(d), Is(None))