def test_get_power_state_queries_node(self): system_id = factory.make_name("system_id") hostname = factory.make_name("hostname") power_driver = random.choice( [driver for _, driver in PowerDriverRegistry if driver.queryable] ) power_state = random.choice(["on", "off"]) context = { factory.make_name("context-key"): factory.make_name("context-val") } self.patch(power, "is_driver_available").return_value = True _, markNodeBroken, io = self.patch_rpc_methods() mock_perform_power_driver_query = self.patch( power, "perform_power_driver_query" ) mock_perform_power_driver_query.return_value = power_state d = power.get_power_state( system_id, hostname, power_driver.name, context ) # This blocks until the deferred is complete. io.flush() self.assertEqual(power_state, extract_result(d)) self.assertThat( power_driver.detect_missing_packages, MockCalledOnceWith() ) self.assertThat( mock_perform_power_driver_query, MockCallsMatch( call(system_id, hostname, power_driver.name, context) ), )
def test_get_power_state_fails_for_missing_packages(self): system_id = factory.make_name("system_id") hostname = factory.make_name("hostname") power_driver = random.choice( [driver for _, driver in PowerDriverRegistry if driver.queryable]) context = { factory.make_name("context-key"): factory.make_name("context-val") } self.patch(power, "is_driver_available").return_value = False _, markNodeBroken, io = self.patch_rpc_methods() power_driver.detect_missing_packages.return_value = ["gone"] d = power.get_power_state(system_id, hostname, power_driver.name, context) # This blocks until the deferred is complete. io.flush() self.assertThat(power_driver.detect_missing_packages, MockCalledOnceWith()) return assert_fails_with(d, exceptions.PowerActionFail)
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)