def test_cached_response_on_timeout(container): cached_rpc = get_extension(container, CachedRpcProxy) def fake_some_method(*args, **kwargs): return 'hi' with patch('nameko.rpc.MethodProxy.__call__', fake_some_method): with entrypoint_hook(container, 'cached') as hook: assert hook() == 'hi' def slow_response(*args, **kwargs): eventlet.sleep(3) return 'hi' start = time.time() with patch('nameko.rpc.MethodProxy.__call__', slow_response): with entrypoint_hook(container, 'cached') as hook: assert hook() == 'hi' assert time.time() - start < 2 cached_rpc.cache = {} start = time.time() with patch('nameko.rpc.MethodProxy.__call__', slow_response): with entrypoint_hook(container, 'cached') as hook: assert hook() == 'hi' assert time.time() - start >= 3
def test_reuse_when_down( self, publisher_container, consumer_container, tracker, toxiproxy, ): """ Verify we detect stale connections. Publish confirms are required for this functionality. Without confirms the later messages are silently lost and the test hangs waiting for a response. """ # call 1 succeeds payload1 = "payload1" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload1) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), ] with toxiproxy.disabled(): # call 2 fails payload2 = "payload2" with pytest.raises(IOError): with entrypoint_hook(publisher_container, 'send') as send: send(payload2) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), ]
def test_normal(self, publisher_container, consumer_container, tracker): # call 1 succeeds payload1 = "payload1" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload1) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), ] # call 2 succeeds payload2 = "payload2" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload2) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), call("recv", payload2), ]
def test_reuse_when_recovered(self, client_container, toxiproxy): """ Verify we detect and recover from stale connections. Publish confirms are required for this functionality. Without confirms the later messages are silently lost and the test hangs waiting for a response. """ with entrypoint_hook(client_container, 'echo') as echo: assert echo(1) == 1 toxiproxy.disable() with pytest.raises(IOError) as exc_info: with entrypoint_hook(client_container, 'echo') as echo: echo(2) assert ( # expect the write to raise a BrokenPipe or, if it succeeds, # the socket to be closed on the subsequent confirmation read "Broken pipe" in str(exc_info.value) or "Socket closed" in str(exc_info.value)) toxiproxy.enable() with entrypoint_hook(client_container, 'echo') as echo: assert echo(3) == 3
def test_end_to_end(container_factory, tmpdir): # create a temporary database db_uri = 'sqlite:///{}'.format(tmpdir.join("db").strpath) engine = create_engine(db_uri) ExampleModel.metadata.create_all(engine) config = { DB_URIS_KEY: { 'exampleservice:examplebase': db_uri } } container = container_factory(ExampleService, config) container.start() # write through the service with entrypoint_hook(container, "write") as write: pk = write("foobar") # verify changes written to disk entries = list(engine.execute('SELECT data FROM example LIMIT 1')) assert entries == [('foobar',)] # read through the service with entrypoint_hook(container, "read") as read: assert read(pk) == "foobar"
def test_integration(runner_factory, config): runner = runner_factory(config, Command, Query) runner.start() container = get_container(runner, Command) with entrypoint_hook(container, 'add_news') as entrypoint: data = { "title": "title test", "author": "author test", "content": "content test", "tags": [ "test tag1", "test tag2", ], } result = entrypoint(data) assert result == data container = get_container(runner, Query) with entrypoint_hook(container, 'get_news') as entrypoint: news = json.loads(entrypoint(result['id'])) assert news["_id"] == result['id'] with entrypoint_hook(container, 'get_all_news') as get_all_news: news = json.loads(get_all_news(1, 10)) assert len(news) > 0
def test_cached_response(container): cached_rpc = get_extension(container, CachedRpcProxy) def fake_some_method(*args, **kwargs): return 'hi' with patch('nameko.rpc.MethodProxy.__call__', fake_some_method): with entrypoint_hook(container, 'cached') as hook: assert hook('test') == 'hi' def broken_some_method(*args, **kwargs): raise Exception('hmm') with patch('nameko.rpc.MethodProxy.__call__', broken_some_method): with entrypoint_hook(container, 'cached') as hook: assert hook('test') == 'hi' with patch('nameko.rpc.MethodProxy.__call__', broken_some_method): with entrypoint_hook(container, 'cached') as hook: with pytest.raises(Exception): hook('unknown') cached_rpc.cache = {} with patch('nameko.rpc.MethodProxy.__call__', broken_some_method): with entrypoint_hook(container, 'cached') as hook: with pytest.raises(Exception): hook('test')
def test_reuse_when_recovered( self, publisher_container, consumer_container, tracker, toxiproxy ): """ Verify we detect and recover from stale connections. Publish confirms are required for this functionality. Without confirms the later messages are silently lost and the test hangs waiting for a response. """ # call 1 succeeds payload1 = "payload1" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload1) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), ] toxiproxy.disable() # call 2 fails payload2 = "payload2" with pytest.raises(IOError) as exc_info: with entrypoint_hook(publisher_container, 'send') as send: send(payload2) assert ( # expect the write to raise a BrokenPipe or, if it succeeds, # the socket to be closed on the subsequent confirmation read "Broken pipe" in str(exc_info.value) or "Socket closed" in str(exc_info.value) ) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), ] toxiproxy.enable() # call 3 succeeds payload3 = "payload3" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload3) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), call("send", payload3), call("recv", payload3), ]
def test_retries(self, toxiproxy, disconnect, container): if not toxiproxy: pytest.skip('Toxiproxy not installed') with entrypoint_hook(container, 'create_record') as create_record: create_record() disconnect(reconnect=True) with entrypoint_hook(container, 'get_record_count') as hook: assert hook() == 1
def test_reuse_when_recovered( self, publisher_container, consumer_container, tracker, toxiproxy ): """ Verify we detect and recover from stale connections. Publish confirms are required for this functionality. Without confirms the later messages are silently lost and the test hangs waiting for a response. """ # call 1 succeeds payload1 = "payload1" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload1) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), ] with toxiproxy.disabled(): # call 2 fails payload2 = "payload2" with pytest.raises(IOError) as exc_info: with entrypoint_hook(publisher_container, 'send') as send: send(payload2) assert ( # expect the write to raise a BrokenPipe or, if it succeeds, # the socket to be closed on the subsequent confirmation read "Broken pipe" in str(exc_info.value) or "Socket closed" in str(exc_info.value) ) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), ] # call 3 succeeds payload3 = "payload3" with entrypoint_waiter(consumer_container, 'recv'): with entrypoint_hook(publisher_container, 'send') as send: send(payload3) assert tracker.call_args_list == [ call("send", payload1), call("recv", payload1), call("send", payload2), call("send", payload3), call("recv", payload3), ]
def test_unsubscribe(container, websocket): ws = websocket() ws.rpc('subscribe') with entrypoint_hook(container, 'broadcast') as broadcast: broadcast(value=42) assert get_message(ws) == 42 ws.rpc('unsubscribe') with entrypoint_hook(container, 'broadcast') as broadcast: broadcast(value=42) with eventlet.Timeout(.1, exception=False): assert get_message(ws) == 42
def test_raises_without_retry(self, toxiproxy, disconnect, container): if not toxiproxy: pytest.skip('Toxiproxy not installed') with entrypoint_hook(container, 'create_record') as create_record: create_record() disconnect(reconnect=True) with entrypoint_hook(container, 'get_record_count_no_retry') as hook: with pytest.raises(OperationalError): hook()
def test_close(container, websocket): ws = websocket() ws.rpc('subscribe') with entrypoint_hook(container, 'list_subscribers') as list_subscribers: subscribers1 = list_subscribers() assert subscribers1['test_channel'] ws.app.close() with entrypoint_hook(container, 'list_subscribers') as list_subscribers: subscribers2 = list_subscribers() assert not subscribers2['test_channel']
def it_should_allow_method_calls_to_beanstalkd(self, bs): container = ServiceContainer(ExampleService, {}) container.start() with entrypoint_hook(container, "write") as write: write("foobar") assert bs.Connection.return_value.put.called assert bs.Connection.return_value.put.call_args[0][0] == 'foobar' bs.Connection.return_value.reserve.return_value = MockJob('foobar') with entrypoint_hook(container, "read") as read: assert read() == "foobar"
def test_entrypoint_hook_with_return(runner_factory, rabbit_config): service_classes = (Service, ServiceA, ServiceB, ServiceC) runner = runner_factory(rabbit_config, *service_classes) runner.start() service_container = get_container(runner, Service) with entrypoint_hook(service_container, 'working') as working: assert working("value") == "value-a-b-c" with entrypoint_hook(service_container, 'broken') as broken: with pytest.raises(ExampleError): broken("value")
def test_entrypoint_hook_with_return(runner_factory, rabbit_config): service_classes = (Service, ServiceA, ServiceB, ServiceC) runner = runner_factory(rabbit_config, *service_classes) runner.start() service_container = get_container(runner, Service) with entrypoint_hook(service_container, "working") as working: assert working("value") == "value-a-b-c" with entrypoint_hook(service_container, "broken") as broken: with pytest.raises(ExampleError): broken("value")
def test_rpc_context_data(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() context_data = {'language': 'en', 'auth_token': '123456789'} with entrypoint_hook(container, 'say_hello', context_data) as say_hello: assert say_hello() == "hello" context_data['language'] = 'fr' with entrypoint_hook(container, 'say_hello', context_data) as say_hello: assert say_hello() == "bonjour"
def test_expected_exceptions(self, container_factory): exceptions = defaultdict(list) class CustomException(Exception): pass class Logger(DependencyProvider): """ Example DependencyProvider that interprets ``expected_exceptions`` on an entrypoint """ def worker_result(self, worker_ctx, result=None, exc_info=None): if exc_info is None: # nothing to do return # pragma: no cover exc = exc_info[1] expected = worker_ctx.entrypoint.expected_exceptions if isinstance(exc, expected): exceptions['expected'].append(exc) else: exceptions['unexpected'].append(exc) class Service(object): name = "service" logger = Logger() @dummy(expected_exceptions=CustomException) def expected(self): raise CustomException() @dummy def unexpected(self): raise CustomException() container = container_factory(Service, {}) container.start() with entrypoint_hook(container, 'expected') as hook: with pytest.raises(CustomException) as expected_exc: hook() assert expected_exc.value in exceptions['expected'] with entrypoint_hook(container, 'unexpected') as hook: with pytest.raises(CustomException) as unexpected_exc: hook() assert unexpected_exc.value in exceptions['unexpected']
def test_verify_token_multiple_tokens(db, service_container): token = "im a token" user = User(email="*****@*****.**", password="******", display_name="Test Account") user_token_1 = UserToken( user=user, token=token, created_datetime_utc=datetime.datetime.utcnow() - datetime.timedelta(days=1), ) user_token_2 = UserToken(user=user, token=token + "123", created_datetime_utc=datetime.datetime.utcnow()) db.session.add(user) db.session.add(user_token_1) db.session.add(user_token_2) db.session.commit() with entrypoint_hook(service_container, "verify_token") as verify_token: verify_token(user.id, token + "123")
def test_proxy_disconnect_with_active_worker(container_factory, rabbit_manager, rabbit_config): """ Break the connection to rabbit while a service's queue consumer and rabbit while the service has an in-flight rpc request (i.e. it is waiting on a reply). """ # ExampleService is the target; ProxyService has the rpc_proxy; proxy_container = container_factory(ProxyService, rabbit_config) example_container = container_factory(ExampleService, rabbit_config) proxy_container.start() # get proxyservice's queue consumer connection while we know it's the # only active connection vhost = rabbit_config['vhost'] connections = get_rabbit_connections(vhost, rabbit_manager) assert len(connections) == 1 proxy_consumer_conn = connections[0]['name'] example_container.start() # there should now be two connections: # 1. the queue consumer from proxyservice # 2. the queue consumer from exampleservice connections = get_rabbit_connections(vhost, rabbit_manager) assert len(connections) == 2 # disconnect proxyservice's queue consumer while its request is in-flight eventlet.spawn(disconnect_on_event, rabbit_manager, proxy_consumer_conn) with entrypoint_hook(proxy_container, 'entrypoint') as entrypoint: # we should receive a response after reconnection assert entrypoint('hello') == 'hello' connections = get_rabbit_connections(vhost, rabbit_manager) assert proxy_consumer_conn not in [conn['name'] for conn in connections]
def test_structlog_depedency(greeting_service, greeting_rpc): greeting_rpc.log = TestingStructlogProcessor().get_logger() with entrypoint_hook(greeting_service.container, "greet") as greet: assert greet() == "Hi" assert greeting_rpc.log.info("bar") == ((), {"event": "bar"})
def test_raises_error_if_message_does_not_exist(message_svc, fake_strict_redis): with entrypoint_hook(message_svc, 'get_message') as get_message: with pytest.raises(RedisError) as err: get_message('message-x') err.match(r'Message not found: message-x')
def test_gets_all_messages(message_svc, fake_strict_redis): fake_strict_redis().set('message-1', 'Hello') fake_strict_redis().set('abcdef123456', 'Howdy') fake_strict_redis().set('xyz789', 'I Love Python') fake_strict_redis().set('aaaabbbb', 'So do I!') with entrypoint_hook(message_svc, 'get_all_messages') as get_all_messages: messages = get_all_messages() assert messages == [ { 'id': 'message-1', 'message': 'Hello', 'expires_in': -1 }, { 'id': 'abcdef123456', 'message': 'Howdy', 'expires_in': -1 }, { 'id': 'xyz789', 'message': 'I Love Python', 'expires_in': -1 }, { 'id': 'aaaabbbb', 'message': 'So do I!', 'expires_in': -1 }, ]
def test_timeout(self, client_container, toxiproxy): toxiproxy.set_timeout() with pytest.raises(IOError) as exc_info: with entrypoint_hook(client_container, 'echo') as echo: echo(1) assert "Socket closed" in str(exc_info.value)
def test_event_dispatcher_over_ssl(self, container_factory, rabbit_ssl_config, rabbit_config): class Dispatcher(object): name = "dispatch" dispatch = EventDispatcher() @dummy def method(self, payload): return self.dispatch("event-type", payload) class Handler(object): name = "handler" @event_handler("dispatch", "event-type") def echo(self, payload): return payload dispatcher = container_factory(Dispatcher, rabbit_ssl_config) dispatcher.start() handler = container_factory(Handler, rabbit_config) handler.start() with entrypoint_waiter(handler, 'echo') as result: with entrypoint_hook(dispatcher, 'method') as dispatch: dispatch("payload") assert result.get() == "payload"
def test_pub_sub(container, websocket): ws = websocket() assert ws.rpc('subscribe') == 'subscribed!' with entrypoint_hook(container, 'broadcast') as broadcast: broadcast(value=42) assert get_message(ws) == 42
def test_unicast(container, websocket): ws = websocket() _, connected_data = ws.wait_for_event('connected') socket_id = connected_data['socket_id'] with entrypoint_hook(container, 'unicast') as unicast: assert unicast(target_socket_id=socket_id, value=42) assert get_message(ws) == 42
def test_client_disconnect( self, container_factory, config, web_session ): class Service(object): name = "service" sentry = SentryReporter() @http('POST', '/resource') def resource(self, request): raise CustomException() container = container_factory(Service, config) container.start() request = Mock( method="GET", url="http://example.com", mimetype='application/json', environ={} ) type(request).data = PropertyMock(side_effect=ClientDisconnected) with entrypoint_hook(container, 'resource') as hook: with pytest.raises(CustomException): hook(request) sentry = get_extension(container, SentryReporter) assert sentry.client.send.call_count == 1 _, kwargs = sentry.client.send.call_args assert kwargs['request']['data'] == {}
def test_expected_exceptions_integration(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() worker_logger = get_extension(container, WorkerErrorLogger) with entrypoint_hook(container, 'broken') as broken: with pytest.raises(ExampleError): broken() with entrypoint_hook(container, 'very_broken') as very_broken: with pytest.raises(AttributeError): very_broken() assert worker_logger.expected == {'broken': ExampleError} assert worker_logger.unexpected == {'very_broken': AttributeError}
def test_create_user_successful(config, db, runner_factory): runner = runner_factory(MonitoringService) container = get_container(runner, MonitoringService) storage = replace_dependencies(container, "storage") runner.start() storage.api_requests.append.return_value = None with entrypoint_hook( container, "consume_monitoring_stream") as consume_monitoring_stream: consume_monitoring_stream( "123", { "__MONITOR_NAME": "API_REQUEST", "url": "url", "method": "method", "duration": "duration", "status": "status", "status_code": 1, "remote_addr": "remote_addr", }, ) assert storage.api_requests.append.call_args == call( "123", "url", "method", "duration", "status", 1, "remote_addr")
def test_down(self, client_container, toxiproxy): toxiproxy.disable() with pytest.raises(IOError) as exc_info: with entrypoint_hook(client_container, 'echo') as echo: echo(1) assert "ECONNREFUSED" in str(exc_info.value)
def test_publisher_over_ssl(self, container_factory, rabbit_ssl_config, rabbit_config, queue): class PublisherService(object): name = "publisher" publish = Publisher() @dummy def method(self, payload): return self.publish(payload, routing_key=queue.name) class ConsumerService(object): name = "consumer" @consume(queue) def echo(self, payload): return payload publisher = container_factory(PublisherService, rabbit_ssl_config) publisher.start() consumer = container_factory(ConsumerService, rabbit_config) consumer.start() with entrypoint_waiter(consumer, 'echo') as result: with entrypoint_hook(publisher, 'method') as publish: publish("payload") assert result.get() == "payload"
def test_event_dispatcher_over_ssl( self, container_factory, rabbit_ssl_config, rabbit_config ): class Dispatcher(object): name = "dispatch" dispatch = EventDispatcher() @dummy def method(self, payload): return self.dispatch("event-type", payload) class Handler(object): name = "handler" @event_handler("dispatch", "event-type") def echo(self, payload): return payload dispatcher = container_factory(Dispatcher, rabbit_ssl_config) dispatcher.start() handler = container_factory(Handler, rabbit_config) handler.start() with entrypoint_waiter(handler, 'echo') as result: with entrypoint_hook(dispatcher, 'method') as dispatch: dispatch("payload") assert result.get() == "payload"
def test_erroring_result_adapter(logger, info, container_factory, tracker): class SomeError(Exception): pass class Service(object): name = "some-service" tracer = Tracer() @dummy def some_method(self, spam): pass container = container_factory(Service, {}) container.start() info.side_effect = [Mock(return_value=(Mock(), Mock())), SomeError('Yo!')] with entrypoint_hook(container, 'some_method') as some_method: some_method('ham') # nothing logged by entrypoint logger assert len(tracker.log_records) == 0 # warning logged by module logger assert logger.warning.call_args == call('Failed to log entrypoint trace', exc_info=True)
def test_gets_message(message_svc, fake_strict_redis): fake_strict_redis().set('message-1', 'Test message here!') with entrypoint_hook(message_svc, 'get_message') as get_message: message = get_message('message-1') assert message == 'Test message here!'
def test_async_rpc(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() with entrypoint_hook(container, 'call_async') as call_async: assert call_async() == ["result_b", "result_a", [[], {}]]
def test_publisher_over_ssl( self, container_factory, rabbit_ssl_config, rabbit_config, queue ): class PublisherService(object): name = "publisher" publish = Publisher() @dummy def method(self, payload): return self.publish(payload, routing_key=queue.name) class ConsumerService(object): name = "consumer" @consume(queue) def echo(self, payload): return payload publisher = container_factory(PublisherService, rabbit_ssl_config) publisher.start() consumer = container_factory(ConsumerService, rabbit_config) consumer.start() with entrypoint_waiter(consumer, 'echo') as result: with entrypoint_hook(publisher, 'method') as publish: publish("payload") assert result.get() == "payload"
def it_should_return_a_client_instance(self, bs): container = ServiceContainer(ExampleService, {}) container.start() with entrypoint_hook(container, "client") as client: client() assert bs.Connection.call_count == 1
def test_hello_languages(language, greeting, container_factory, rabbit_config): container = container_factory(HelloService, rabbit_config) container.start() context_data = {'language': language} with entrypoint_hook(container, 'hello', context_data) as hook: assert hook("Matt") == "{}, Matt!".format(greeting)
def test_rpc_context_data(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() context_data = { 'language': 'en', 'auth_token': '123456789' } with entrypoint_hook(container, 'say_hello', context_data) as say_hello: assert say_hello() == "hello" context_data['language'] = 'fr' with entrypoint_hook(container, 'say_hello', context_data) as say_hello: assert say_hello() == "bonjour"
def test_entrypoint_hook_context_data(container_factory, rabbit_config, context_data): container = container_factory(Service, rabbit_config) container.start() method = "get_language" with entrypoint_hook(container, method, context_data) as get_language: assert get_language() == context_data["language"]
def test_expected_exceptions_integration(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() worker_logger = get_dependency(container, WorkerErrorLogger) with entrypoint_hook(container, 'broken') as broken: with pytest.raises(ExampleError): broken() with entrypoint_hook(container, 'very_broken') as very_broken: with pytest.raises(AttributeError): very_broken() wait_for_worker_idle(container) # wait for worker lifecycle to complete assert worker_logger.expected == {'broken': ExampleError} assert worker_logger.unexpected == {'very_broken': AttributeError}
def test_error_in_worker(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() with entrypoint_hook(container, "broken") as broken: with pytest.raises(ExampleError): broken() assert not container._died.ready()
def test_error_in_remote_worker(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() with entrypoint_hook(container, "proxy") as proxy: with pytest.raises(RemoteError) as exc_info: proxy("broken") assert exc_info.value.exc_type == "ExampleError" assert not container._died.ready()
def test_end_to_end(container_factory, tmpdir, setup_db): db = setup_db class ExampleService(object): name = "exampleservice" rdbc = RDB(db) @dummy def write(self, value): result = r.table('test').insert({'data': value}).run(self.rdbc) return result @dummy def read(self, id): return r.table('test').get(id).run(self.rdbc) rdbc = r.connect(host=RDB_HOST, port=RDB_PORT) config = { RDB_KEY: { 'exampleservice': { 'RDB_HOST': RDB_HOST, 'RDB_PORT': RDB_PORT, } } } container = container_factory(ExampleService, config) container.start() # write through the service with entrypoint_hook(container, "write") as write: write("foobar") # verify changes written to disk entries = r.db(db).table('test').run(rdbc) data = list(entries)[0] assert data['data'] == u'foobar' pk = data['id'] # read through the service with entrypoint_hook(container, "read") as read: assert read(pk)['data'] == "foobar"
def test_multiple_calls(container, websocket): ws = websocket() ws.rpc('subscribe') count = 2 for value in range(count): with entrypoint_hook(container, 'broadcast') as broadcast: broadcast(value=value) for value in range(count): assert get_message(ws) == value
def test_rpc_args_kwargs(container_factory, rabbit_config): container = container_factory(ExampleService, rabbit_config) container.start() with entrypoint_hook(container, 'echo') as echo: assert echo() == ((), {}) assert echo("a", "b") == (("a", "b"), {}) assert echo(foo="bar") == ((), {'foo': 'bar'}) assert echo("arg", kwarg="kwarg") == (("arg",), {'kwarg': 'kwarg'})
def test_entrypoint_hook_dependency_not_found(container_factory, rabbit_config): container = container_factory(Service, rabbit_config) container.start() method = "nonexistent_method" with pytest.raises(ExtensionNotFound): with entrypoint_hook(container, method): pass
def test_call_id_stack(rabbit_config, predictable_call_ids, runner_factory): child_do_called = Mock() stack_request = Mock() LoggingWorkerContext = get_logging_worker_context(stack_request) class Child(object): name = 'child' @rpc def child_do(self): child_do_called() return 1 class Parent(object): name = "parent" child_service = RpcProxy('child') @rpc def parent_do(self): return self.child_service.child_do() class Grandparent(object): name = "grandparent" parent_service = RpcProxy('parent') @rpc def grandparent_do(self): return self.parent_service.parent_do() runner = runner_factory(rabbit_config) runner.add_service(Child, LoggingWorkerContext) runner.add_service(Parent, LoggingWorkerContext) runner.add_service(Grandparent, LoggingWorkerContext) runner.start() container = get_container(runner, Grandparent) with entrypoint_hook(container, "grandparent_do") as grandparent_do: assert grandparent_do() == 1 # Check child is called child_do_called.assert_called_with() assert child_do_called.call_count == 1 # Check IDs were requested assert predictable_call_ids.call_count == 3 # Check call ID stack persisted over RPC stack_request.assert_has_calls([ call(None), call(['grandparent.grandparent_do.0']), call(['grandparent.grandparent_do.0', 'parent.parent_do.1']), ])
def test_sensitive_event(container_factory): container = container_factory(Service, {}) handler_entrypoint = get_extension(container, EventHandler) assert handler_entrypoint.sensitive_variables == "event_data.foo" with entrypoint_hook(container, "handle") as handler: handler({"foo": "FOO", "bar": "BAR"}) assert redacted == {"event_data": {"foo": REDACTED, "bar": "BAR"}}
def test_service_x_y_integration(runner_factory, rabbit_config): # run services in the normal manner runner = runner_factory(rabbit_config, ServiceX, ServiceY) runner.start() # artificially fire the "remote_method" entrypoint on ServiceX # and verify response container = get_container(runner, ServiceX) with entrypoint_hook(container, "remote_method") as entrypoint: assert entrypoint("value") == "value-x-y"