def test_custom_details(interceptors): """We can set custom details.""" special_cases = {"error": raises(gx.NotFound(details="custom"))} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: assert (client.Execute(DummyRequest(input="foo")).output == "foo" ) # Test a happy path too with pytest.raises(grpc.RpcError) as e: client.Execute(DummyRequest(input="error")) assert e.value.code() == grpc.StatusCode.NOT_FOUND assert e.value.details() == "custom"
def test_client_streaming(interceptors): """Client streaming should work.""" special_cases = {"error": lambda r, c: 1 / 0} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: inputs = ["foo", "bar"] input_iter = (DummyRequest(input=input) for input in inputs) assert client.ExecuteClientStream(input_iter).output == "foobar" inputs = ["foo", "error"] input_iter = (DummyRequest(input=input) for input in inputs) with pytest.raises(grpc.RpcError): client.ExecuteClientStream(input_iter)
def test_code_counting(): """Access to code on call details works correctly.""" interceptor = CodeCountInterceptor() special_cases = {"error": raises(ValueError("oops"))} with dummy_client(special_cases=special_cases, client_interceptors=[interceptor]) as client: assert interceptor.counts == {} client.Execute(DummyRequest(input="foo")) assert interceptor.counts == {grpc.StatusCode.OK: 1} with pytest.raises(grpc.RpcError): client.Execute(DummyRequest(input="error")) assert interceptor.counts == { grpc.StatusCode.OK: 1, grpc.StatusCode.UNKNOWN: 1 }
def test_all_exceptions(interceptors): """Every gRPC status code is represented, and they each are unique. Make sure we aren't missing any status codes, and that we didn't copy paste the same status code or details into two different classes. """ all_status_codes = { sc for sc in grpc.StatusCode if sc != grpc.StatusCode.OK } seen_codes = set() seen_details = set() for sc in all_status_codes: ex = getattr(gx, _snake_to_camel(sc.name)) assert ex special_cases = {"error": raises(ex())} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: with pytest.raises(grpc.RpcError) as e: client.Execute(DummyRequest(input="error")) assert e.value.code() == sc assert e.value.details() == ex.details seen_codes.add(sc) seen_details.add(ex.details) assert seen_codes == all_status_codes assert len(seen_details) == len(all_status_codes)
def test_basic_retry(): """Calling the continuation multiple times should work.""" interceptor = RetryInterceptor(retries=1) special_cases = {"error_once": CrashingService(num_crashes=1)} with dummy_client(special_cases=special_cases, client_interceptors=[interceptor]) as client: assert client.Execute(DummyRequest(input="error_once")).output == "OK"
def test_client_server_streaming(interceptors): """Bidirectional streaming should work.""" with dummy_client(special_cases={}, interceptors=interceptors) as client: inputs = ["foo", "bar"] input_iter = (DummyRequest(input=input) for input in inputs) response = client.ExecuteClientServerStream(input_iter) assert [r.output for r in response] == inputs
def test_metadata_server_stream(metadata_client, metadata_string): """Invocation metadata should be added to the servicer context.""" server_stream_output = [ r.output for r in metadata_client.ExecuteServerStream( DummyRequest(input="metadata")) ] assert metadata_string in "".join(server_stream_output)
def test_server_streaming(interceptors): """Server streaming should work.""" with dummy_client(special_cases={}, interceptors=interceptors) as client: output = [ r.output for r in client.ExecuteServerStream(DummyRequest(input="foo")) ] assert output == ["f", "o", "o"]
def test_non_grpc_exception(interceptors): """Exceptions other than GrpcExceptions are ignored.""" special_cases = {"error": raises(ValueError("oops"))} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: with pytest.raises(grpc.RpcError) as e: client.Execute(DummyRequest(input="error")) assert e.value.code() == grpc.StatusCode.UNKNOWN
def test_aborting_interceptor(): """context.abort called in an interceptor works.""" interceptor = AbortingInterceptor("oh no") with dummy_client(special_cases={}, interceptors=[interceptor]) as client: with pytest.raises(grpc.RpcError) as e: client.Execute(DummyRequest(input="test")) assert e.value.code() == grpc.StatusCode.ABORTED assert e.value.details() == "oh no"
def test_failed_retry(): """The interceptor can return failed futures.""" interceptor = RetryInterceptor(retries=1) special_cases = {"error_twice": CrashingService(num_crashes=2)} with dummy_client(special_cases=special_cases, client_interceptors=[interceptor]) as client: with pytest.raises(grpc.RpcError): client.Execute(DummyRequest(input="error_twice"))
def test_interceptor_chain(): """Interceptors are called in the right order.""" trace = [] interceptor1 = SideEffectInterceptor(lambda: trace.append(1)) interceptor2 = SideEffectInterceptor(lambda: trace.append(2)) with dummy_client(special_cases={}, interceptors=[interceptor1, interceptor2]) as client: assert client.Execute(DummyRequest(input="test")).output == "test" assert trace == [1, 2]
def test_call_counts(): """The counts should be correct.""" intr = CountingInterceptor() interceptors = [intr] special_cases = {"error": lambda r, c: 1 / 0} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: assert client.Execute(DummyRequest(input="foo")).output == "foo" assert len(intr.num_calls) == 1 assert intr.num_calls["/DummyService/Execute"] == 1 assert len(intr.num_errors) == 0 with pytest.raises(grpc.RpcError): client.Execute(DummyRequest(input="error")) assert len(intr.num_calls) == 1 assert intr.num_calls["/DummyService/Execute"] == 2 assert len(intr.num_errors) == 1 assert intr.num_errors["/DummyService/Execute"] == 1
def test_non_grpc_exception_with_override(): """We can set a custom status code when non-GrpcExceptions are raised.""" interceptors = [ ExceptionToStatusInterceptor( status_on_unknown_exception=grpc.StatusCode.INTERNAL) ] special_cases = {"error": raises(ValueError("oops"))} with dummy_client(special_cases=special_cases, interceptors=interceptors) as client: with pytest.raises(grpc.RpcError) as e: client.Execute(DummyRequest(input="error")) assert e.value.code() == grpc.StatusCode.INTERNAL assert re.fullmatch(r"ValueError\('oops',?\)", e.value.details())
def test_chaining(): """Chaining interceptors should work.""" retry_interceptor = RetryInterceptor(retries=1) code_count_interceptor = CodeCountInterceptor() interceptors = [retry_interceptor, code_count_interceptor] special_cases = {"error_once": CrashingService(num_crashes=1)} with dummy_client(special_cases=special_cases, client_interceptors=interceptors) as client: assert code_count_interceptor.counts == {} assert client.Execute(DummyRequest(input="error_once")).output == "OK" assert code_count_interceptor.counts == { grpc.StatusCode.OK: 1, grpc.StatusCode.UNKNOWN: 1, }
def test_caching(): """Caching calls (not calling the continuation) should work.""" caching_interceptor = CachingInterceptor() # Use this to test how many times the continuation is called. code_count_interceptor = CodeCountInterceptor() interceptors = [caching_interceptor, code_count_interceptor] with dummy_client(special_cases={}, client_interceptors=interceptors) as client: assert code_count_interceptor.counts == {} assert client.Execute(DummyRequest(input="hello")).output == "hello" assert code_count_interceptor.counts == {grpc.StatusCode.OK: 1} assert client.Execute(DummyRequest(input="hello")).output == "hello" assert code_count_interceptor.counts == {grpc.StatusCode.OK: 1} assert client.Execute( DummyRequest(input="goodbye")).output == "goodbye" assert code_count_interceptor.counts == {grpc.StatusCode.OK: 2} # Try streaming requests inputs = ["foo", "bar"] input_iter = (DummyRequest(input=input) for input in inputs) assert client.ExecuteClientStream(input_iter).output == "foobar" assert code_count_interceptor.counts == {grpc.StatusCode.OK: 3} input_iter = (DummyRequest(input=input) for input in inputs) assert client.ExecuteClientStream(input_iter).output == "foobar" assert code_count_interceptor.counts == {grpc.StatusCode.OK: 3}
def test_modifying_interceptor(): """Interceptors can modify requests.""" interceptor = UppercasingInterceptor() with dummy_client(special_cases={}, interceptors=[interceptor]) as client: assert client.Execute(DummyRequest(input="test")).output == "TEST"
def test_no_exception(interceptors): """An RPC with no exceptions should work as if the interceptor wasn't there.""" with dummy_client(special_cases={}, interceptors=interceptors) as client: assert client.Execute(DummyRequest(input="foo")).output == "foo"
def test_metadata_unary(metadata_client, metadata_string): """Invocation metadata should be added to the servicer context.""" unary_output = metadata_client.Execute( DummyRequest(input="metadata")).output assert metadata_string in unary_output
def test_metadata_client_server_stream(metadata_client, metadata_string): """Invocation metadata should be added to the servicer context.""" stream_stream_input = iter((DummyRequest(input="metadata"), )) result = metadata_client.ExecuteClientServerStream(stream_stream_input) stream_stream_output = [r.output for r in result] assert metadata_string in "".join(stream_stream_output)
def test_metadata_client_stream(metadata_client, metadata_string): """Invocation metadata should be added to the servicer context.""" client_stream_input = iter((DummyRequest(input="metadata"), )) client_stream_output = metadata_client.ExecuteClientStream( client_stream_input).output assert metadata_string in client_stream_output