def test_log_none_effectful_fields(self): """ When log is not passed, but there are log fields from BoundFields, the log passed to treq has those fields. """ log = mock_log() # we have to include system='otter' in the expected log here because # the code falls back to otter.log.log, which has the system key bound. expected_log = matches(IsBoundWith(bound='stuff', system='otter')) req = ('GET', 'http://google.com/', None, None, None, { 'log': expected_log }) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/") req.treq = treq req_eff = Effect(req) bound_log_eff = with_log(req_eff, bound='stuff') dispatcher = ComposedDispatcher( [get_simple_dispatcher(None), get_log_dispatcher(log, {})]) self.assertEqual( self.successResultOf(perform(dispatcher, bound_log_eff)), (response, "content"))
def test_log(self): """ The log specified in the Request is passed on to the treq implementation. """ log = object() req = ('GET', 'http://google.com/', None, None, {'log': log}) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/", log=log) req.treq = treq self.assertEqual(self.successResultOf(perform(Effect(req))), (response, "content"))
def test_perform(self): """ The Request effect dispatches a request to treq, and returns a two-tuple of the Twisted Response object and the content as bytes. """ req = ('GET', 'http://google.com/', None, None, {'log': None}) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/") req.treq = treq self.assertEqual( self.successResultOf(perform(Effect(req))), (response, "content"))
def test_throttling(self): """ When the throttler function returns a bracketing function, it's used to throttle the request. """ def throttler(stype, method, tid): if (stype == ServiceType.CLOUD_SERVERS and method == 'get' and tid == 1): return bracket bracket = object() svcreq = service_request(ServiceType.CLOUD_SERVERS, 'GET', 'servers').intent response = stub_pure_response({}, 200) seq = SequenceDispatcher([ (_Throttle(bracket=bracket, effect=mock.ANY), nested_sequence([ (Authenticate(authenticator=self.authenticator, tenant_id=1, log=self.log), lambda i: ('token', fake_service_catalog)), (Request(method='GET', url='http://dfw.openstack/servers', headers=headers('token'), log=self.log), lambda i: response), ])), ]) eff = self._concrete(svcreq, throttler=throttler) with seq.consume(): result = sync_perform(seq, eff) self.assertEqual(result, (response[0], {}))
def test_added_headers_win(self): """When merging headers together, headers from the effect win.""" request_ = add_effectful_headers(self.auth_effect, request) eff = request_('m', 'u', headers={'x-auth-token': 'fooey'}) self.assertEqual( resolve_stubs(eff).intent, Request(method="m", url="u", headers={"x-auth-token": "abc123"}))
def test_log(self): """ The log specified in the Request is passed on to the treq implementation. """ log = object() req = ('GET', 'http://google.com/', None, None, None, {'log': log}) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/", log=log) req.treq = treq dispatcher = get_simple_dispatcher(None) self.assertEqual( self.successResultOf(perform(dispatcher, Effect(req))), (response, "content"))
def test_add_headers_optional(self): """It's okay if no headers are passed.""" request_ = add_headers({'one': '1'}, request) eff = request_('m', 'u') self.assertEqual( resolve_stubs(eff).intent, Request(method='m', url='u', headers={'one': '1'}))
def test_add_headers_optional(self): """It's okay if no headers are passed.""" request_ = add_effectful_headers(self.auth_effect, request) eff = request_('m', 'u') self.assertEqual( resolve_stubs(eff).intent, Request(method='m', url='u', headers={'x-auth-token': 'abc123'}))
def test_perform(self): """ The Request effect dispatches a request to treq, and returns a two-tuple of the Twisted Response object and the content as bytes. """ req = ('GET', 'http://google.com/', None, None, None, { 'log': default_log }) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/") req.treq = treq dispatcher = get_simple_dispatcher(None) self.assertEqual( self.successResultOf(perform(dispatcher, Effect(req))), (response, "content"))
def simple_intents(): return [ Authenticate(None, None, None), InvalidateToken(None, None), Request(method='GET', url='http://example.com/'), Retry(effect=Effect(Constant(None)), should_retry=lambda e: False), Delay(0), Constant(None), ReadReference(ref=Reference(None)), ]
def test_performs_tenant_scope(self, deferred_lock_run): """ :func:`perform_tenant_scope` performs :obj:`TenantScope`, and uses the default throttler """ # We want to ensure # 1. the TenantScope can be performed # 2. the ServiceRequest is run within a lock, since it matches the # default throttling policy set_config_data({ "cloud_client": { "throttling": { "create_server_delay": 1, "delete_server_delay": 0.4 } } }) self.addCleanup(set_config_data, {}) clock = Clock() authenticator = object() log = object() dispatcher = get_cloud_client_dispatcher(clock, authenticator, log, make_service_configs()) svcreq = service_request(ServiceType.CLOUD_SERVERS, 'POST', 'servers') tscope = TenantScope(tenant_id='111', effect=svcreq) def run(f, *args, **kwargs): result = f(*args, **kwargs) result.addCallback(lambda x: (x[0], assoc(x[1], 'locked', True))) return result deferred_lock_run.side_effect = run response = stub_pure_response({}, 200) seq = SequenceDispatcher([ (Authenticate(authenticator=authenticator, tenant_id='111', log=log), lambda i: ('token', fake_service_catalog)), (Request(method='POST', url='http://dfw.openstack/servers', headers=headers('token'), log=log), lambda i: response), ]) disp = ComposedDispatcher([seq, dispatcher]) with seq.consume(): result = perform(disp, Effect(tscope)) self.assertNoResult(result) clock.advance(1) self.assertEqual(self.successResultOf(result), (response[0], { 'locked': True }))
def test_add_headers(self): """Headers from the provided effect are inserted.""" request_ = add_effectful_headers(self.auth_effect, request) eff = request_('m', 'u', headers={'default': 'headers'}) self.assertEqual( resolve_stubs(eff).intent, Request(method="m", url="u", headers={ "x-auth-token": "abc123", "default": "headers" }))
def test_log_effectful_fields(self): """ The log passed to treq is bound with the fields from BoundFields. """ log = mock_log().bind(duplicate='should be overridden') expected_log = matches(IsBoundWith(duplicate='effectful', bound='stuff')) req = ('GET', 'http://google.com/', None, None, None, {'log': expected_log}) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/", log=log) req.treq = treq req_eff = Effect(req) bound_log_eff = with_log(req_eff, bound='stuff', duplicate='effectful') dispatcher = ComposedDispatcher([ get_simple_dispatcher(None), get_log_dispatcher(log, {})]) self.assertEqual( self.successResultOf(perform(dispatcher, bound_log_eff)), (response, "content"))
def test_add_headers(self): """Headers are merged, with passed headers taking precedence.""" request_ = add_headers({'one': '1', 'two': '2'}, request) eff = request_('m', 'u', headers={'one': 'hey', 'three': '3'}) self.assertEqual( resolve_stubs(eff).intent, Request(method='m', url='u', headers={ 'one': 'hey', 'two': '2', 'three': '3' }))
def test_authenticates(self): """Auth is done before making the request.""" eff = self._concrete(self.svcreq) expected_intent = Authenticate(self.authenticator, 1, self.log) self.assertEqual(eff.intent, expected_intent) next_eff = resolve_authenticate(eff) # The next effect in the chain is the requested HTTP request, # with appropriate auth headers self.assertEqual( next_eff.intent, Request(method='GET', url='http://dfw.openstack/servers', headers=headers('token'), log=self.log))
def test_log_effectful_fields(self): """ The log passed to treq is bound with the fields from BoundFields. """ log = mock_log().bind(duplicate='should be overridden') expected_log = matches( IsBoundWith(duplicate='effectful', bound='stuff')) req = ('GET', 'http://google.com/', None, None, None, { 'log': expected_log }) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/", log=log) req.treq = treq req_eff = Effect(req) bound_log_eff = with_log(req_eff, bound='stuff', duplicate='effectful') dispatcher = ComposedDispatcher( [get_simple_dispatcher(None), get_log_dispatcher(log, {})]) self.assertEqual( self.successResultOf(perform(dispatcher, bound_log_eff)), (response, "content"))
def test_log_none_effectful_fields(self): """ When log is not passed, but there are log fields from BoundFields, the log passed to treq has those fields. """ log = mock_log() # we have to include system='otter' in the expected log here because # the code falls back to otter.log.log, which has the system key bound. expected_log = matches(IsBoundWith(bound='stuff', system='otter')) req = ('GET', 'http://google.com/', None, None, None, {'log': expected_log}) response = StubResponse(200, {}) treq = StubTreq(reqs=[(req, response)], contents=[(response, "content")]) req = Request(method="get", url="http://google.com/") req.treq = treq req_eff = Effect(req) bound_log_eff = with_log(req_eff, bound='stuff') dispatcher = ComposedDispatcher([ get_simple_dispatcher(None), get_log_dispatcher(log, {})]) self.assertEqual( self.successResultOf(perform(dispatcher, bound_log_eff)), (response, "content"))
def test_binds_url(self): """ Binds a URL from service config if it has URL instead of binding URL from service catalog """ self.service_configs[ServiceType.CLOUD_SERVERS]['url'] = 'myurl' eff = self._concrete(self.svcreq) next_eff = resolve_authenticate(eff) # URL in HTTP request is configured URL self.assertEqual( next_eff.intent, Request(method='GET', url='myurl/servers', headers=headers('token'), log=self.log))