def test_container_doesnt_exhaust_max_workers(container): spam_called = Event() spam_continue = Event() class Service(object): name = 'max-workers' @foobar def spam(self, a): spam_called.send(a) spam_continue.wait() container = ServiceContainer(Service, config={MAX_WORKERS_CONFIG_KEY: 1}) dep = get_extension(container, Entrypoint) # start the first worker, which should wait for spam_continue container.spawn_worker(dep, ['ham'], {}) # start the next worker in a speparate thread, # because it should block until the first one completed gt = spawn(container.spawn_worker, dep, ['eggs'], {}) with Timeout(1): assert spam_called.wait() == 'ham' # if the container had spawned the second worker, we would see # an error indicating that spam_called was fired twice, and the # greenthread would now be dead. assert not gt.dead # reset the calls and allow the waiting worker to complete. spam_called.reset() spam_continue.send(None) # the second worker should now run and complete assert spam_called.wait() == 'eggs' assert gt.dead
def test_healthcheck(config, db, web_session): container = ServiceContainer(MonitoringService) replace_dependencies(container, storage=StorageWrapper(db, Storage.collections)) container.start() response = web_session.get("/health-check") assert response.status_code == 200
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 it_should_destroy_connection_on_kill(self, bs): container = ServiceContainer(ExampleService, {}) container.start() assert bs.Connection.called container.kill() assert bs.Connection.return_value.close.called
def test_raises_error_if_message_does_not_exist(fake_strict_redis, config): container = ServiceContainer(MessageService, config) container.start() with entrypoint_hook(container, '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_rpc_timeout(): container = ServiceContainer(FooService, CONFIG) container.start() with StandaloneRpcProxy(CONFIG, timeout=.5) as proxy: with pytest.raises(RpcTimeout): assert proxy.foo_service.sleep(1) assert proxy.foo_service.sleep(0) == 0
def test_health_check(config, web_session): container = ServiceContainer(GatewayService) redis = replace_dependencies(container, "redis") container.start() redis.set.return_value = "1" response = web_session.get("/health-check") assert response.status_code == 200
def test_gets_message(fake_strict_redis, config): fake_strict_redis().set('message-1', 'Test message here!') container = ServiceContainer(MessageService, config) container.start() with entrypoint_hook(container, 'get_message') as get_message: message = get_message('message-1') assert message == 'Test message here!'
def test_hello_languages(language, greeting, rabbit_config): container = ServiceContainer(HelloService, rabbit_config) container.start() context_data = {'language': language} with entrypoint_hook(container, 'hello', context_data) as hook: assert hook("Matt") == "{}, Matt!".format(greeting) container.stop()
def test_image_not_found(self, config, web_session): image_svc = ServiceContainer(ImageService, config) mock_image_host = replace_dependencies(image_svc, 'image_host') mock_image_host.download_image.side_effect = ImageNotFound('not found') image_svc.start() response = web_session.get('/image/abc123') assert response.status_code == 404 assert response.text == 'not found'
def test_auth_user_incorrect_schema(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.auth_user.side_effect = UserNotAuthorised() response = web_session.post("/v1/user/auth", data=json.dumps({})) assert response.status_code == 400 assert response.json() == {"error": "VALIDATION_ERROR", "message": ANY}
def test_rpc_proxy(): container = ServiceContainer(FooService, CONFIG) container.start() with StandaloneRpcProxy(CONFIG) as proxy: assert proxy.foo_service.test("test") == "test" msg = "Error occurred" try: proxy.foo_service.error(msg) except FooTestError as error: assert str(error) == msg
def test_verify_user_token_incorrect_schema(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() email = "*****@*****.**" response = web_session.post("/v1/user/token", data=json.dumps({"email": email})) assert response.status_code == 400 assert response.json() == {"error": "VALIDATION_ERROR", "message": ANY}
def test_gets_image(self, config, web_session): image_svc = ServiceContainer(ImageService, config) mock_image_host = replace_dependencies(image_svc, 'image_host') mock_image_host.download_image.return_value = b'foo' image_svc.start() response = web_session.get('/image/abc123') assert response.status_code == 200 assert response.content == b'foo' assert response.headers['Content-Type'] == 'image/jpeg'
def test_update_is_called_when_battle_finishes(rabbit_config): container = ServiceContainer(ScoreService, rabbit_config) container.start() dispatch = event_dispatcher(rabbit_config) with mock.patch.object(ScoreService, 'update_players_score') as mock_method: with entrypoint_waiter(container, 'update_players_score'): dispatch('battle_service', 'battle_finished', [0, 1, 2]) mock_method.assert_called_once_with([0, 1, 2]) container.stop()
def test_event_interface(rabbit_config): container = ServiceContainer(ServiceB, rabbit_config) container.start() dispatch = event_dispatcher(rabbit_config) # prints "service b received payload" before "exited" with entrypoint_waiter(container, 'handle_event'): dispatch("service_a", "event_type", "payload") print "exited" container.stop()
def test_auth_user_not_authorised(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.auth_user.side_effect = UserNotAuthorised() response = web_session.post( "/v1/user/auth", data=json.dumps({"email": "email", "password": "******"}) ) assert response.status_code == 401 assert response.json() == {"error": "USER_NOT_AUTHORISED", "message": ""}
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_check_user_exists_false(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.user_already_exists.return_value = False email = "*****@*****.**" response = web_session.head(f"/v1/user/{email}") assert accounts.user_already_exists.call_args == call(email) assert response.status_code == 200
def test_saves_new_message(fake_strict_redis, config, uuid4): uuid4.return_value.hex = 'abcdef123456' container = ServiceContainer(MessageService, config) container.start() with entrypoint_hook(container, 'save_message') as save_message: message_id = save_message('Test message here!') assert message_id == 'abcdef123456' # Writing point: # When first running this, it will fail since the message is # in bytes. fake_strict_redis is not set up to # decode_responses. decode() is needed message = fake_strict_redis().get('abcdef123456').decode() assert message == 'Test message here!'
def test_unexpected_error(self, config, web_session, mock_uuid): image_svc = ServiceContainer(ImageService, config) mock_image_host = replace_dependencies(image_svc, 'image_host') mock_image_host.upload_image.side_effect = ImageUploadError('BOOM!') image_svc.start() with open(TEST_IMAGE_FILE, 'rb') as image_file: response = web_session.post( '/image', files={'data': image_file}, ) assert response.text == 'Error: ImageUploadError: BOOM!\n' assert response.status_code == 500
def test_posts_image(self, config, web_session, mock_uuid): image_svc = ServiceContainer(ImageService, config) mock_image_host = replace_dependencies(image_svc, 'image_host') mock_image_host.upload_image.return_value = b'foo' image_svc.start() with open(TEST_IMAGE_FILE, 'rb') as image_file: response = web_session.post( '/image', files={'data': image_file}, ) assert response.json() == {'image_id': 'abc123'} assert mock_image_host.upload_image.call_args_list[0][0][1] == 'abc123'
def test_async_calls(): container = ServiceContainer(FooService, CONFIG) container.start() with StandaloneRpcProxy(CONFIG) as proxy: resp1 = proxy.foo_service.test.call_async(1) resp2 = proxy.foo_service.sleep.call_async(2) resp3 = proxy.foo_service.test.call_async(3) resp4 = proxy.foo_service.test.call_async(4) resp5 = proxy.foo_service.test.call_async(5) assert resp2.result() == 2 assert resp3.result() == 3 assert resp1.result() == 1 assert resp4.result() == 4 assert resp5.result() == 5
def test_kwarg_deprecation_warning(self, warnings, service_cls, worker_ctx_cls): config = {} ServiceContainer(service_cls, config, worker_ctx_cls=worker_ctx_cls) # TODO: replace with pytest.warns when eventlet >= 0.19.0 is released assert warnings.warn.call_args_list == [call(ANY, DeprecationWarning)]
def make_container(service_cls, config, worker_ctx_cls=None): if worker_ctx_cls is None: worker_ctx_cls = WorkerContext container = ServiceContainer(service_cls, worker_ctx_cls, config) all_containers.append(container) return container
def container(): container = ServiceContainer(Service, config={}) for ext in container.extensions: ext._reset_calls() CallCollectorMixin.call_counter = 0 return container
def test_get_extension(rabbit_config): from nameko.messaging import QueueConsumer from nameko.rpc import Rpc, RpcConsumer from nameko.containers import ServiceContainer class Service(object): name = "service" @rpc def foo(self): pass @rpc def bar(self): pass container = ServiceContainer(Service, rabbit_config) rpc_consumer = get_extension(container, RpcConsumer) queue_consumer = get_extension(container, QueueConsumer) foo_rpc = get_extension(container, Rpc, method_name="foo") bar_rpc = get_extension(container, Rpc, method_name="bar") extensions = container.extensions assert extensions == set([rpc_consumer, queue_consumer, foo_rpc, bar_rpc])
def test_create_stripe_checkout_session_unsuccessful(config, web_session, mock_jwt_token): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.create_stripe_checkout_session.side_effect = ( UnableToCreateCheckoutSession()) user_id = 1 email = "*****@*****.**" plan = "plan_1" success_url = "http://success.com" cancel_url = "http://cancel.com" mock_jwt_token.return_value = {"user_id": user_id, "email": email} response = web_session.post( "/v1/stripe/checkout-session", data=json.dumps({ "plan": plan, "success_url": success_url, "cancel_url": cancel_url, "project_id": 1, }), ) assert accounts.create_stripe_checkout_session.call_args == call({ "user_id": user_id, "email": email, "plan": plan, "success_url": success_url, "cancel_url": cancel_url, "project_id": 1, }) assert response.status_code == 500 assert response.json() == { "error": "UNABLE_TO_CREATE_CHECKOUT_SESSION", "message": "", }
def test_expected_exceptions(rabbit_config): container = ServiceContainer(ExampleService, WorkerContext, rabbit_config) broken = get_dependency(container, RpcProvider, name="broken") assert broken.expected_exceptions == ExampleError very_broken = get_dependency(container, RpcProvider, name="very_broken") assert very_broken.expected_exceptions == (KeyError, ValueError)
def setUp(self): configuration = ConfigContainer(CONFIG_KEY) self.service_container = ServiceContainer(Service, configuration.config) configuration = configuration.config[CONFIG_KEY] self._redis_client = Redis(host=configuration['host'], port=configuration['port'], db=configuration['db'], password=configuration['password'], decode_responses=True) self._queue = Queue(QUEUE_NAME, self._redis_client)
def test_end_to_end(redis_db): config = {REDIS_URIS_KEY: {'server': redis_db}} container = ServiceContainer(ExampleService, config) container.start() # write through the service with entrypoint_hook(container, "write") as write: write("foobar") # verify changes written to redis client = StrictRedis.from_url(redis_db, decode_responses=True) assert client.get(TEST_KEY) == "foobar" # read through the service with entrypoint_hook(container, "read") as read: assert read() == "foobar"
def test_expected_exceptions(rabbit_config): container = ServiceContainer(ExampleService, rabbit_config) broken = get_extension(container, Rpc, method_name="broken") assert broken.expected_exceptions == ExampleError very_broken = get_extension(container, Rpc, method_name="very_broken") assert very_broken.expected_exceptions == (KeyError, ValueError)
def test_create_user_already_exists(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.create_user.side_effect = UserAlreadyExists() email = "*****@*****.**" password = "******" display_name = "test" request = {"email": email, "password": password, "display_name": display_name} response = web_session.post("/v1/user", data=json.dumps(request)) assert response.status_code == 409 assert response.json() == {"error": "USER_ALREADY_EXISTS", "message": ""}
def container(): container = ServiceContainer(service_cls=Service, worker_ctx_cls=WorkerContext, config={}) for dep in container.dependencies: dep._reset_calls() CallCollectorMixin.call_counter = 0 return container
def test_auth_user(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.auth_user.return_value = {"JWT": "test"} email = "*****@*****.**" password = "******" response = web_session.post( "/v1/user/auth", data=json.dumps({"email": email, "password": password}) ) assert accounts.auth_user.call_args == call(email, password) assert response.status_code == 200 assert response.json() == {"JWT": "test"}
def test_create_stripe_checkout_session_successful(config, web_session, mock_jwt_token): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.create_stripe_checkout_session.return_value = "test" user_id = 1 email = "*****@*****.**" plan = "plan_1" success_url = "http://success.com" cancel_url = "http://cancel.com" mock_jwt_token.return_value = {"user_id": user_id, "email": email} response = web_session.post( "/v1/stripe/checkout-session", data=json.dumps({ "plan": plan, "success_url": success_url, "cancel_url": cancel_url, "project_id": 1, }), ) assert accounts.create_stripe_checkout_session.call_args == call({ "user_id": user_id, "email": email, "plan": plan, "success_url": success_url, "cancel_url": cancel_url, "project_id": 1, }) assert response.status_code == 200 assert response.json() == {"session_id": "test"}
def test_verify_user_token_valid(config, web_session): container = ServiceContainer(GatewayService) accounts = replace_dependencies(container, "accounts_rpc") container.start() accounts.verify_user.return_value = None email = "*****@*****.**" token = "token" response = web_session.post("/v1/user/token", data=json.dumps({ "email": email, "token": token })) assert accounts.verify_user.call_args == call(email, token) assert response.status_code == 200
def test_end_to_end(redis_db): config = { REDIS_URIS_KEY: { 'server': redis_db } } container = ServiceContainer(ExampleService, config) container.start() # write through the service with entrypoint_hook(container, "write") as write: write("foobar") # verify changes written to redis client = StrictRedis.from_url(redis_db) assert client.get(TEST_KEY) == b'foobar' # read through the service with entrypoint_hook(container, "read") as read: assert read() == b"foobar"
class TestPyrqServer(unittest.TestCase): def setUp(self): configuration = ConfigContainer(CONFIG_KEY) self.service_container = ServiceContainer(Service, configuration.config) configuration = configuration.config[CONFIG_KEY] self._redis_client = Redis(host=configuration['host'], port=configuration['port'], db=configuration['db'], password=configuration['password'], decode_responses=True) self._queue = Queue(QUEUE_NAME, self._redis_client) def tearDown(self): self._redis_client.delete(QUEUE_NAME) def testService(self): self._queue.add_item(json.dumps({ 'method': 'hello', 'params': { 'arg1': True } })) self.service_container.start() self.assertFalse(Service.arg_missing)
def it_should_connect_to_the_server_on_setup(self, bs): container = ServiceContainer(ExampleService, {}) container.start() assert bs.Connection.called
from nameko.containers import ServiceContainer class Service(object): name = "service" # create a container container = ServiceContainer(Service, config={}) # ``container.extensions`` exposes all extensions used by the service service_extensions = list(container.extensions) # start service container.start() # stop service container.stop()