def test_mismatched_request_causes_failure(self): """ If a request is made that is not expected as the next request, causes a failure. """ sequence = RequestSequence( [ ( (b"get", "https://anything/", {b"1": [b"2"]}, HasHeaders({b"1": [b"1"]}), b"what"), (418, {}, b"body"), ), ((b"get", "http://anything", {}, HasHeaders({b"2": [b"1"]}), b"what"), (202, {}, b"deleted")), ], async_failure_reporter=self.async_failures.append, ) stub = StubTreq(StringStubbingResource(sequence)) get = partial(stub.get, "https://anything?1=2", data=b"what", headers={b"1": b"1"}) resp = self.successResultOf(get()) self.assertEqual(418, resp.code) self.assertEqual(b"body", self.successResultOf(stub.content(resp))) self.assertEqual([], self.async_failures) resp = self.successResultOf(get()) self.assertEqual(500, resp.code) self.assertEqual(1, len(self.async_failures)) self.assertIn("Expected the next request to be", self.async_failures[0]) self.assertFalse(sequence.consumed())
def test_consume_context_manager_fails_on_remaining_requests(self): """ If the `consume` context manager is used, if there are any remaining expecting requests, the test case will be failed. """ sequence = RequestSequence( [((ANY, ANY, ANY, ANY, ANY), (418, {}, 'body'))] * 2, async_failure_reporter=self.async_failures.append) stub = StubTreq(StringStubbingResource(sequence)) consume_failures = [] with sequence.consume(sync_failure_reporter=consume_failures.append): self.successResultOf(stub.get('https://anything', data='what', headers={'1': '1'})) self.assertEqual(1, len(consume_failures)) self.assertIn( "Not all expected requests were made. Still expecting:", consume_failures[0]) self.assertIn( "{0}(url={0}, params={0}, headers={0}, data={0})".format( repr(ANY)), consume_failures[0]) # no asynchronous failures (mismatches, etc.) self.assertEqual([], self.async_failures)
def test_content_type(self): client = StubTreq(StaticResource(content=b'hello', content_type='text/plain')) response = self.successResultOf(client.get('http://an.example/')) self.assertEqual(200, response.code) self.assertEqual([b'text/plain'], response.headers.getRawHeaders(b'Content-Type')) body = self.successResultOf(response.content()) self.assertEqual(b'hello', body)
def test_providing_resource_to_stub_treq(self): """ The resource provided to StubTreq responds to every request no matter what the URI or parameters or data. """ verbs = ("GET", "PUT", "HEAD", "PATCH", "DELETE", "POST") urls = ( "http://supports-http.com", "https://supports-https.com", "http://this/has/a/path/and/invalid/domain/name", "https://supports-https.com:8080", "http://supports-http.com:8080", ) params = (None, {}, {b"page": [1]}) headers = (None, {}, {b"x-random-header": [b"value", b"value2"]}) data = (None, b"", b"some data", b'{"some": "json"}') stub = StubTreq(_StaticTestResource()) combos = ( (verb, {"url": url, "params": p, "headers": h, "data": d}) for verb in verbs for url in urls for p in params for h in headers for d in data ) for combo in combos: verb, kwargs = combo deferreds = (stub.request(verb, **kwargs), getattr(stub, verb.lower())(**kwargs)) for d in deferreds: resp = self.successResultOf(d) self.assertEqual(418, resp.code) self.assertEqual([b"teapot!"], resp.headers.getRawHeaders(b"x-teapot")) self.assertEqual(b"" if verb == "HEAD" else b"I'm a teapot", self.successResultOf(stub.content(resp)))
def test_mismatched_request_causes_failure(self): """ If a request is made that is not expected as the next request, causes a failure. """ sequence = RequestSequence( [(('get', 'https://anything/', {'1': ['2']}, HasHeaders({'1': ['1']}), 'what'), (418, {}, 'body')), (('get', 'http://anything', {}, HasHeaders({'2': ['1']}), 'what'), (202, {}, 'deleted'))], async_failure_reporter=self.async_failures.append) stub = StubTreq(StringStubbingResource(sequence)) get = partial(stub.get, 'https://anything?1=2', data='what', headers={'1': '1'}) resp = self.successResultOf(get()) self.assertEqual(418, resp.code) self.assertEqual('body', self.successResultOf(stub.content(resp))) self.assertEqual([], self.async_failures) resp = self.successResultOf(get()) self.assertEqual(500, resp.code) self.assertEqual(1, len(self.async_failures)) self.assertIn("Expected the next request to be", self.async_failures[0]) self.assertFalse(sequence.consumed())
def test_content(self): client = StubTreq(StaticResource(content=b'abcd')) response = self.successResultOf(client.get('http://an.example/')) self.assertEqual(200, response.code) self.assertEqual([b'application/xml'], response.headers.getRawHeaders(b'Content-Type')) body = self.successResultOf(response.content()) self.assertEqual(b'abcd', body)
def test_handles_asynchronous_requests(self): """ Handle a resource returning NOT_DONE_YET. """ stub = StubTreq(_NonResponsiveTestResource()) d = stub.request('method', 'http://url', data="1234") self.assertNoResult(d) d.cancel() self.failureResultOf(d, ResponseFailed)
def test_handles_invalid_schemes(self): """ Invalid URLs errback with a :obj:`SchemeNotSupported` failure, and does so even after a successful request. """ stub = StubTreq(_StaticTestResource()) self.failureResultOf(stub.get(""), SchemeNotSupported) self.successResultOf(stub.get("http://url.com")) self.failureResultOf(stub.get(""), SchemeNotSupported)
def test_handles_failing_asynchronous_requests(self): """ Handle a resource returning NOT_DONE_YET and then canceling the request. """ stub = StubTreq(_NonResponsiveTestResource()) d = stub.request("method", "http://url", data=b"1234") self.assertNoResult(d) d.cancel() self.failureResultOf(d, ResponseFailed)
def test_match(self): client = StubTreq(StaticEtagResource(b'abcd', b'"abcd"')) response = self.successResultOf(client.get('http://an.example/', headers={ 'if-none-match': ['"abcd"'], })) self.assertEqual(304, response.code) self.assertEqual(['application/xml'], response.headers.getRawHeaders('Content-Type')) self.assertEqual(['"abcd"'], response.headers.getRawHeaders('Etag')) body = self.successResultOf(response.content()) self.assertEqual(b'', body)
def test_handles_successful_asynchronous_requests_with_streaming(self): """ Handle a resource returning NOT_DONE_YET and then streaming data back gradually over time. """ rsrc = _EventuallyResponsiveTestResource() stub = StubTreq(rsrc) d = stub.request("method", "http://example.com/", data="1234") self.assertNoResult(d) chunks = [] rsrc.stored_request.write(b"spam ") rsrc.stored_request.write(b"eggs") stub.flush() resp = self.successResultOf(d) d = stub.collect(resp, chunks.append) self.assertNoResult(d) self.assertEqual(b"".join(chunks), b"spam eggs") del chunks[:] rsrc.stored_request.write(b"eggs\r\nspam\r\n") stub.flush() self.assertNoResult(d) self.assertEqual(b"".join(chunks), b"eggs\r\nspam\r\n") rsrc.stored_request.finish() stub.flush() self.successResultOf(d)
def test_no_match(self): client = StubTreq(StaticLastModifiedResource( content=b'abcd', last_modified=u'Mon, 6 Feb 2017 00:00:00 GMT', )) response = self.successResultOf(client.get('http://an.example/')) self.assertEqual(200, response.code) self.assertEqual([u'Mon, 6 Feb 2017 00:00:00 GMT'], response.headers.getRawHeaders(u'Last-Modified')) body = self.successResultOf(response.content()) self.assertEqual(b'abcd', body)
def test_passing_in_strange_data_is_rejected(self): """ StubTreq rejects data that isn't list/dictionary/tuple/bytes/unicode. """ stub = StubTreq(_StaticTestResource()) self.assertRaises(AssertionError, stub.request, "method", "http://url", data=object()) self.successResultOf(stub.request("method", "http://url", data={})) self.successResultOf(stub.request("method", "http://url", data=[])) self.successResultOf(stub.request("method", "http://url", data=())) self.successResultOf(stub.request("method", "http://url", data=binary_type(b""))) self.successResultOf(stub.request("method", "http://url", data=text_type("")))
def test_handles_successful_asynchronous_requests(self): """ Handle a resource returning NOT_DONE_YET and then later finishing the response. """ rsrc = _EventuallyResponsiveTestResource() stub = StubTreq(rsrc) d = stub.request("method", "http://example.com/", data=b"1234") self.assertNoResult(d) rsrc.stored_request.finish() stub.flush() resp = self.successResultOf(d) self.assertEqual(resp.code, 200)
def test_async_failures_logged(self): """ When no `async_failure_reporter` is passed async failures are logged by default. """ sequence = RequestSequence([]) stub = StubTreq(StringStubbingResource(sequence)) with sequence.consume(self.fail): self.successResultOf(stub.get('https://example.com')) [failure] = self.flushLoggedErrors() self.assertIsInstance(failure.value, AssertionError)
class FakeMarathonAPI(object): app = Klein() def __init__(self, marathon): self._marathon = marathon self.client = StubTreq(self.app.resource()) self.event_requests = [] self._called_get_apps = False def check_called_get_apps(self): """ Check and reset the ``_called_get_apps`` flag. """ was_called, self._called_get_apps = self._called_get_apps, False return was_called @app.route('/v2/apps', methods=['GET']) def get_apps(self, request): self._called_get_apps = True response = { 'apps': self._marathon.get_apps() } request.setResponseCode(200) write_request_json(request, response) @app.route('/v2/events', methods=['GET']) def get_events(self, request): assert (get_single_header(request.requestHeaders, 'Accept') == 'text/event-stream') request.setResponseCode(200) request.setHeader('Content-Type', 'text/event-stream') # Push the response headers before any events are written request.write(b'') self.client.flush() def callback(event): _write_request_event(request, event) self.client.flush() self._marathon.attach_event_stream( callback, _get_event_types(request.args), request.getClientIP()) self.event_requests.append(request) def finished_errback(failure): self._marathon.detach_event_stream(callback, request.getClientIP()) self.event_requests.remove(request) finished = request.notifyFinish() finished.addErrback(finished_errback) return finished
def test_unexpected_number_of_request_causes_failure(self): """ If there are no more expected requests, making a request causes a failure. """ sequence = RequestSequence([], async_failure_reporter=self.async_failures.append) stub = StubTreq(StringStubbingResource(sequence)) d = stub.get("https://anything", data=b"what", headers={b"1": b"1"}) resp = self.successResultOf(d) self.assertEqual(500, resp.code) self.assertEqual(1, len(self.async_failures)) self.assertIn("No more requests expected, but request", self.async_failures[0]) # the expected requests have all been made self.assertTrue(sequence.consumed())
def test_interacts_successfully_with_istub(self): """ The :obj:`IStringResponseStubs` is passed the correct parameters with which to evaluate the response, and the response is returned. """ resource = StringStubbingResource( self._get_response_for( (b"DELETE", "http://what/a/thing", {b"page": [b"1"]}, {b"x-header": [b"eh"]}, b"datastr"), (418, {b"x-response": b"responseheader"}, b"response body"), ) ) stub = StubTreq(resource) d = stub.delete("http://what/a/thing", headers={b"x-header": b"eh"}, params={b"page": b"1"}, data=b"datastr") resp = self.successResultOf(d) self.assertEqual(418, resp.code) self.assertEqual([b"responseheader"], resp.headers.getRawHeaders(b"x-response")) self.assertEqual(b"response body", self.successResultOf(stub.content(resp)))
def test_works_with_mock_any(self): """ :obj:`mock.ANY` can be used with the request parameters. """ sequence = RequestSequence( [((ANY, ANY, ANY, ANY, ANY), (418, {}, b"body"))], async_failure_reporter=self.async_failures.append ) stub = StubTreq(StringStubbingResource(sequence)) with sequence.consume(sync_failure_reporter=self.fail): d = stub.get("https://anything", data=b"what", headers={b"1": b"1"}) resp = self.successResultOf(d) self.assertEqual(418, resp.code) self.assertEqual(b"body", self.successResultOf(stub.content(resp))) self.assertEqual([], self.async_failures) # the expected requests have all been made self.assertTrue(sequence.consumed())
def test_interacts_successfully_with_istub(self): """ The :obj:`IStringResponseStubs` is passed the correct parameters with which to evaluate the response, and the response is returned. """ resource = StringStubbingResource(self._get_response_for( ('DELETE', 'http://what/a/thing', {'page': ['1']}, {'x-header': ['eh']}, 'datastr'), (418, {'x-response': 'responseheader'}, 'response body'))) stub = StubTreq(resource) d = stub.delete('http://what/a/thing', headers={'x-header': 'eh'}, params={'page': '1'}, data='datastr') resp = self.successResultOf(d) self.assertEqual(418, resp.code) self.assertEqual(['responseheader'], resp.headers.getRawHeaders('x-response')) self.assertEqual('response body', self.successResultOf(stub.content(resp)))
def test_start_responding(self, token): """ Calling ``start_responding`` makes an appropriate resource available. """ challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() challenge_resource = Resource() challenge_resource.putChild(b'acme-challenge', responder.resource) root = Resource() root.putChild(b'.well-known', challenge_resource) client = StubTreq(root) encoded_token = challenge.encode('token') challenge_url = URL(host=u'example.com', path=[ u'.well-known', u'acme-challenge', encoded_token]).asText() self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404)))) responder.start_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesAll( MatchesStructure( code=Equals(200), headers=AfterPreprocessing( methodcaller('getRawHeaders', b'content-type'), Equals([b'text/plain']))), AfterPreprocessing(methodcaller('content'), succeeded( Equals(response.key_authorization.encode('utf-8')))) ))) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(200)))) responder.stop_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404))))
def test_providing_resource_to_stub_treq(self): """ The resource provided to StubTreq responds to every request no matter what the URI or parameters or data. """ verbs = ('GET', 'PUT', 'HEAD', 'PATCH', 'DELETE', 'POST') urls = ( 'http://supports-http.com', 'https://supports-https.com', 'http://this/has/a/path/and/invalid/domain/name' 'https://supports-https.com:8080', 'http://supports-http.com:8080', ) params = (None, {}, {'page': [1]}) headers = (None, {}, {'x-random-header': ['value', 'value2']}) data = (None, "", 'some data', '{"some": "json"}') stub = StubTreq(_StaticTestResource()) combos = ( (verb, {"url": url, "params": p, "headers": h, "data": d}) for verb in verbs for url in urls for p in params for h in headers for d in data ) for combo in combos: verb, kwargs = combo deferreds = (stub.request(verb, **kwargs), getattr(stub, verb.lower())(**kwargs)) for d in deferreds: resp = self.successResultOf(d) self.assertEqual(418, resp.code) self.assertEqual(['teapot!'], resp.headers.getRawHeaders('x-teapot')) self.assertEqual("" if verb == "HEAD" else "I'm a teapot", self.successResultOf(stub.content(resp)))
def test_handles_successful_asynchronous_requests_with_response_data(self): """ Handle a resource returning NOT_DONE_YET and then sending some data in the response. """ rsrc = _EventuallyResponsiveTestResource() stub = StubTreq(rsrc) d = stub.request('method', 'http://example.com/', data=b"1234") self.assertNoResult(d) chunks = [] rsrc.stored_request.write(b'spam ') rsrc.stored_request.write(b'eggs') stub.flush() resp = self.successResultOf(d) d = stub.collect(resp, chunks.append) self.assertNoResult(d) self.assertEqual(b''.join(chunks), b'spam eggs') rsrc.stored_request.finish() stub.flush() self.successResultOf(d)
def app(tmpdir_factory, trained_nlu_model): """Use IResource interface of Klein to mock Rasa HTTP server""" _, nlu_log_file = tempfile.mkstemp(suffix="_rasa_nlu_logs.json") temp_path = tmpdir_factory.mktemp("projects") try: shutil.copytree( trained_nlu_model, os.path.join( temp_path.strpath, "{}/{}".format(KEYWORD_PROJECT_NAME, KEYWORD_MODEL_NAME), ), ) except FileExistsError: pass router = DataRouter(temp_path.strpath) rasa = RasaNLU(router, logfile=nlu_log_file, testing=True) return StubTreq(rasa.app.resource())
def test_updated_only(self): """ An Atom feed which only has entry dates from ``<updated>`` tags is interpreted as having articles with the dates according to the ``<updated>`` tags. """ feed = FetchFeed() xml = resources.read_binary("yarrharr.examples", "updated-only.atom") client = StubTreq(StaticResource(xml)) outcome = self.successResultOf(poll_feed(feed, self.clock, client)) self.assertIsInstance(outcome, MaybeUpdated) self.assertEqual( [ datetime(2017, 3, 17, tzinfo=tz.utc), datetime(2013, 1, 1, tzinfo=tz.utc), ], [article.date for article in outcome.articles], )
def simpleSessionRouter() -> Tuple[Sessions, Errors, str, str, StubTreq]: """ Construct a simple router. """ sessions = [] exceptions = [] mss = MemorySessionStore.fromAuthorizers([memoryAuthorizer]) router = Klein() token = "X-Test-Session-Token" cookie = "X-Test-Session-Cookie" sproc = SessionProcurer( mss, secureTokenHeader=b"X-Test-Session-Token", secureCookie=b"X-Test-Session-Cookie", ) @router.route("/") @inlineCallbacks def route(request: IRequest) -> Deferred: try: sessions.append((yield sproc.procureSession(request))) except NoSuchSession as nss: exceptions.append(nss) returnValue(b"ok") requirer = Requirer() @requirer.prerequisite([ISession]) def procure(request: IRequest) -> Deferred: return sproc.procureSession(request) @requirer.require(router.route("/test"), simple=Authorization(ISimpleTest)) def testRoute(simple: SimpleTest) -> str: return "ok: " + str(simple.doTest() + 4) @requirer.require(router.route("/denied"), nope=Authorization(IDenyMe)) def testDenied(nope: IDenyMe) -> str: return "bad" treq = StubTreq(router.resource()) return sessions, exceptions, token, cookie, treq
def test_passing_in_strange_data_is_rejected(self): """ StubTreq rejects data that isn't list/dictionary/tuple/bytes/unicode. """ stub = StubTreq(_StaticTestResource()) self.assertRaises( AssertionError, stub.request, 'method', 'http://url', data=object()) self.successResultOf(stub.request('method', 'http://url', data={})) self.successResultOf(stub.request('method', 'http://url', data=[])) self.successResultOf(stub.request('method', 'http://url', data=())) self.successResultOf( stub.request('method', 'http://url', data=binary_type(""))) self.successResultOf( stub.request('method', 'http://url', data=text_type("")))
def app(component_builder): """Use IResource interface of Klein to mock Rasa HTTP server. :param component_builder: :return: """ if "TRAVIS_BUILD_DIR" in os.environ: root_dir = os.environ["TRAVIS_BUILD_DIR"] else: root_dir = os.getcwd() _, nlu_log_file = tempfile.mkstemp(suffix="_rasa_nlu_logs.json") train_models(component_builder, os.path.join(root_dir, "data/examples/rasa/demo-rasa.json")) router = DataRouter(os.path.join(root_dir, "test_projects")) rasa = RasaNLU(router, logfile=nlu_log_file, testing=True) return StubTreq(rasa.app.resource())
def test_own_content_type(self): """ If an existing ``Content-Type`` header exists it is used instead of ``application/json``. """ def _response_for(method, url, params, headers, data): self.assertThat(method, Equals(u'POST')) self.assertThat(url, Equals(b'http://example.com/post_json')) self.assertThat( headers, ContainsDict( {b'Accept': Equals([b'application/json']), b'Content-Type': Equals([b'text/plain'])})) return 200, {}, json.dumps({u'arst': u'arst'}) resource = StringStubbingResource(_response_for) treq = StubTreq(resource) self.assertThat( post_json(treq.request, b'http://example.com/post_json', headers={b'Content-Type': b'text/plain'}), succeeded( Equals({u'arst': u'arst'})))
def test_magic_folder_not_ok(self, folder_name, collective_dircap, upload_dircap, good_token, bad_token): """ If the response to a request for magic folder status does not receive an HTTP OK response, ``status`` fails with ``BadResponseCode``. """ assume(collective_dircap != upload_dircap) assume(good_token != bad_token) tempdir = FilePath(self.mktemp()) node_directory = tempdir.child(u"node") node = self.useFixture(NodeDirectory(node_directory, good_token)) node.create_magic_folder( folder_name, collective_dircap, upload_dircap, tempdir.child(u"folder"), 60, ) folders = { folder_name: StubMagicFolder(), } resource = magic_folder_uri_hierarchy( folders, collective_dircap, upload_dircap, {}, {}, bad_token, ) treq = StubTreq(resource) self.assertThat( status(folder_name, node_directory, treq), failed( AfterPreprocessing( lambda f: f.value, IsInstance(BadResponseCode), ), ), )
def test_start_responding(self, token): """ Calling ``start_responding`` makes an appropriate resource available. """ challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() challenge_resource = Resource() challenge_resource.putChild(b'acme-challenge', responder.resource) root = Resource() root.putChild(b'.well-known', challenge_resource) client = StubTreq(root) encoded_token = challenge.encode('token') challenge_url = URL( host=u'example.com', path=[u'.well-known', u'acme-challenge', encoded_token]).asText() self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404)))) responder.start_responding(u'example.com', challenge, response) self.assertThat( client.get(challenge_url), succeeded( MatchesAll( MatchesStructure(code=Equals(200), headers=AfterPreprocessing( methodcaller('getRawHeaders', b'content-type'), Equals([b'text/plain']))), AfterPreprocessing( methodcaller('content'), succeeded( Equals(response.key_authorization.encode( 'utf-8'))))))) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(200)))) responder.stop_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404))))
def test_etag_200(self): """ When the ``If-None-Match`` header does not match, a 200 response is processed normally. """ feed = FetchFeed(etag=b'"abcd"') client = StubTreq(StaticEtagResource(EMPTY_RSS, '"1234"')) result = self.successResultOf(poll_feed(feed, self.clock, client)) self.assertEqual( MaybeUpdated( feed_title="Empty RSS feed", site_url="http://an.example/", etag=b'"1234"', last_modified=b"", digest=mock.ANY, articles=[], check_time=mock.ANY, ), result, )
def app(tmpdir_factory): """ This fixture makes use of the IResource interface of the Klein application to mock Rasa HTTP server. :param component_builder: :return: """ _, nlu_log_file = tempfile.mkstemp(suffix="_rasa_nlu_logs.json") _config = { 'write': nlu_log_file, 'port': -1, # unused in test app "pipeline": "keyword", "path": tmpdir_factory.mktemp("projects").strpath, "server_model_dirs": {}, "data": "./data/demo-restaurants.json", "emulate": "wit", "max_training_processes": 1 } config = RasaNLUConfig(cmdline_args=_config) rasa = RasaNLU(config, testing=True) return StubTreq(rasa.app.resource())
def test_start_responding(self): """ Calling ``start_responding`` makes an appropriate resource available. """ token = b'BWYcfxzmOha7-7LoxziqPZIUr99BCz3BfbN9kzSFnrU' challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() challenge_resource = Resource() challenge_resource.putChild(b'acme-challenge', responder.resource) root = Resource() root.putChild(b'.well-known', challenge_resource) client = StubTreq(root) encoded_token = challenge.encode('token') challenge_url = URL( host=u'example.com', path=[u'.well-known', u'acme-challenge', encoded_token]).asText() # We got page not found while the challenge is not yet active. result = yield client.get(challenge_url) self.assertEqual(404, result.code) # Once we enable the response. responder.start_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(200, result.code) self.assertEqual(['text/plain'], result.headers.getRawHeaders('content-type')) result = yield result.content() self.assertEqual(response.key_authorization.encode('utf-8'), result) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(200, result.code) yield responder.stop_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(404, result.code)
def test_store_content(self): """ Store content in a Documint session. """ def _response_for(method, url, params, headers, data): self.assertThat(method, Equals(b'POST')) self.assertThat( headers, ContainsDict({ b'Accept': Equals([b'application/json']), b'Content-Type': Equals([b'text/plain'])})) self.assertThat( url, MatchesAll( IsInstance(bytes), Equals(b'http://example.com/store'))) self.assertThat( data, MatchesAll( IsInstance(bytes), Equals(b'hello world'))) return (200, {b'Content-Type': b'application/json'}, json.dumps( {u'links': {u'self': u'http://example.com/stored_object'}})) resource = StringStubbingResource(_response_for) treq = StubTreq(resource) session = Session({u'store-content': u'http://example.com/store'}, treq.request) # XXX: This is not a real file object because `StubTreq` doesn't # implement support for that. fileobj = b'hello world' self.assertThat( session.store_content(fileobj, b'text/plain'), succeeded( Equals(u'http://example.com/stored_object')))
def test_error(self): """ Documint errors are parsed into a structured exception. """ def _response_for(method, url, params, headers, data): return (400, {b'Content-Type': b'application/json'}, json.dumps({u'causes': [ {u'type': u'foo', u'reason': 42, u'description': u'nope'}, {u'type': u'bar', u'reason': 42, u'description': None}, {u'type': u'baz', u'reason': None, u'description': None}]})) resource = StringStubbingResource(_response_for) treq = StubTreq(resource) request = documint_request_factory(treq.request) def cause(t, r=None, d=None): return MatchesStructure(type=Equals(t), reason=Equals(r), description=Equals(d)) self.assertThat( request(b'GET', b'http://example.com/error'), failed( AfterPreprocessing( lambda f: f.value, MatchesAll( IsInstance(DocumintError), MatchesStructure( causes=MatchesListwise([ cause(u'foo', 42, u'nope'), cause(u'bar', 42), cause(u'baz')]))))))
def test_handles_successful_asynchronous_requests_with_response_data(self): """ Handle a resource returning NOT_DONE_YET and then sending some data in the response. """ rsrc = _EventuallyResponsiveTestResource() stub = StubTreq(rsrc) d = stub.request('method', 'http://example.com/', data="1234") self.assertNoResult(d) chunks = [] rsrc.stored_request.write('spam ') rsrc.stored_request.write('eggs') stub.flush() resp = self.successResultOf(d) d = stub.collect(resp, chunks.append) self.assertNoResult(d) self.assertEqual(''.join(chunks), 'spam eggs') rsrc.stored_request.finish() stub.flush() self.successResultOf(d)
def test_status( self, folder_name, collective_dircap, upload_dircap, token, local_file, upload_items, download_items, ): """ ``status`` returns a ``Deferred`` that fires with a ``Status`` instance reflecting the status of the identified magic folder. """ assume(collective_dircap != upload_dircap) tempdir = FilePath(self.mktemp()) node_directory = tempdir.child(u"node") node = self.useFixture(NodeDirectory(node_directory, token)) local_folder = tempdir.child(u"folder") local_folder.makedirs() node.create_magic_folder( folder_name, collective_dircap, upload_dircap, local_folder, 60, ) local_files = { u"foo": ["filenode", local_file], } remote_files = { u"participant-name": local_files, } folders = { folder_name: StubMagicFolder( uploader=StubQueue(upload_items), downloader=StubQueue(download_items), ), } treq = StubTreq( magic_folder_uri_hierarchy( folders, collective_dircap, upload_dircap, local_files, remote_files, token, )) self.assertThat( status(folder_name, node_directory, treq), succeeded( Equals( Status( folder_name=folder_name, local_files=local_files, remote_files=remote_files, folder_status=list( status_for_item(kind, item) for (kind, items) in [ ("upload", upload_items), ("download", download_items), ] for item in items), )), ), )
def patch_deps(self, monkeypatch): monkeypatch.setattr('treq_kerberos.treq', StubTreq(FakeTestResource())) monkeypatch.setattr('treq_kerberos.kerberos', FakeKerberos())
def __init__(self, marathon): self._marathon = marathon self.client = StubTreq(self.app.resource()) self.event_requests = [] self._called_get_apps = False
class TestMarathonAcmeServer(object): def setup_method(self): self.responder_resource = Resource() self.server = MarathonAcmeServer(self.responder_resource) self.client = StubTreq(self.server.app.resource()) def test_responder_resource_empty(self): """ When a GET request is made to the ACME challenge path, but the responder resource is empty, a 404 response code should be returned. """ response = self.client.get( 'http://localhost/.well-known/acme-challenge/foo') assert_that(response, succeeded(MatchesStructure(code=Equals(404)))) def test_responder_resource_child(self): """ When a GET request is made to the ACME challenge path, and the responder resource has a child resource at the correct path, the value of the resource should be returned. """ self.responder_resource.putChild(b'foo', Data(b'bar', 'text/plain')) response = self.client.get( 'http://localhost/.well-known/acme-challenge/foo') assert_that( response, succeeded( MatchesAll( MatchesStructure(code=Equals(200), headers=HasHeader('Content-Type', ['text/plain'])), After(methodcaller('content'), succeeded(Equals(b'bar')))))) # Sanity check that a request to a different subpath does not succeed response = self.client.get( 'http://localhost/.well-known/acme-challenge/baz') assert_that(response, succeeded(MatchesStructure(code=Equals(404)))) def test_health_healthy(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is healthy, a 200 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(True, {'message': "I'm 200/OK!"})) response = self.client.get('http://localhost/health') assert_that( response, succeeded( MatchesAll( IsJsonResponseWithCode(200), After(json_content, succeeded(Equals({'message': "I'm 200/OK!"})))))) def test_health_unhealthy(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is unhealthy, a 503 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(False, {'error': "I'm sad :("})) response = self.client.get('http://localhost/health') assert_that( response, succeeded( MatchesAll( IsJsonResponseWithCode(503), After(json_content, succeeded(Equals({'error': "I'm sad :("})))))) def test_health_handler_unset(self): """ When a GET request is made to the health endpoint, and the health handler hasn't been set, a 501 status code should be returned together with a JSON message that explains that the handler is not set. """ response = self.client.get('http://localhost/health') assert_that( response, succeeded( MatchesAll( IsJsonResponseWithCode(501), After( json_content, succeeded( Equals({ 'error': 'Cannot determine service health: no handler set' })))))) def test_health_handler_unicode(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is unhealthy, a 503 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(False, {'error': u"I'm sad 🙁"})) response = self.client.get('http://localhost/health') assert_that( response, succeeded( MatchesAll( IsJsonResponseWithCode(503), After(json_content, succeeded(Equals({'error': u"I'm sad 🙁"}))))))
def setUp(self): # prepare the authentication systems self.userdb = cred.InMemoryUnicodeUsernamePasswordDatabase() self.sitedb = cred.InMemoryUnicodeUsernamePasswordDatabase() self.userrealm = TestUserRealm() self.siterealm = TestSiteRealm() self.userportal = portal.Portal(self.userrealm) self.siteportal = portal.Portal(self.siterealm) self.userportal.registerChecker(self.userdb) self.siteportal.registerChecker(self.sitedb) # register tokens self.sitedb.addUser( self.SITE_A_TOKEN, self.SITE_A_SECRET, ) self.siterealm.register_csauth_perm( self.SITE_A_TOKEN, TestWebAuthPermission( self.SITE_A_NAME, "http://{}/login".format(self.WEB_NAME), full_username=True, ), ) self.sitedb.addUser( self.SITE_B_TOKEN, self.SITE_B_SECRET, ) self.siterealm.register_csauth_perm( self.SITE_B_TOKEN, TestWebAuthPermission( self.SITE_B_NAME, "http://{}/bpage".format(self.WEB_NAME), full_username=False, ), ) # register Users self.userdb.addUser( self.USER_A_NAME, self.USER_A_PSWD, ) self.userdb.addUser( self.USER_B_NAME, self.USER_B_PSWD, ) # prepare the auth site lr = BasicLoginResource() authpage = AuthResource( self.siteportal, self.userportal, lr, url=u"http://{}/auth".format(self.AUTH_NAME), ) arr = DebugResource("auth") arr.putChild(b"auth", authpage) arr.putChild(b"expire", SessionExpiringResource()) # prepare the web site lrr = DebugResource("web") # add the login page loginpage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_A_TOKEN, self.SITE_A_SECRET, ) lrr.putChild(b"login", loginpage) # add a login page with a different permission bpage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_B_TOKEN, self.SITE_B_SECRET, ) lrr.putChild(b"bpage", bpage) # add a resource with an invalid token/secret combination invalidepage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_A_TOKEN, self.SITE_B_SECRET, # <- site B secret ) lrr.putChild(b"invalid", invalidepage) # create and install treq stubs supersite = NameVirtualHost() supersite.addHost(self.AUTH_NAME.encode("ascii"), arr) supersite.addHost(self.WEB_NAME.encode("ascii"), lrr) supersite.default = DebugResource("default") self.treq = StubTreq(supersite) loginpage._set_request_dispatcher(self.treq) bpage._set_request_dispatcher(self.treq) invalidepage._set_request_dispatcher(self.treq)
def setup_method(self): self.responder_resource = Resource() self.server = MarathonAcmeServer(self.responder_resource) self.client = StubTreq(self.server.app.resource())
def setUp(self): service = StubFeed({URL.from_text(feed._source).host.encode('ascii'): make_xml(feed) for feed in FEEDS}) treq = StubTreq(service.resource()) self.retriever = FeedRetrieval(treq=treq)
def app(core_server): """This fixture makes use of the IResource interface of the Klein application to mock Rasa Core server.""" return StubTreq(core_server.app.resource())
def test_api_error(self): """ An error is reported if the API reports an error """ stdout = StringIO() stderr = StringIO() basedir = FilePath(self.mktemp()) global_config = create_global_configuration( basedir, "tcp:-1", FilePath(u"/no/tahoe/node-directory"), "tcp:127.0.0.1:-1", ) # 2-tuples of "expected request" and the corresponding reply request_sequence = RequestSequence([ # ((method, url, params, headers, data), (code, headers, body)), ( (b"post", self.url.child("magic-folder", "default", "snapshot").to_text(), {b"path": [b"foo"]}, { b'Host': [b'invalid.'], b'Content-Length': [b'0'], b'Connection': [b'close'], b'Authorization': [b'Bearer ' + global_config.api_token], b'Accept-Encoding': [b'gzip'] }, b""), (406, {}, b'{"reason": "an explanation"}') ), ]) http_client = StubTreq( StringStubbingResource( request_sequence, ) ) client = create_magic_folder_client( Clock(), global_config, http_client, ) with self.assertRaises(SystemExit): with request_sequence.consume(self.fail): yield dispatch_magic_folder_api_command( ["--config", basedir.path, "add-snapshot", "--file", "foo", "--folder", "default"], stdout=stdout, stderr=stderr, client=client, ) self.assertThat( stdout.getvalue().strip(), Equals("") ) self.assertThat( json.loads(stderr.getvalue()), Equals({"reason": "an explanation"}) )
def XXXtest_add_participant(self): """ A new participant is added to a magic-folder """ stdout = StringIO() stderr = StringIO() # 2-tuples of "expected request" and the corresponding reply request_sequence = RequestSequence([ # ((method, url, params, headers, data), (code, headers, body)), ( # expected request (b"post", self.url.child("magic-folder", "default", "participants").to_text(), {}, { b'Host': [b'invalid.'], b'Content-Length': [b'149'], b'Connection': [b'close'], b'Authorization': [b'Bearer ' + self.global_config.api_token], b'Accept-Encoding': [b'gzip'] }, # XXX args, this fails because of different sorting of keys in body serialization json.dumps({ "personal_dmd": "URI:DIR2-CHK:lq34kr5sp7mnvkhce4ahl2nw4m:dpujdl7sol6xih5gzil525tormolzaucq4re7snn5belv7wzsdha:1:5:328", "author": { "name": "amaya", } }).encode("utf8"), ), # expected response (200, {}, b"{}"), ), ]) http_client = StubTreq( StringStubbingResource( request_sequence, ) ) client = create_magic_folder_client( Clock(), self.global_config, http_client, ) with request_sequence.consume(self.fail): yield dispatch_magic_folder_api_command( ["--config", self.magic_config.path, "add-participant", "--folder", "default", "--author-name", "amaya", "--personal-dmd", 'URI:DIR2-CHK:lq34kr5sp7mnvkhce4ahl2nw4m:dpujdl7sol6xih5gzil525tormolzaucq4re7snn5belv7wzsdha:1:5:328', ], stdout=stdout, stderr=stderr, client=client, ) self.assertThat( stdout.getvalue().strip(), Equals("{}") ) self.assertThat( stderr.getvalue().strip(), Equals("") )
def treq_for_folders(reactor, basedir, auth_token, folders, start_folder_services): """ Construct a ``treq``-module-alike which is hooked up to a Magic Folder service with Magic Folders like the ones given. :param reactor: A reactor to give to the ``MagicFolderService`` which will back the HTTP interface. :param FilePath basedir: A non-existant directory to create and populate with a new Magic Folder service configuration. :param unicode auth_token: The authorization token accepted by the service. :param folders: A mapping from Magic Folder names to their configurations. These are the folders which will appear to exist. :param bool start_folder_services: If ``True``, start the Magic Folder service objects. Otherwise, don't. :return: An object like the ``treq`` module. """ global_config = create_global_configuration( basedir, # Make this endpoint string and the one below parse but make them # invalid, too, because we don't want anything to start listening on # these during this set of tests. # # https://github.com/LeastAuthority/magic-folder/issues/276 u"tcp:-1", # It wants to know where the Tahoe-LAFS node directory is but we don't # have one and we don't want to invoke any functionality that requires # one. Give it something bogus. FilePath(u"/non-tahoe-directory"), u"tcp:127.0.0.1:-1", ) for name, config in folders.items(): global_config.create_magic_folder( name, config[u"magic-path"], config[u"state-path"], config[u"author"], config[u"collective-dircap"], config[u"upload-dircap"], config[u"poll-interval"], ) global_service = MagicFolderService( reactor, global_config, # Provide a TahoeClient so MagicFolderService doesn't try to look up a # Tahoe-LAFS node URL in the non-existent directory we supplied above # in its efforts to create one itself. TahoeClient(DecodedURL.from_text(u""), StubTreq(Resource())), ) if start_folder_services: # Reach in and start the individual service for the folder we're going # to interact with. This is required for certain functionality, eg # snapshot creation. We avoid starting the whole global_service # because it wants to do error-prone things like bind ports. for name in folders: global_service.get_folder_service(name).startService() return create_testing_http_client(reactor, global_config, global_service, lambda: auth_token)
class TestFeedAggregation(SynchronousTestCase): def setUp(self): service = StubFeed({URL.from_text(feed._source).host.encode('ascii'): make_xml(feed) for feed in FEEDS}) treq = StubTreq(service.resource()) urls = [feed._source for feed in FEEDS] retriever = FeedRetrieval(treq) self.client = StubTreq(FeedAggregation(retriever.retrieve, urls).resource()) @defer.inlineCallbacks def get(self, url): response = yield self.client.get(url) self.assertEqual(response.code, 200) content = yield response.content() defer.returnValue(content) def test_render_HTML(self): content = self.successResultOf(self.get(u'http://test.invalid/')) parsed = html.fromstring(content) self.assertEqual( parsed.xpath(u'/html/body/div/table/tr/th/a/text()'), [u'First feed', u'Second feed'] ) self.assertEqual( parsed.xpath(u'/html/body/div/table/tr/th/a/@href'), [u'http://feed-1/', u'http://feed-2/'] ) self.assertEqual( parsed.xpath(u'/html/body/div/table/tr/td/a/text()'), [u'First item', u'Second item'] ) self.assertEqual( parsed.xpath(u'/html/body/div/table/tr/td/a/@href'), [u'#first', u'#second'] ) def test_render_JSON(self): content = self.successResultOf( self.get(u'http://test.invalud/?json=true')) parsed = json.loads(content) self.assertEqual( parsed, { u'feeds': [ { u'title': u'First feed', u'link': u'http://feed-1/', u'items': [ { u'title': u'First item', u'link': u'#first' } ] }, { u'title': u'Second feed', u'link': u'http://feed-2/', u'items': [ { u'title': u'Second item', u'link': u'#second' } ] } ] } )
def setUp(self): service = StubFeed({URL.from_text(feed._source).host.encode('ascii'): make_xml(feed) for feed in FEEDS}) treq = StubTreq(service.resource()) urls = [feed._source for feed in FEEDS] retriever = FeedRetrieval(treq) self.client = StubTreq(FeedAggregation(retriever.retrieve, urls).resource())
def __init__(self): self.client = StubTreq(self.app.resource()) self._signalled_hup = False self._signalled_usr1 = False
class CsauthTests(unittest.TestCase): """ Tests for L{txwebutils.csauth}. """ WEB_NAME = u"web.localhost" AUTH_NAME = u"auth.localhost" SITE_A_NAME = u"Site Alpha" SITE_A_TOKEN = u"site a token" SITE_A_SECRET = u"secret for a" SITE_B_NAME = u"Site Beta" SITE_B_TOKEN = u"site B token" SITE_B_SECRET = u"secret for _b_" USER_A_NAME = u"UserA" USER_A_PSWD = u"PswdA" USER_B_NAME = u"IAmUserB" USER_B_PSWD = u"P-S-W-D_B" def setUp(self): # prepare the authentication systems self.userdb = cred.InMemoryUnicodeUsernamePasswordDatabase() self.sitedb = cred.InMemoryUnicodeUsernamePasswordDatabase() self.userrealm = TestUserRealm() self.siterealm = TestSiteRealm() self.userportal = portal.Portal(self.userrealm) self.siteportal = portal.Portal(self.siterealm) self.userportal.registerChecker(self.userdb) self.siteportal.registerChecker(self.sitedb) # register tokens self.sitedb.addUser( self.SITE_A_TOKEN, self.SITE_A_SECRET, ) self.siterealm.register_csauth_perm( self.SITE_A_TOKEN, TestWebAuthPermission( self.SITE_A_NAME, "http://{}/login".format(self.WEB_NAME), full_username=True, ), ) self.sitedb.addUser( self.SITE_B_TOKEN, self.SITE_B_SECRET, ) self.siterealm.register_csauth_perm( self.SITE_B_TOKEN, TestWebAuthPermission( self.SITE_B_NAME, "http://{}/bpage".format(self.WEB_NAME), full_username=False, ), ) # register Users self.userdb.addUser( self.USER_A_NAME, self.USER_A_PSWD, ) self.userdb.addUser( self.USER_B_NAME, self.USER_B_PSWD, ) # prepare the auth site lr = BasicLoginResource() authpage = AuthResource( self.siteportal, self.userportal, lr, url=u"http://{}/auth".format(self.AUTH_NAME), ) arr = DebugResource("auth") arr.putChild(b"auth", authpage) arr.putChild(b"expire", SessionExpiringResource()) # prepare the web site lrr = DebugResource("web") # add the login page loginpage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_A_TOKEN, self.SITE_A_SECRET, ) lrr.putChild(b"login", loginpage) # add a login page with a different permission bpage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_B_TOKEN, self.SITE_B_SECRET, ) lrr.putChild(b"bpage", bpage) # add a resource with an invalid token/secret combination invalidepage = TestLoginResource( u"http://{}/auth".format(self.AUTH_NAME), self.SITE_A_TOKEN, self.SITE_B_SECRET, # <- site B secret ) lrr.putChild(b"invalid", invalidepage) # create and install treq stubs supersite = NameVirtualHost() supersite.addHost(self.AUTH_NAME.encode("ascii"), arr) supersite.addHost(self.WEB_NAME.encode("ascii"), lrr) supersite.default = DebugResource("default") self.treq = StubTreq(supersite) loginpage._set_request_dispatcher(self.treq) bpage._set_request_dispatcher(self.treq) invalidepage._set_request_dispatcher(self.treq) @defer.inlineCallbacks def test_login_correct(self): """ Test a correct login. """ # first, GET loginpage r = yield self.treq.get(u"http://{}/login".format(self.WEB_NAME), ) cookies = r.cookies() self.assertEqual(r.code, 200) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were redirected to the auth server self.assertNotIn(six.text_type(self.WEB_NAME), pa_url) self.assertIn(six.text_type(self.AUTH_NAME), pa_url) # ensure paramters were set correctly self.assertIn(u"action=login", pa_url) self.assertIn(u"ctoken=", pa_url) # POST correct login userdata r = yield self.treq.post( pa_url, params={ u"username": self.USER_A_NAME, u"password": self.USER_A_PSWD, }, cookies=cookies, browser_like_redirects=True, ) self.assertEqual(r.code, 200) url = r.request.absoluteURI.decode("ascii") # ensure we were redirected back to webserver self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(six.text_type(self.WEB_NAME), url) # ensure content was set correctly text = yield r.text() self.assertEqual(text, self.USER_A_NAME) # ensure cookies will keep us logged in cr = yield self.treq.get( u"http://{}/login".format(self.WEB_NAME), cookies=cookies, ) url = cr.request.absoluteURI.decode("ascii") self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(six.text_type(self.WEB_NAME), url) # expire session er = yield self.treq.get( u"http://{}/expire".format(self.AUTH_NAME), cookies=cookies, ) self.assertEqual(er.code, 200) # ensure we will no longer be logged in automatically cr = yield self.treq.get( u"http://{}/login".format(self.WEB_NAME), cookies=cookies, ) url = cr.request.absoluteURI.decode("ascii") self.assertNotIn(six.text_type(self.WEB_NAME), url) self.assertIn(six.text_type(self.AUTH_NAME), url) @defer.inlineCallbacks def test_login_different_perm_correct(self): """ Test a correct login with site b, which has different permissions. """ # first, GET loginpage r = yield self.treq.get(u"http://{}/bpage".format(self.WEB_NAME), ) cookies = r.cookies() self.assertEqual(r.code, 200) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were redirected to the auth server self.assertNotIn(six.text_type(self.WEB_NAME), pa_url) self.assertIn(six.text_type(self.AUTH_NAME), pa_url) # ensure paramters were set correctly self.assertIn(u"action=login", pa_url) self.assertIn(u"ctoken=", pa_url) # POST correct login userdata # we use user b this time, so we also check whether different # users work r = yield self.treq.post( pa_url, params={ u"username": self.USER_B_NAME, u"password": self.USER_B_PSWD, }, cookies=cookies, browser_like_redirects=True, ) self.assertEqual(r.code, 200) url = r.request.absoluteURI.decode("ascii") # ensure we were redirected back to webserver self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(six.text_type(self.WEB_NAME), url) # ensure we are at the bpade self.assertIn(u"bpage", url) # ensure content was set correctly text = yield r.text() self.assertEqual(text, six.text_type(len(self.USER_B_NAME))) # ensure cookies will keep us logged in cr = yield self.treq.get( u"http://{}/bpage".format(self.WEB_NAME), cookies=cookies, ) url = cr.request.absoluteURI.decode("ascii") self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(six.text_type(self.WEB_NAME), url) self.assertIn(u"bpage", url) @defer.inlineCallbacks def test_crossite_cookies(self): """ Test that cookies will kept you logged in across sites. """ # first, GET loginpage r = yield self.treq.get(u"http://{}/login".format(self.WEB_NAME), ) cookies = r.cookies() self.assertEqual(r.code, 200) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were redirected to the auth server self.assertNotIn(six.text_type(self.WEB_NAME), pa_url) self.assertIn(six.text_type(self.AUTH_NAME), pa_url) self.assertIn(u"login", pa_url) # ensure paramters were set correctly self.assertIn(u"action=login", pa_url) self.assertIn(u"ctoken=", pa_url) # POST correct login userdata r = yield self.treq.post( pa_url, params={ u"username": self.USER_A_NAME, u"password": self.USER_A_PSWD, }, cookies=cookies, browser_like_redirects=True, ) self.assertEqual(r.code, 200) url = r.request.absoluteURI.decode("ascii") # ensure we were redirected back to webserver self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(six.text_type(self.WEB_NAME), url) # ensure content was set correctly text = yield r.text() self.assertEqual(text, self.USER_A_NAME) # GET bpage r = yield self.treq.get( u"http://{}/bpage".format(self.WEB_NAME), cookies=cookies, ) self.assertEqual(r.code, 200) url = r.request.absoluteURI.decode("ascii") # ensure we were not redirected to the auth server self.assertIn(six.text_type(self.WEB_NAME), url) self.assertNotIn(six.text_type(self.AUTH_NAME), url) self.assertIn(u"bpage", url) # ensure content is still correct # this is important, since the different sites have different # access to the userdata text = yield r.text() self.assertEqual(text, six.text_type(len(self.USER_A_NAME))) @defer.inlineCallbacks def test_login_invalid(self): """ Test an invalid login. """ # first, GET loginpage r = yield self.treq.get(u"http://{}/login".format(self.WEB_NAME), ) cookies = r.cookies() self.assertEqual(r.code, 200) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were redirected to the auth server self.assertNotIn(six.text_type(self.WEB_NAME), pa_url) self.assertIn(six.text_type(self.AUTH_NAME), pa_url) # ensure paramters were set correctly self.assertIn(u"action=login", pa_url) self.assertIn(u"ctoken=", pa_url) # POST incorrect login userdata r = yield self.treq.post( pa_url, params={ u"username": self.USER_A_NAME, u"password": self.USER_B_PSWD, # <- user b password }, cookies=cookies, browser_like_redirects=True, ) self.assertEqual(r.code, 401) url = r.request.absoluteURI.decode("ascii") # ensure we were not redirected back to webserver self.assertIn(six.text_type(self.AUTH_NAME), url) self.assertNotIn(six.text_type(self.WEB_NAME), url) # ensure a malicious request back to the webserver will fail qs = urlparse(url).query ctoken = parse_qs(qs)[u"ctoken"] r = yield self.treq.get( u"http://{}/login?action=callback&ctoken={}".format( self.WEB_NAME, ctoken, ), cookies=cookies, ) cookies = r.cookies() self.assertEqual(r.code, 200) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were redirected to the auth server self.assertNotIn(six.text_type(self.WEB_NAME), pa_url) self.assertIn(six.text_type(self.AUTH_NAME), pa_url) @defer.inlineCallbacks def test_token_secret_invalid(self): """ Test an invalid token/secret. """ # first, GET loginpage r = yield self.treq.get(u"http://{}/invalid".format(self.WEB_NAME), ) cookies = r.cookies() self.assertEqual(r.code, 500) pa_url = r.request.absoluteURI.decode("ascii") # ensure we were not redirected to the auth server self.assertIn(six.text_type(self.WEB_NAME), pa_url) self.assertNotIn(six.text_type(self.AUTH_NAME), pa_url)
class TestMarathonAcmeServer(object): def setup_method(self): self.responder_resource = Resource() self.server = MarathonAcmeServer(self.responder_resource) self.client = StubTreq(self.server.app.resource()) def test_responder_resource_empty(self): """ When a GET request is made to the ACME challenge path, but the responder resource is empty, a 404 response code should be returned. """ response = self.client.get( 'http://localhost/.well-known/acme-challenge/foo') assert_that(response, succeeded(MatchesStructure(code=Equals(404)))) def test_responder_resource_child(self): """ When a GET request is made to the ACME challenge path, and the responder resource has a child resource at the correct path, the value of the resource should be returned. """ self.responder_resource.putChild(b'foo', Data(b'bar', 'text/plain')) response = self.client.get( 'http://localhost/.well-known/acme-challenge/foo') assert_that(response, succeeded(MatchesAll( MatchesStructure( code=Equals(200), headers=HasHeader('Content-Type', ['text/plain'])), After(methodcaller('content'), succeeded(Equals(b'bar'))) ))) # Sanity check that a request to a different subpath does not succeed response = self.client.get( 'http://localhost/.well-known/acme-challenge/baz') assert_that(response, succeeded(MatchesStructure(code=Equals(404)))) def test_acme_challenge_ping(self): """ When a GET request is made to the ACME challenge path ping endpoint, a pong message should be returned. """ response = self.client.get( 'http://localhost/.well-known/acme-challenge/ping') assert_that(response, succeeded(MatchesAll( IsJsonResponseWithCode(200), After(json_content, succeeded(Equals({'message': 'pong'}))) ))) def test_health_healthy(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is healthy, a 200 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(True, {'message': "I'm 200/OK!"})) response = self.client.get('http://localhost/health') assert_that(response, succeeded(MatchesAll( IsJsonResponseWithCode(200), After(json_content, succeeded(Equals({'message': "I'm 200/OK!"}))) ))) def test_health_unhealthy(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is unhealthy, a 503 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(False, {'error': "I'm sad :("})) response = self.client.get('http://localhost/health') assert_that(response, succeeded(MatchesAll( IsJsonResponseWithCode(503), After(json_content, succeeded(Equals({'error': "I'm sad :("}))) ))) def test_health_handler_unset(self): """ When a GET request is made to the health endpoint, and the health handler hasn't been set, a 501 status code should be returned together with a JSON message that explains that the handler is not set. """ response = self.client.get('http://localhost/health') assert_that(response, succeeded(MatchesAll( IsJsonResponseWithCode(501), After(json_content, succeeded(Equals({ 'error': 'Cannot determine service health: no handler set' }))) ))) def test_health_handler_unicode(self): """ When a GET request is made to the health endpoint, and the health handler reports that the service is unhealthy, a 503 status code should be returned together with the JSON message from the handler. """ self.server.set_health_handler( lambda: Health(False, {'error': u"I'm sad 🙁"})) response = self.client.get('http://localhost/health') assert_that(response, succeeded(MatchesAll( IsJsonResponseWithCode(503), After(json_content, succeeded(Equals({'error': u"I'm sad 🙁"}))) )))