def assertWarningsEnabled(self, category): message = "%s from %s" % (category.__name__, self.package_name) with catch_warnings(record=True) as log: self.warn(message, category=category) self.assertThat( log, MatchesListwise([ MatchesStructure( message=MatchesAll( IsInstance(category), MatchesStructure.byEquality(args=(message, )), ), category=Equals(category), ) ]), )
def test_namespaced(self): """ `namespaced` creates a function that when called produces a namespaced name. """ self.assertThat( namespaced(u'foo'), MatchesAll( MatchesPredicate(callable, '%s is not callable'), After( lambda f: f(u'bar'), MatchesAll( MatchesListwise([Equals(u'foo'), Equals(u'bar')]), MatchesStructure(prefix=Equals(u'foo'), name=Equals(u'bar'))))))
def test_format_value_failures(self): """ Catch exceptions when formatting node values and display a message without interrupting the processing of tasks. List all caught exceptions to stderr. """ def bad_format_value(*a, **kw): raise ValueError('Nope') self.assertThat( self.render_tasks([message_task], format_value=bad_format_value), MatchesListwise([ Contains(u'message: <value formatting exception>'), MatchesAll( Contains(u'Traceback (most recent call last):'), Contains(u'ValueError: Nope'))]))
def test_failing_deferred_effect(self): """ A failing Deferred returned from an effect causes error handlers to be called with an exception tuple based on the failure. """ d = fail(ValueError('foo')) e = Effect(ConstantIntent(d)).on(error=lambda e: ('error', e)) result = self.successResultOf(perform(e)) self.assertThat( result, MatchesListwise( [Equals('error'), MatchesException(ValueError('foo'))])) # The traceback element is None, because we constructed the failure # without a traceback. self.assertIs(result[1][2], None)
def test_extraBuildArgs_archive_trusted_keys(self): # If the archive has a signing key, extraBuildArgs sends it. yield self.useFixture(InProcessKeyServerFixture()).start() archive = self.factory.makeArchive() key_path = os.path.join(gpgkeysdir, "*****@*****.**") yield IArchiveSigningKey(archive).setSigningKey( key_path, async_keyserver=True) job = self.makeJob(archive=archive, with_builder=True) distroarchseries = job.build.distroseries.architectures[0] self.factory.makeBinaryPackagePublishingHistory( distroarchseries=distroarchseries, pocket=job.build.pocket, archive=archive, status=PackagePublishingStatus.PUBLISHED) args = yield job.extraBuildArgs() self.assertThat(args["trusted_keys"], MatchesListwise([ Base64KeyMatches("0D57E99656BEFB0897606EE9A022DD1F5001B46D"), ]))
def test_filename_can_be_overridden(self): with temp_file_contents(b"Hello") as f: specified_file_name = self.getUniqueString() result = get_result_for([ self.option, self.test_id, '--attach-file', f.name, '--file-name', specified_file_name ]) self.assertThat( result._events, MatchesListwise([ MatchesStatusCall(call='startTestRun'), MatchesStatusCall(file_name=specified_file_name, file_bytes=b'Hello'), MatchesStatusCall(call='stopTestRun'), ]))
def test_jobs_with_retry_exceptions_are_queued_again(self): # A job that raises a retry error is automatically queued # and executed again. self.useFixture( FeatureFixture( {'jobs.celery.enabled_classes': 'TestJobWithRetryError'})) # Set scheduled_start on the job to ensure that retry delays # override it. job = TestJobWithRetryError(scheduled_start=datetime.now(UTC) + timedelta(seconds=1)) job.celeryRunOnCommit() transaction.commit() count = 0 while count < 300 and job.is_pending: # We have a maximum wait of one minute. We should not get # anywhere close to that on developer machines (10 seconds was # working fine), but when the test suite is run in parallel we # can need a lot more time (see bug 1007576). sleep(0.2) count += 1 transaction.abort() # Collect the start times recorded by the job. dates_started = [ iso8601.parse_date(d) for d in job.job.base_json_data['dates_started'] ] # The first attempt's lease is set to the end of the job, so the # second attempt should start roughly 5 seconds after the first. The # third attempt should start roughly 5 seconds after the second. self.assertThat(dates_started, HasLength(3)) self.assertThat( dates_started, MatchesListwise([ MatchesAll(), MatchesAll( GreaterThan(dates_started[0] + timedelta(seconds=4)), LessThan(dates_started[0] + timedelta(seconds=8))), MatchesAll( GreaterThan(dates_started[1] + timedelta(seconds=4)), LessThan(dates_started[1] + timedelta(seconds=8))), ])) self.assertEqual(3, job.attempt_count) self.assertEqual(JobStatus.COMPLETED, job.status)
def test__captures_stdout_after_stderr_closes(self): # Write to stderr, close stderr, then write to stdout. proc = Popen('echo -n bar >&2 && exec 2>&- && echo -n foo >&1', stdout=PIPE, stderr=PIPE, shell=True) # Capturing gets the foo even after stderr is closed. self.assertThat( self.capture(proc), MatchesListwise(( Equals(0), Equals("foo"), Equals("bar"), # The writes to stdout and stderr occur so close in time that # they may be received in any order. MatchesAny(Equals("foobar"), Equals("barfoo")), )))
def test_describe_returns_json(self): response = self.client.get(reverse("describe")) self.assertThat( ( response.status_code, response["Content-Type"], response.content, response.content, ), MatchesListwise(( Equals(http.client.OK), Equals("application/json"), StartsWith(b"{"), Contains(b"name"), )), response, )
def assertWarningsEnabled(self, category): message = "%s from %s" % (category.__name__, self.package_name) filename, ext = splitext(__file__) with catch_warnings(record=True) as log: warn(message, category=category) self.assertThat( log, MatchesListwise([ MatchesStructure( message=MatchesAll( IsInstance(category), MatchesStructure.byEquality(args=(message, )), ), category=Equals(category), filename=StartsWith(filename), ), ]))
def test_nevow_request(self): """ Rendering the resource returns a successful deferred and inserted a `NEVOW_REQUEST` value into the context. """ def _spy(res): def _spy_inner(context): res.append(context) return context return before(_spy_inner) requests = [] resource = nevow_adapter_resource([_spy(requests)]) req = fake_nevow_request() self.assertThat(resource.renderHTTP(req), succeeded(Equals(b''))) self.assertThat(requests, MatchesListwise([Contains(NEVOW_REQUEST)]))
def test_api_url(self): transformations = list( { "http://example.com/": "http://example.com/api/2.0/", "http://example.com/foo": "http://example.com/foo/api/2.0/", "http://example.com/foo/": "http://example.com/foo/api/2.0/", "http://example.com/api/7.9": "http://example.com/api/7.9/", "http://example.com/api/7.9/": "http://example.com/api/7.9/", }.items() ) urls = [url for url, url_out in transformations] urls_out = [url_out for url, url_out in transformations] expected = [ AfterPreprocessing(utils.api_url, Equals(url_out)) for url_out in urls_out ] self.assertThat(urls, MatchesListwise(expected))
def test_iterable_interceptors(self): """ Iterables have each item processed and wrapped, if necessary. The last interceptor / function's name becomes the route name. """ def func(_): return 42 trace = tracer('a') self.assertThat( route.route(u'/foo', route.GET, [trace, func]), MatchesStructure(name=Equals('func'), interceptors=MatchesListwise([ Equals(trace), EnterStage( ContainsDict({RESPONSE: Equals(42)})) ])))
def test_write_dns_config_writes_file(self): zone_names = [random.randint(1, 100), random.randint(1, 100)] command = factory.getRandomString() result = write_dns_config.delay( zone_names=zone_names, callback=rndc_command.subtask(args=[command])) self.assertThat(( result.successful(), os.path.join(self.dns_conf_dir, MAAS_NAMED_CONF_NAME), self.rndc_recorder.calls, ), MatchesListwise(( Equals(True), FileExists(), Equals([((command, ), {})]), )), result)
def test_structure_matches_strategy(self): """ The basic structure of the result returned matches the structure created by the hypothesis strategies used by other tests. """ marshalled = marshal_tahoe_configuration("", "", "", 0, 0, "", "", "", "", "", "") introducer = introducer_configuration().example() storage = storage_configuration().example() self.assertThat( [set(introducer), set(storage)], MatchesListwise([ Equals(set(marshalled["introducer"])), Equals(set(marshalled["storage"])), ]), )
def test_merge_tasks(self): """ Merge tasks into the tree and retrieve an list of key-node pairs ordered by task timestamp. """ tree = Tree() matches = tree.merge_tasks([message_task, action_task]) self.expectThat(matches, Is(None)) keys, nodes = zip(*tree.nodes()) self.expectThat( list(keys), Equals(['cdeb220d-7605-4d5f-8341-1a170222e308', 'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4'])) self.assertThat( list(_flattened_tasks(nodes)), MatchesListwise([Equals(message_task), Equals(action_task)]))
def test_merge_startless_tasks(self): """ Merging a task that will never have a start parent creates a fake start task. """ tree = Tree() missing_task = missing_start_task(action_task_end) matches = tree.merge_tasks([action_task_end]) self.expectThat(matches, Is(None)) keys, nodes = zip(*tree.nodes()) self.expectThat( list(keys), Equals(['f3a32bb3-ea6b-457c-aa99-08a3d0491ab4'])) self.assertThat( list(_flattened_tasks(nodes)), MatchesListwise([Equals(missing_task), Equals(action_task_end)]))
def test_setup_rndc_configuration_writes_files(self): command = factory.getRandomString() result = setup_rndc_configuration.delay(callback=rndc_command.subtask( args=[command])) self.assertThat(( result.successful(), os.path.join(self.dns_conf_dir, MAAS_RNDC_CONF_NAME), os.path.join(self.dns_conf_dir, MAAS_NAMED_RNDC_CONF_NAME), self.rndc_recorder.calls, ), MatchesListwise(( Equals(True), FileExists(), FileExists(), Equals([((command, ), {})]), )), result)
def test_formulate_change_as_json(self): params = {factory.make_string(): factory.make_string()} url, headers, body = make_client()._formulate_change( make_path(), params, as_json=True) observed = [ headers.get('Content-Type'), headers.get('Content-Length'), body, ] expected = [ Equals('application/json'), Equals('%d' % (len(body),)), AfterPreprocessing(json.loads, Equals(params)), ] self.assertThat(observed, MatchesListwise(expected)) data = parse_headers_and_body_with_mimer(headers, body) self.assertEqual(params, data)
def test_delete_node_also_deletes_dhcp_host_map(self): lease = factory.make_dhcp_lease() node = factory.make_node(nodegroup=lease.nodegroup) node.add_mac_address(lease.mac) mocked_task = self.patch(node_module, "remove_dhcp_host_map") mocked_apply_async = self.patch(mocked_task, "apply_async") node.delete() args, kwargs = mocked_apply_async.call_args expected = ( Equals(kwargs['queue']), Equals({ 'ip_address': lease.ip, 'server_address': "127.0.0.1", 'omapi_key': lease.nodegroup.dhcp_key, })) observed = node.work_queue, kwargs['kwargs'] self.assertThat(observed, MatchesListwise(expected))
def test_list_for_admin(self): admin = factory.make_admin() admin2 = factory.make_admin() handler = NotificationHandler(admin, {}, None) notifications = [ factory.make_Notification(user=admin), # Will match. factory.make_Notification(user=admin2), factory.make_Notification(users=True), factory.make_Notification(users=False), factory.make_Notification(admins=True), # Will match. factory.make_Notification(admins=False), ] expected = [ MatchesRenderedNotification(notifications[0]), MatchesRenderedNotification(notifications[4]), ] self.assertThat(handler.list({}), MatchesListwise(expected))
def test_list(self): user = factory.make_User() user2 = factory.make_User() handler = NotificationHandler(user, {}, None) notifications = [ factory.make_Notification(user=user), # Will match. factory.make_Notification(user=user2), factory.make_Notification(users=True), # Will match. factory.make_Notification(users=False), factory.make_Notification(admins=True), factory.make_Notification(admins=False), ] expected = [ MatchesRenderedNotification(notifications[0]), MatchesRenderedNotification(notifications[2]), ] self.assertThat(handler.list({}), MatchesListwise(expected))
def test_callback_error_exception(self): """ If a error callback raises an error, the exception is passed to the error callback. """ calls = [] intent = lambda box: box.fail( (ValueError, ValueError('dispatched'), None)) perform( func_dispatcher, Effect(intent).on( error=lambda _: raise_(ValueError("oh dear"))).on( error=calls.append)) self.assertThat( calls, MatchesListwise([MatchesException(ValueError('oh dear'))]))
def assertRetry( self, clock, observed, expected_elapsed, expected_remaining, expected_wait ): """Assert that the retry tuple matches the given expectations. Retry tuples are those returned by `retries`. """ self.assertThat( observed, MatchesListwise( [ Equals(expected_elapsed), # elapsed Equals(expected_remaining), # remaining Equals(expected_wait), # wait ] ), )
def test_logged_messages_go_to_observer(self): # Using _TwistedLogObservers means messages logged to Twisted go to # that observer while the fixture is active. from testtools.twistedsupport._runtest import _TwistedLogObservers messages = [] class SomeTest(TestCase): def test_something(self): self.useFixture(_TwistedLogObservers([messages.append])) log.msg('foo') SomeTest('test_something').run() log.msg('bar') self.assertThat( messages, MatchesListwise([ContainsDict({'message': Equals(('foo', ))})]))
def test_logging_restored(self): # _NoTwistedLogObservers restores the original log observers. from testtools.twistedsupport._runtest import _NoTwistedLogObservers class SomeTest(TestCase): def test_something(self): self.useFixture(_NoTwistedLogObservers()) log.msg('foo') def run_then_log(): SomeTest('test_something').run() log.msg('bar') _, messages = self._get_logged_messages(run_then_log) self.assertThat( messages, MatchesListwise([ContainsDict({'message': Equals(('bar', ))})]))
def test_discharge_macaroon(self): # If a discharge macaroon was requested and received, the view # returns a form that submits it to the starting URL. test_email = '*****@*****.**' person = self.factory.makePerson(email=test_email) identifier = ITestOpenIDPersistentIdentity( person.account).openid_identity_url openid_response = FakeOpenIDResponse( identifier, status=SUCCESS, message='', email=test_email, full_name='Foo User', discharge_macaroon_raw='dummy discharge') form = { 'starting_url': 'http://launchpad.dev/after-login', 'discharge_macaroon_action': 'field.actions.complete', 'discharge_macaroon_field': 'field.discharge_macaroon', } with SRegResponse_fromSuccessResponse_stubbed(): with MacaroonResponse_fromSuccessResponse_stubbed(): view, html = self._createAndRenderView(openid_response, form=form) self.assertTrue(view.login_called) self.assertEqual('dummy discharge', view.discharge_macaroon_raw) discharge_form = find_tag_by_id(html, 'discharge-form') self.assertEqual(form['starting_url'], discharge_form['action']) self.assertThat( [dict(tag.attrs) for tag in discharge_form.findAll('input')], MatchesListwise([ ContainsDict({ 'type': Equals('hidden'), 'name': Equals('field.actions.complete'), 'value': Equals('1'), }), ContainsDict({ 'type': Equals('hidden'), 'name': Equals('field.discharge_macaroon'), 'value': Equals('dummy discharge'), }), ContainsDict({ 'type': Equals('submit'), 'value': Equals('Continue'), }), ]))
def test_start_up_errors_are_logged(self): ipcWorker = MagicMock() service = RegionService(ipcWorker) # Ensure that endpoint.listen fails with a obvious error. exception = ValueError("This is not the messiah.") endpoints = self.patch(service, "endpoints", [[Mock()]]) endpoints[0][0].listen.return_value = fail(exception) logged_failures_expected = [ AfterPreprocessing((lambda failure: failure.value), Is(exception)) ] with TwistedLoggerFixture() as logger: yield service.startService() self.assertThat(logger.failures, MatchesListwise(logged_failures_expected))
def test_get_file_returning_404_file_includes_header(self): # In order to fix bug 1123986 we need to distinguish between # a 404 returned when the file is not present and a 404 returned # when the API endpoint is not present. We do this by setting # a header: "Workaround: bug1123986". response = self.client.get( reverse("file_handler", args=[factory.make_name("file")]) ) self.assertThat( (response.status_code, list(response.items())), MatchesListwise( ( Equals(http.client.NOT_FOUND), Contains(("Workaround", "bug1123986")), ) ), response, )
def test_log_to_twisted(self): # If suppress_twisted_logging is False, we log to the default Twisted # loggers. messages = [] publisher, _ = _get_global_publisher_and_observers() publisher.addObserver(messages.append) class LogSomething(TestCase): def test_something(self): log.msg("foo") test = LogSomething('test_something') runner = self.make_runner(test, suppress_twisted_logging=False) result = self.make_result() runner.run(result) self.assertThat( messages, MatchesListwise([ContainsDict({'message': Equals(('foo', ))})]))