def test_immediate_success(self, logger): """ If the predicate returns something truthy immediately, then ``loop_until`` returns a deferred that has already fired with that value. """ result = object() def predicate(): return result clock = Clock() d = loop_until(clock, predicate) self.assertEqual(self.successResultOf(d), result) action = LoggedAction.of_type(logger.messages, LOOP_UNTIL_ACTION)[0] assertContainsFields(self, action.start_message, { 'predicate': predicate, }) assertContainsFields(self, action.end_message, { 'action_status': 'succeeded', 'result': result, })
def test_reconnection_failed(self): assert self.factory.disconnect is False self.factory.last_reconnection_wait = \ CardinalBotFactory.MINIMUM_RECONNECTION_WAIT clock = Clock() mock_connector = Mock() self.factory._reactor = clock self.factory.clientConnectionFailed(mock_connector, 'Called by unit test') # time should have doubled assert self.factory.last_reconnection_wait == \ CardinalBotFactory.MINIMUM_RECONNECTION_WAIT * 2 # make sure it's not called on original time clock.advance(self.factory.MINIMUM_RECONNECTION_WAIT) assert not mock_connector.connect.called # advance it one more time and it should be clock.advance(self.factory.MINIMUM_RECONNECTION_WAIT) mock_connector.connect.assert_called_once()
def test_logs_other_errors(self): service = ImageDownloadService( sentinel.rpc, sentinel.tftp_root, Clock()) maybe_start_download = self.patch(service, "maybe_start_download") maybe_start_download.return_value = defer.fail( ZeroDivisionError("Such a shame I can't divide by zero")) with FakeLogger("maas") as maaslog, TwistedLoggerFixture() as logger: d = service.try_download() self.assertEqual(None, extract_result(d)) self.assertDocTestMatches( "Failed to download images: " "Such a shame I can't divide by zero", maaslog.output) self.assertDocTestMatches( """\ Downloading images failed. Traceback (most recent call last): Failure: builtins.ZeroDivisionError: Such a shame ... """, logger.output)
def test_partial_predicate(self, logger): """ Predicate can be a functools.partial function. """ result = object() def check(): return result predicate = partial(check) clock = Clock() d = loop_until(clock, predicate) self.assertEqual(self.successResultOf(d), result) [action] = LoggedAction.of_type(logger.messages, LOOP_UNTIL_ACTION) assertContainsFields(self, action.start_message, { 'predicate': predicate, }) assertContainsFields(self, action.end_message, { 'action_status': 'succeeded', 'result': result, })
def build_control_amp_service(test_case, reactor=None): """ Create a new ``ControlAMPService``. :param TestCase test_case: The test this service is for. :return ControlAMPService: Not started. """ if reactor is None: reactor = Clock() cluster_state = ClusterStateService(reactor) cluster_state.startService() test_case.addCleanup(cluster_state.stopService) persistence_service = ConfigurationPersistenceService( reactor, test_case.make_temporary_directory()) persistence_service.startService() test_case.addCleanup(persistence_service.stopService) return ControlAMPService( reactor, cluster_state, persistence_service, TCP4ServerEndpoint(MemoryReactor(), 1234), # Easiest TLS context factory to create: ClientContextFactory(), )
def test_glass_from_sand_on_wood(self): """ Crafting one glass, from one sand, using one wood, should take 15s. """ # Patch the clock. clock = Clock() self.tile.burning.clock = clock self.tile.inventory.fuel[0] = Slot(blocks['wood'].slot, 0, 1) self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 1) self.tile.changed(self.factory, coords) # Pump the clock. Burn time is 15s. clock.pump([0.5] * 30) self.assertEqual(self.factory.world.chunk.states[0], blocks["burning-furnace"].slot) # it was started... self.assertEqual(self.factory.world.chunk.states[1], blocks["furnace"].slot) # ...and stopped at the end self.assertEqual(self.tile.inventory.fuel[0], None) self.assertEqual(self.tile.inventory.crafting[0], None) self.assertEqual(self.tile.inventory.crafted[0], (blocks['glass'].slot, 0, 1))
def test_scenario_succeeds_when_rate_has_tolerated_drop(self, _logger): """ ``read_request_load_scenario`` succeeds even if the rate drops, if it is within the tolerance percentage. Establish the requested rate by having the ``FakeFlockerClient`` respond to all requests, then lower the rate by dropping alternate requests. """ c = Clock() cluster = self.make_cluster(RequestDroppingFakeFlockerClient) sample_size = 5 s = read_request_load_scenario(c, cluster, sample_size=sample_size, tolerance_percentage=0.6) cluster.get_control_service(c).drop_requests = True d = s.start() s.maintained().addBoth(lambda x: self.fail()) d.addCallback(lambda ignored: s.stop()) # Generate enough samples to finish the scenario c.pump(repeat(1, sample_size*s.request_rate)) self.successResultOf(d)
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_late_succeed(self): m = mock_manager() m.allocate_subchannel_id = mock.Mock(return_value=0) hostaddr = _WormholeAddress() peeraddr = _SubchannelAddress(0) eq = EventualQueue(Clock()) ep = SubchannelConnectorEndpoint(m, hostaddr, eq) ep._main_channel_ready() f = mock.Mock() p = mock.Mock() t = mock.Mock() f.buildProtocol = mock.Mock(return_value=p) with mock.patch("wormhole._dilation.subchannel.SubChannel", return_value=t) as sc: d = ep.connect(f) eq.flush_sync() self.assertIdentical(self.successResultOf(d), p) self.assertEqual(f.buildProtocol.mock_calls, [mock.call(peeraddr)]) self.assertEqual(sc.mock_calls, [mock.call(0, m, hostaddr, peeraddr)]) self.assertEqual(t.mock_calls, [mock.call._set_protocol(p)]) self.assertEqual(p.mock_calls, [mock.call.makeConnection(t)])
def test_starting_and_stopping(self): deferToDatabase = self.patch(publication, "deferToDatabase") utcnow = patch_utcnow(self) cutoff = utcnow.replace(tzinfo=UTC) - timedelta(days=7) dnsgc = publication.DNSPublicationGarbageService() dnsgc.clock = clock = Clock() dnsgc.startService() self.assertTrue(dnsgc.running) self.assertTrue(dnsgc._loop.running) self.assertThat(deferToDatabase, MockNotCalled()) self.assertThat(dnsgc._loop.interval, IsExpectedInterval) clock.advance(dnsgc._loop.interval) self.assertThat(deferToDatabase, MockCalledOnceWith(dnsgc._collectGarbage, cutoff)) self.assertThat(dnsgc._loop.interval, IsExpectedInterval) dnsgc.stopService() self.assertFalse(dnsgc.running) self.assertFalse(dnsgc._loop.running)
def test_early_fail(self): m = mock_manager() m.allocate_subchannel_id = mock.Mock(return_value=0) hostaddr = _WormholeAddress() eq = EventualQueue(Clock()) ep = SubchannelConnectorEndpoint(m, hostaddr, eq) f = mock.Mock() p = mock.Mock() t = mock.Mock() f.buildProtocol = mock.Mock(return_value=p) with mock.patch("wormhole._dilation.subchannel.SubChannel", return_value=t) as sc: d = ep.connect(f) eq.flush_sync() self.assertNoResult(d) ep._main_channel_failed(Failure(CannotDilateError())) eq.flush_sync() self.failureResultOf(d).check(CannotDilateError) self.assertEqual(f.buildProtocol.mock_calls, []) self.assertEqual(sc.mock_calls, []) self.assertEqual(t.mock_calls, [])
def test_late_fail(self): # dilation is abandoned, then ep.connect() is called scid0 = 0 peeraddr = _SubchannelAddress(scid0) sc0 = mock.Mock() alsoProvides(sc0, ISubChannel) eq = EventualQueue(Clock()) ep = ControlEndpoint(peeraddr, sc0, eq) ep._main_channel_failed(Failure(CannotDilateError())) f = mock.Mock() p = mock.Mock() f.buildProtocol = mock.Mock(return_value=p) d = ep.connect(f) eq.flush_sync() self.failureResultOf(d).check(CannotDilateError) self.assertEqual(f.buildProtocol.mock_calls, []) self.assertEqual(sc0.mock_calls, []) d = ep.connect(f) self.failureResultOf(d, SingleUseEndpointError)
def test_returnAsynchronousDeferred(self): """ If the greenlet does switch, the Deferred will fire only when the greenlet has returned. """ clock = Clock() events = [] @deferredGreenlet def waity(): events.append("prewait") wait(3, clock) result = [] d = waity() d.addCallback(result.append) # Make sure the deferred has *not* fired yet... self.assertEquals(result, []) # But the greenlet *has* been started self.assertEquals(events, ["prewait"]) clock.advance(3) self.assertEquals(result, [None])
def test_late_succeed(self): # dilation can proceed, then ep.connect() is called scid0 = 0 peeraddr = _SubchannelAddress(scid0) sc0 = mock.Mock() alsoProvides(sc0, ISubChannel) eq = EventualQueue(Clock()) ep = ControlEndpoint(peeraddr, sc0, eq) ep._main_channel_ready() f = mock.Mock() p = mock.Mock() f.buildProtocol = mock.Mock(return_value=p) d = ep.connect(f) eq.flush_sync() self.assertIdentical(self.successResultOf(d), p) self.assertEqual(f.buildProtocol.mock_calls, [mock.call(peeraddr)]) self.assertEqual(sc0.mock_calls, [mock.call._set_protocol(p)]) self.assertEqual(p.mock_calls, [mock.call.makeConnection(sc0)]) d = ep.connect(f) self.failureResultOf(d, SingleUseEndpointError)
def make_outbound(): m = mock.Mock() alsoProvides(m, IDilationManager) clock = Clock() eq = EventualQueue(clock) term = mock.Mock(side_effect=lambda: True) # one write per Eventual tick def term_factory(): return term coop = Cooperator(terminationPredicateFactory=term_factory, scheduler=eq.eventually) o = Outbound(m, coop) c = mock.Mock() # Connection def maybe_pause(r): if isinstance(r, Pauser): o.pauseProducing() elif isinstance(r, Stopper): o.subchannel_unregisterProducer(r.sc) c.send_record = mock.Mock(side_effect=maybe_pause) o._test_eq = eq o._test_term = term return o, m, c
def test_logWaits(self): """ CommonStoreTransactionMonitor logs waiting transactions. """ c = Clock() self.patch(CommonStoreTransactionMonitor, "callLater", c.callLater) # Patch config to turn on log waits then rebuild the store self.patch(self.store, "logTransactionWaits", 1) ctr = [0] def counter(*args, **kwargs): ctr[0] += 1 self.patch(log, "error", counter) txn = self.transactionUnderTest() c.advance(2) self.assertNotEqual(ctr[0], 0) txn.abort()
def test_sessions_created_all_have_integer_tenant_ids(self): """ Sessions created by :class:`SessionStore.session_for_username_password`, :class:`SessionStore.session_for_impersonation`, :class:`SessionStore.session_for_api_key`, and :class:`SessionStore.session_for_token`, when not passed a specific tenant ID, all generate integer-style tenant IDs. """ clock = Clock() sessions = SessionStore(clock) sessions = [ sessions.session_for_username_password("someuser1", "testpass"), sessions.session_for_impersonation("someuser2", 12), sessions.session_for_api_key("someuser3", "someapikey"), sessions.session_for_token("sometoken"), ] integer = re.compile('^\d+$') for session in sessions: self.assertIsNot( integer.match(session.tenant_id), None, "{0} is not an integer.".format(session.tenant_id)) self.assertTrue(int(session.tenant_id) < 1e15)
def test_reports_neighbours_to_region(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateInterfaces, region.ReportNeighbours ) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, ) neighbours = [{"ip": factory.make_ip_address()}] yield service.reportNeighbours(neighbours) self.assertThat( protocol.ReportNeighbours, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent, neighbours=neighbours, ), )
def test_stopServiceWhileRestarting(self): """ Calling L{ClientService.stopService} after calling a reconnection attempt returns a L{Deferred} that fires when the disconnection has completed. """ clock = Clock() cq, service = self.makeReconnector(fireImmediately=False, clock=clock) # The protocol connects cq.connectQueue[0].callback(None) # The protocol begins disconnecting firstStopDeferred = service.stopService() # The protocol begins reconnecting service.startService() # The protocol begins disconnecting again secondStopDeferred = service.stopService() # The protocol is disconnected cq.constructedProtocols[0].connectionLost(Failure(IndentationError())) self.successResultOf(firstStopDeferred) self.successResultOf(secondStopDeferred)
def test_worker_stopped_after_required_executions(num_executions): # Control time clock = Clock() worker = MagicMock() worktracker = WorkTrackerTrackExecutions(clock=clock, num_executions_before_stop=num_executions, worker=worker) def start(): worktracker.start() d = threads.deferToThread(start) def advance_one_cycle(_): clock.advance(WorkTrackerBase.INTERVAL_CEIL) for i in range(10): d.addCallback(advance_one_cycle) yield d assert worktracker.executions_when_stopped == num_executions assert worktracker.executions >= num_executions
def test_push_writes_filesystem(self): """ Pushing a locally-owned volume writes its filesystem to the remote process. """ pool = FilesystemStoragePool(FilePath(self.mktemp())) service = VolumeService(FilePath(self.mktemp()), pool, reactor=Clock()) service.startService() volume = self.successResultOf(service.create(MY_VOLUME)) filesystem = volume.get_filesystem() filesystem.get_path().child(b"foo").setContent(b"blah") with filesystem.reader() as reader: data = reader.read() node = FakeNode([ # Hard-code the knowledge that first `flocker-volume snapshots` is # run. It doesn't need to produce any particular output for this # test, it just needs to not fail. b"", ]) self.successResultOf(service.push(volume, RemoteVolumeManager(node))) self.assertEqual(node.stdin.read(), data)
def test_printProgressBarReporting(self): """ L{StdioClient._printProgressBar} prints a progress description, including percent done, amount transferred, transfer rate, and time remaining, all based the given start time, the given L{FileWrapper}'s progress information and the reactor's current time. """ # Use a short, known console width because this simple test doesn't # need to test the console padding. self.setKnownConsoleSize(10, 34) clock = self.client.reactor = Clock() wrapped = BytesIO(b"x") wrapped.name = b"sample" wrapper = cftp.FileWrapper(wrapped) wrapper.size = 1024 * 10 startTime = clock.seconds() clock.advance(2.0) wrapper.total += 4096 self.client._printProgressBar(wrapper, startTime) result = b"\rb'sample' 40% 4.0kB 2.0kBps 00:03 " self.assertEqual(self.client.transport.value(), result)
def test_calculates_times_with_reference_to_current_time(self): # Take control of time. clock = Clock() gen_retries = utils.retries(5, 2, time=clock.seconds) # No time has passed, 5 seconds remain, and it suggests sleeping # for 2 seconds. self.assertRetry(clock, next(gen_retries), 0, 5, 2) # Mimic sleeping for 4 seconds, more than the suggested. clock.advance(4) # Now 4 seconds have passed, 1 second remains, and it suggests # sleeping for just 1 more second. self.assertRetry(clock, next(gen_retries), 4, 1, 1) # Don't sleep, ask again immediately, and the same answer is given. self.assertRetry(clock, next(gen_retries), 4, 1, 1) # Mimic sleeping for 100 seconds, much more than the suggested. clock.advance(100) # There's always a final chance to try something, but the elapsed and # remaining figures are still calculated with reference to the current # time. The wait time never goes below zero. self.assertRetry(clock, next(gen_retries), 104, -99, 0) # All done. self.assertRaises(StopIteration, next, gen_retries)
def test_enumerate_skips_other_filesystems(self): """ The result of ``enumerate()`` does not include any volumes representing filesystems named outside of the Flocker naming convention (which may have been created directly by the user). """ path = FilePath(self.mktemp()) path.child(b"arbitrary stuff").makedirs() path.child(b"stuff\tarbitrary").makedirs() path.child(b"non-uuid.stuff").makedirs() pool = FilesystemStoragePool(path) service = VolumeService(FilePath(self.mktemp()), pool, reactor=Clock()) service.startService() name = VolumeName(namespace=u"mynspaces", dataset_id=u"good_volume_name") self.successResultOf(service.create(service.get(name))) volumes = list(self.successResultOf(service.enumerate())) self.assertEqual( [Volume(node_id=service.node_id, name=name, service=service)], volumes)
def create_client(self): """ Create a new ``FlockerClient`` instance pointing at a running control service REST API. :return: ``FlockerClient`` instance. """ clock = Clock() _, self.port = find_free_port() self.persistence_service = ConfigurationPersistenceService( clock, FilePath(self.mktemp())) self.persistence_service.startService() self.cluster_state_service = ClusterStateService(reactor) self.cluster_state_service.startService() self.addCleanup(self.cluster_state_service.stopService) self.addCleanup(self.persistence_service.stopService) credential_set, _ = get_credential_sets() credentials_path = FilePath(self.mktemp()) credentials_path.makedirs() api_service = create_api_service( self.persistence_service, self.cluster_state_service, TCP4ServerEndpoint(reactor, self.port, interface=b"127.0.0.1"), rest_api_context_factory( credential_set.root.credential.certificate, credential_set.control), # Use consistent fake time for API results: clock) api_service.startService() self.addCleanup(api_service.stopService) credential_set.copy_to(credentials_path, user=True) return FlockerClient(reactor, b"127.0.0.1", self.port, credentials_path.child(b"cluster.crt"), credentials_path.child(b"user.crt"), credentials_path.child(b"user.key"))
def test_entries_for_tenant_external_with_tenantid_replacement(self): """ Validate that the external API shows up in the service catalog for a given tenant and the tenant id is in the URL. """ eeapi = make_example_external_api(self, name=self.eeapi_name, set_enabled=True) tenant_id = 'some-tenant-other' ept_internal_url = "http://internal.url/v1/" + tenant_id ept_public_url = "http://public.url/v1/" + tenant_id for ept in eeapi.endpoint_templates.values(): ept.internal_url = "http://internal.url/v1/%tenant_id%" ept.public_url = "http://public.url/v1/%tenant_id%" core = MimicCore(Clock(), [eeapi]) prefix_map = {} base_uri = "http://some/random/prefix" catalog_entries = [ entry for entry in core.entries_for_tenant(tenant_id, prefix_map, base_uri) ] self.assertEqual(len(core._uuid_to_api_internal), 0) self.assertEqual(len(core._uuid_to_api_external), 1) self.assertEqual(len(catalog_entries), 1) self.assertEqual(catalog_entries[0].type, eeapi.type_key) self.assertEqual(catalog_entries[0].name, eeapi.name_key) self.assertEqual(catalog_entries[0].tenant_id, tenant_id) self.assertEqual(len(catalog_entries[0].endpoints), 1) self.assertEqual(catalog_entries[0].endpoints[0].internal_url, ept_internal_url) self.assertEqual(catalog_entries[0].endpoints[0].complete_url, ept_public_url)
def test_exits_gracefully_if_cant_report_foreign_dhcp_server(self): clock = Clock() interface_name = factory.make_name("eth") interfaces = { interface_name: { "enabled": True, "links": [{ "address": "10.0.0.1/24" }], } } maaslog = self.patch(dhcp_probe_service, "maaslog") deferToThread = self.patch(dhcp_probe_service, "deferToThread") deferToThread.side_effect = [defer.succeed(interfaces)] probe_interface = self.patch(dhcp_probe_service, "probe_interface") probe_interface.return_value = ["192.168.0.100"] protocol, connecting = self.patch_rpc_methods() self.addCleanup((yield connecting)) del protocol._commandDispatch[ region.ReportForeignDHCPServer.commandName] rpc_service = Mock() rpc_service.getClientNow.return_value = defer.succeed( getRegionClient()) service = DHCPProbeService(rpc_service, clock) yield service.startService() yield service.stopService() self.assertThat( maaslog.error, MockCalledOnceWith( "Unable to inform region of DHCP server: the region " "does not yet support the ReportForeignDHCPServer RPC " "method."), )
def test_reports_foreign_dhcp_servers_to_region(self): clock = Clock() interface_name = factory.make_name("eth") interfaces = { interface_name: { "enabled": True, "links": [{ "address": "10.0.0.1/24" }], } } protocol, connecting = self.patch_rpc_methods() self.addCleanup((yield connecting)) deferToThread = self.patch(dhcp_probe_service, "deferToThread") foreign_dhcp_ip = factory.make_ipv4_address() deferToThread.side_effect = [defer.succeed(interfaces)] probe_interface = self.patch(dhcp_probe_service, "probe_interface") probe_interface.return_value = [foreign_dhcp_ip] client = getRegionClient() rpc_service = Mock() rpc_service.getClientNow.return_value = defer.succeed(client) service = DHCPProbeService(rpc_service, clock) yield service.startService() yield service.stopService() self.assertThat( protocol.ReportForeignDHCPServer, MockCalledOnceWith( protocol, system_id=client.localIdent, interface_name=interface_name, dhcp_ip=foreign_dhcp_ip, ), )
def test_convergence_sent_state_fail_resends(self): """ If sending state to the control node fails the next iteration will send state even if the state hasn't changed. """ local_state = NodeState(hostname=u'192.0.2.123') configuration = Deployment(nodes=[to_node(local_state)]) state = DeploymentState(nodes=[local_state]) deployer = ControllableDeployer( local_state.hostname, [succeed(local_state), succeed(local_state.copy())], [no_action(), no_action()]) client = self.make_amp_client( [local_state], successes=[False], ) reactor = Clock() loop = build_convergence_loop_fsm(reactor, deployer) loop.receive( _ClientStatusUpdate(client=client, configuration=configuration, state=state)) reactor.advance(1.0) # Calculating actions happened, result was run... and then we did # whole thing again: self.assertTupleEqual( (deployer.calculate_inputs, client.calls), ( # Check that the loop has run twice [(local_state, configuration, state), (local_state, configuration, state)], # And that state was re-sent even though it remained unchanged [(NodeStateCommand, dict(state_changes=(local_state, ))), (NodeStateCommand, dict(state_changes=(local_state, )))], ))
def test_download_is_initiated_in_new_thread(self): clock = Clock() maas_meta_last_modified = self.patch(tftppath, "maas_meta_last_modified") one_week = timedelta(minutes=15).total_seconds() maas_meta_last_modified.return_value = clock.seconds() - one_week http_proxy = factory.make_simple_http_url() https_proxy = factory.make_simple_http_url() rpc_client = Mock() client_call = Mock() client_call.side_effect = [ defer.succeed(dict(sources=sentinel.sources)), defer.succeed( dict(http=urlparse(http_proxy), https=urlparse(https_proxy))), ] rpc_client.getClientNow.return_value = defer.succeed(client_call) rpc_client.maas_url = factory.make_simple_http_url() # We could patch out 'import_boot_images' instead here but I # don't do that for 2 reasons: # 1. It requires spinning the reactor again before being able to # test the result. # 2. It means there's no thread to clean up after the test. deferToThread = self.patch(boot_images, "deferToThread") deferToThread.return_value = defer.succeed(None) service = ImageDownloadService(rpc_client, sentinel.tftp_root, clock) service.startService() self.assertThat( deferToThread, MockCalledOnceWith( _run_import, sentinel.sources, rpc_client.maas_url, http_proxy=http_proxy, https_proxy=https_proxy, ), )