Skip to content

Commit a45ab9e

Browse files
committed
Full tests
1 parent 332b9f5 commit a45ab9e

File tree

5 files changed

+144
-23
lines changed

5 files changed

+144
-23
lines changed

lib/util/grpc_x.ex

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,12 @@ defmodule Util.GrpcX do
5656
"""
5757
@spec call(client_name(), Atom.t(), any(), any()) :: Util.GrpcX.RPCCall.response()
5858
def call(client_name, method_name, request, opts \\ []) do
59-
{:ok, client} = State.find_client(client_name)
59+
case State.find_client(client_name) do
60+
{:ok, client} ->
61+
Client.call(client, method_name, request, opts)
6062

61-
Client.call(client, method_name, request, opts)
63+
:error ->
64+
{:error, "GrpcX client with name='#{client_name}' not registered in GrpcX"}
65+
end
6266
end
6367
end

lib/util/grpc_x/client.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ defmodule Util.GrpcX.Client do
3939
def call(client, method_name, request, opts \\ []) do
4040
rpc_call = RPCCall.new(client, method_name, request, opts)
4141

42-
Wormhole.capture(fn -> RPCCall.execute(rpc_call) end, timeout: rpc_call.timeout)
42+
result = Wormhole.capture(fn -> RPCCall.execute(rpc_call) end, timeout: rpc_call.timeout)
43+
44+
case result do
45+
{:ok, result} -> result
46+
{:error, result} -> {:error, result}
47+
end
4348
end
4449
end

lib/util/grpc_x/rpc_call.ex

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ defmodule Util.GrpcX.RPCCall do
1313

1414
%{
1515
endpoint: client.endpoint,
16+
client_name: client.name,
1617
stub: client.stub,
1718
method_name: method_name,
1819
request: request,
@@ -37,16 +38,16 @@ defmodule Util.GrpcX.RPCCall do
3738
end)
3839
end
3940

40-
defp connect(rpc_call) do
41-
inc(rpc_call, "connect.count")
41+
defp connect(rpc) do
42+
inc(rpc, "connect.count")
4243

43-
case GRPC.Stub.connect(rpc_call.endpoint) do
44+
case GRPC.Stub.connect(rpc.endpoint) do
4445
{:ok, channel} ->
4546
{:ok, channel}
4647

4748
{:error, err} ->
48-
inc(rpc_call, "connect.failure.count")
49-
log(rpc_call, "Failed to connect")
49+
inc(rpc, "connect.error.count")
50+
log_err(rpc, "failed to connect to #{rpc.endpoint}")
5051

5152
{:error, err}
5253
end
@@ -64,18 +65,22 @@ defmodule Util.GrpcX.RPCCall do
6465
inc(rpc, "response.success.count")
6566
{:ok, result}
6667

68+
{:error, {:unknown_rpc, _}} = e ->
69+
e
70+
6771
{:error, err} ->
6872
inc(rpc, "response.error.count")
69-
log(rpc, "response error err='#{inspect(err)}'")
73+
log_err(rpc, "err='#{inspect(err)}'")
7074

7175
{:error, err}
7276
end
7377
end
7478

7579
defp do_call(rpc, channel) do
76-
GRPC.Stub.call(rpc.stub, rpc.method_name, channel, rpc.request, rpc.opts)
80+
apply(rpc.stub, rpc.method_name, [channel, rpc.request, rpc.opts])
7781
rescue
78-
e -> {:error, e}
82+
e in UndefinedFunctionError ->
83+
{:error, {:unknown_rpc, "no RPC method named='#{e.function}'"}}
7984
end
8085

8186
defp inc(rpc, metric) do
@@ -92,7 +97,10 @@ defmodule Util.GrpcX.RPCCall do
9297
end
9398
end
9499

95-
defp log(rpc, msg) do
96-
Logger.log(rpc.log_level, "GrpcX: #{rpc.client_name} #{rpc.method_name} #{msg}")
100+
defp log_err(rpc, msg) do
101+
Logger.log(
102+
rpc.log_level,
103+
"GrpcX ERROR client='#{rpc.client_name}' rpc='#{rpc.method_name}' #{msg}"
104+
)
97105
end
98106
end

test/grpc_x_test.exs

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,132 @@
11
defmodule Util.GrpcXTest do
22
use ExUnit.Case
3+
import Mock
34

45
alias Util.GrpcX
56

67
setup_all do
7-
server_pid = start_helloworld_server()
8-
clients_pid = start_clients()
8+
{:ok, server_pid} = start_helloworld_server()
9+
{:ok, clients_pid} = start_clients()
910

1011
on_exit(fn ->
1112
Process.exit(server_pid, :kill)
1213
Process.exit(clients_pid, :kill)
1314
end)
1415
end
1516

16-
test "connecting to an existing services works and returns an {:ok, reply} tuple" do
17+
test "it can connect to existing services, result is in form {:ok, reply}" do
1718
req = Helloworld.HelloRequest.new(name: "shiroyasha")
1819

1920
assert {:ok, reply} = GrpcX.call(:hello_service, :say_hello, req)
2021
assert reply.message == "Hello shiroyasha"
2122
end
2223

24+
test "it raises an error if you pass an unknown service name" do
25+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
26+
27+
assert {:error, err} = GrpcX.call(:hellooooooo, :say_hello, req)
28+
assert err == "GrpcX client with name='hellooooooo' not registered in GrpcX"
29+
end
30+
31+
test "it raises an error if you request an unknown rpc method" do
32+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
33+
34+
assert {:error, {:unknown_rpc, err}} = GrpcX.call(:hello_service, :describe, req)
35+
36+
assert err == "no RPC method named='describe'"
37+
end
38+
39+
test "it timeouts long calls" do
40+
req = Helloworld.HelloRequest.new(name: "please take a long time")
41+
42+
assert {:error, err} = GrpcX.call(:hello_service, :say_hello, req, timeout: 500)
43+
assert err == %GRPC.RPCError{message: "Deadline expired", status: 4}
44+
end
45+
46+
test "it reports connection errors" do
47+
req = Helloworld.HelloRequest.new(name: "please take a long time")
48+
49+
assert {:error, err} = GrpcX.call(:not_running_service, :say_hello, req)
50+
assert err == "Error when opening connection: :timeout"
51+
end
52+
53+
describe "when metrics are disabled" do
54+
test_with_mock "no increments are submitted", Watchman, [:passthrough], [] do
55+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
56+
GrpcX.call(:hello_service_not_measured, :say_hello, req)
57+
58+
assert_not_called(Watchman.increment(:_))
59+
end
60+
61+
test_with_mock "no benchmarks are submitted", Watchman, [:passthrough], [] do
62+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
63+
GrpcX.call(:hello_service_not_measured, :say_hello, req)
64+
65+
assert_not_called(Watchman.benchmark(:_, :_))
66+
end
67+
end
68+
69+
describe "when metrics are enabled" do
70+
test_with_mock "it measures number of connections", Watchman, [:passthrough], [] do
71+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
72+
GrpcX.call(:hello_service, :say_hello, req)
73+
74+
assert_called(Watchman.increment("grpc.hello_service.say_hello.connect.count"))
75+
end
76+
77+
test_with_mock "it measures number of requests", Watchman, [:passthrough], [] do
78+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
79+
GrpcX.call(:hello_service, :say_hello, req)
80+
81+
assert_called(Watchman.increment("grpc.hello_service.say_hello.request.count"))
82+
end
83+
84+
test_with_mock "it measures connection failures", Watchman, [:passthrough], [] do
85+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
86+
GrpcX.call(:not_running_service, :say_hello, req)
87+
88+
assert_called(Watchman.increment("grpc.not_running_service.say_hello.connect.error.count"))
89+
end
90+
91+
test_with_mock "it measures response successes", Watchman, [:passthrough], [] do
92+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
93+
GrpcX.call(:hello_service, :say_hello, req)
94+
95+
assert_called(Watchman.increment("grpc.hello_service.say_hello.response.success.count"))
96+
end
97+
98+
test_with_mock "it measures response errors", Watchman, [:passthrough], [] do
99+
req = Helloworld.HelloRequest.new(name: "please fail")
100+
GrpcX.call(:hello_service, :say_hello, req)
101+
102+
assert_called(Watchman.increment("grpc.hello_service.say_hello.response.error.count"))
103+
end
104+
105+
test_with_mock "it measures the duration of the rpc call", Watchman, [:passthrough], [] do
106+
req = Helloworld.HelloRequest.new(name: "shiroyasha")
107+
GrpcX.call(:hello_service, :say_hello, req)
108+
109+
assert_called(Watchman.benchmark("grpc.hello_service.say_hello.duration", :_))
110+
end
111+
end
112+
23113
def start_helloworld_server() do
24-
spawn_link(fn ->
25-
GRPC.Server.start(Helloworld.Greeter.Server, 50_051)
26-
end)
114+
{:ok, pid, _} = GRPC.Server.start(Helloworld.Greeter.Server, 50_052)
115+
{:ok, pid}
27116
end
28117

29118
def start_clients() do
30119
clients = [
31-
Util.GrpcX.Client.new(:hello_service, "localhost:50051", Helloworld.Greeter.Stub)
120+
Util.GrpcX.Client.new(:hello_service, "localhost:50052", Helloworld.Greeter.Stub),
121+
Util.GrpcX.Client.new(:not_running_service, "localhost:60000", Helloworld.Greeter.Stub),
122+
Util.GrpcX.Client.new(
123+
:hello_service_not_measured,
124+
"localhost:50052",
125+
Helloworld.Greeter.Stub,
126+
publish_metrics: false
127+
)
32128
]
33129

34-
{:ok, client_pid} = Util.GrpcX.start_link(clients)
130+
Util.GrpcX.start_link(clients)
35131
end
36132
end

test/protos/server.ex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ defmodule Helloworld.Greeter.Server do
55

66
@spec say_hello(HelloRequest.t(), GRPC.Server.Stream.t()) :: HelloReply.t()
77
def say_hello(request, _stream) do
8-
IO.inspect("Say Hello requested")
8+
case request.name do
9+
"please take a long time" ->
10+
:timer.sleep(60_000)
11+
Helloworld.HelloReply.new(message: "Hello")
912

10-
Helloworld.HelloReply.new(message: "Hello #{request.name}")
13+
"please fail" ->
14+
raise "I'm failing"
15+
16+
name ->
17+
Helloworld.HelloReply.new(message: "Hello #{name}")
18+
end
1119
end
1220
end

0 commit comments

Comments
 (0)