Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added bang functions to client #43

Open
wants to merge 1 commit into
base: v_1_5_0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions lib/riffed/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ defmodule Riffed.Client do
args = {:{}, [], params}

quote do
defp raise_exception(ex=unquote(args)) do
ex = unquote(struct_module).to_elixir(ex, unquote(struct_def))
raise ex
defp cast_to_exception(ex=unquote(args)) do
unquote(struct_module).to_elixir(ex, unquote(struct_def))
end
end
end
Expand All @@ -82,6 +81,7 @@ defmodule Riffed.Client do
reply_meta = function_meta[:reply] |> Riffed.Struct.to_riffed_type_spec
reply_meta = Riffed.Enumeration.get_overridden_type(function_name, :return_type, overrides, reply_meta)

exception_function_name = :"#{function_name}!"
arg_list = build_arg_list(length(param_meta))
{:{}, _, list_args} = build_handler_tuple_args(param_meta)
casts = build_casts(function_name, struct_module, param_meta, overrides, :to_erlang)
Expand All @@ -92,18 +92,37 @@ defmodule Riffed.Client do

unquote_splicing(exception_handlers)

def unquote(exception_function_name)(client_pid, unquote_splicing(arg_list))
when is_pid(client_pid) do

case unquote(function_name)(client_pid, unquote_splicing(arg_list)) do
{:error, exception} ->
raise exception

{:ok, response} ->
response
end
end

def unquote(function_name)(client_pid, unquote_splicing(arg_list))
when is_pid(client_pid) do
unquote_splicing(casts)
rv = GenServer.call(client_pid, {unquote(function_name), unquote(list_args)})
case rv do
{:exception, exception_record} ->
raise_exception(exception_record)
{:exception, ex} ->
{:error, cast_to_exception(ex)}

success ->
unquote(struct_module).to_elixir(success, unquote(reply_meta))
{:ok, unquote(struct_module).to_elixir(success, unquote(reply_meta))}
end
end

def unquote(exception_function_name)(unquote_splicing(arg_list)) do
__MODULE__
|> Process.whereis
|> unquote(exception_function_name)(unquote_splicing(arg_list))
end

def unquote(function_name)(unquote_splicing(arg_list)) do
__MODULE__
|> Process.whereis
Expand Down Expand Up @@ -210,7 +229,7 @@ defmodule Riffed.Client do
unquote_splicing(client_functions)

# the default no-op for functions that don't have exceptions.
defp raise_exception(e) do
defp cast_to_exception(e) do
e
end

Expand Down
39 changes: 26 additions & 13 deletions test/riffed/client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ defmodule ClientTest do
test_with_mock "it should convert structs into their correct types", :thrift_client,
[call: respond_with({:ConfigResponse, "foo/bar", 3, 32})] do

response = Client.config(config_request_struct, 3)
{:ok, response} = Client.config(config_request_struct, 3)

assert Models.ConfigResponse.new(template: "foo/bar", requestCount: 3, per: 32) == response
assert {:config, [{:ConfigRequest, "foo/bar", 32, {:User, "Foobie", "Barson", 1}}, 3]} == EchoServer.last_call
Expand All @@ -96,7 +96,7 @@ defmodule ClientTest do
[call: respond_with(:dict.from_list([{"foobar", user_tuple}]))] do
dict_arg = Enum.into([{"foobar", user_struct}], HashDict.new)

response = Client.dictUserFun(dict_arg)
{:ok, response} = Client.dictUserFun(dict_arg)

assert dict_arg == response
expected = {:dictUserFun, [:dict.from_list([{"foobar", user_tuple}])]}
Expand All @@ -107,7 +107,7 @@ defmodule ClientTest do
[call: respond_with(:sets.from_list([user_tuple]))] do
set_arg = Enum.into([user_struct], HashSet.new)

response = Client.setUserFun(set_arg)
{:ok, response} = Client.setUserFun(set_arg)

assert set_arg == response
{call_name, [set_arg]} = EchoServer.last_call
Expand All @@ -119,7 +119,8 @@ defmodule ClientTest do
[call: respond_with(3)] do
user_state = Models.ActivityState.inactive

response = Client.getState(user_state)
{:ok, response} = Client.getState(user_state)

assert response == Models.ActivityState.banned

{call_name, [state]} = EchoServer.last_call
Expand All @@ -130,7 +131,9 @@ defmodule ClientTest do

test_with_mock "it should convert enums returned by client functions", :thrift_client,
[call: respond_with(2)] do
response = Client.getTranslatedState(Models.ActivityState.banned)

{:ok, response} = Client.getTranslatedState(Models.ActivityState.banned)

assert response == Models.ActivityState.inactive
assert {:getTranslatedState, [3]} == EchoServer.last_call
end
Expand All @@ -141,15 +144,18 @@ defmodule ClientTest do
{client, {:ok, 3}}
end] do

response = Client.echoState(Models.ActivityState.active)
{:ok, response} = Client.echoState(Models.ActivityState.active)

assert response == Models.ActivityState.banned
[last_call] = EchoServer.last_call
assert Models.ActivityState.active.value == last_call
end

test_with_mock "it should use callbacks to convert things to elixir", :thrift_client,
[call: fn(client, _, _) -> {client, {:ok, {:LoudUser, "stinky", "stinkman"}}} end] do
response = Client.getLoudUser()

{:ok, response} = Client.getLoudUser()

assert response == Models.LoudUser.new(firstName: "STINKY", lastName: "STINKMAN")
end

Expand All @@ -166,37 +172,42 @@ defmodule ClientTest do
test_with_mock "it should convert enums in lists", :thrift_client,
[call: respond_with([3, 2, 1])] do

response = Client.echoActivityStateList([Models.ActivityState.active])
{:ok, response} = Client.echoActivityStateList([Models.ActivityState.active])

assert [Models.ActivityState.banned, Models.ActivityState.inactive, Models.ActivityState.active] == response
end

test_with_mock "it should convert enums in maps", :thrift_client,
[call: respond_with(:dict.from_list([{"foobar", 3}, {"barfoo", 2}]))] do

response = Client.getUserStates(["foobar", "barfoo"])
{:ok, response} = Client.getUserStates(["foobar", "barfoo"])

assert Models.ActivityState.banned == response["foobar"]
assert Models.ActivityState.inactive == response["barfoo"]
end

test_with_mock "it should convert enums in sets", :thrift_client,
[call: respond_with(:sets.from_list([3, 2]))] do

response = Client.getAllStates()
{:ok, response} = Client.getAllStates()
assert Enum.into([Models.ActivityState.banned,
Models.ActivityState.inactive], HashSet.new) == response
end

test_with_mock "it should convert things in response data structures", :thrift_client,
[call: respond_with({:ResponseWithMap, :dict.from_list([{1234, user_tuple}])})] do

response = Client.getUsers(1234)
{:ok, response} = Client.getUsers(1234)

user_dict = Enum.into([{1234, user_struct}], HashDict.new)
assert Models.ResponseWithMap.new(users: user_dict) == response
end

test_with_mock "it should handle functions defined without argument numbers", :thrift_client,
[call: respond_with(1234)] do
response = Client.functionWithoutNumberedArgs(user_struct, 23)

{:ok, response} = Client.functionWithoutNumberedArgs(user_struct, 23)

last_call = EchoServer.last_call

assert response == 1234
Expand All @@ -205,8 +216,10 @@ defmodule ClientTest do

test_with_mock "it should throw exceptions from the thrift server", :thrift_client, [call: error_with({:ServerException, "Server died", 500})] do

assert {:error, %Models.ServerException{}} = Client.callAndBlowUp("foo", "bar")

assert_raise Models.ServerException, fn ->
Client.callAndBlowUp("foo", "bar")
Client.callAndBlowUp!("foo", "bar")
end
end

Expand Down
27 changes: 18 additions & 9 deletions test/riffed/integration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -125,71 +125,80 @@ defmodule IntegrationTest do

test "The easy client should work" do
EasyClient.start_link
rsp = EasyClient.getUserStates(["foo"])
rsp = EasyClient.getUserStates!(["foo"])

assert 1 == rsp["foo"]
end

test "The enumerized client should convert into structs" do
EnumerizedClient.start_link
response = EnumerizedClient.getUserStates(["foo"])

assert {:ok, _} = EnumerizedClient.getUserStates(["foo"])
response = EnumerizedClient.getUserStates!(["foo"])

assert EnumerizedClient.Models.ActivityState.active == response["foo"]
end

test "The host and port client should work" do
{:ok, client} = HostAndPortClient.start_link("localhost", 22831)
response = HostAndPortClient.getUserStates(client, ["foo"])

assert {:ok, _} = HostAndPortClient.getUserStates(client, ["foo"])
response = HostAndPortClient.getUserStates!(client, ["foo"])

assert 1 == response["foo"]
end

test "unicode text should be supported" do
EasyClient.start_link
rsp = EasyClient.echoString("マイケルさんはすごいですよ。")
rsp = EasyClient.echoString!("マイケルさんはすごいですよ。")
assert "マイケルさんはすごいですよ。" == rsp
end

test "Can attach own error handler for when client disconnects" do
refute File.exists?("rift_error_test.log")
{:ok, client} = ErrorHandlerClient.start_link
ErrorHandlerClient.close(client)

# Sleep for a bit while the server writes to file
:timer.sleep(100)

assert File.read!("rift_error_test.log") == "The client left us in the dust"
File.rm! "rift_error_test.log"
end

test "Can reconnect client" do
EasyClient.start_link
EasyClient.reconnect
rsp = EasyClient.getUserStates(["foo"])
rsp = EasyClient.getUserStates!(["foo"])
assert 1 == rsp["foo"]
end

test "Disconnected client should return :disconnected if calls are made" do
EasyClient.start_link
EasyClient.close
assert :disconnected == EasyClient.getUserStates(["foo"])

assert :disconnected == EasyClient.getUserStates!(["foo"])
end

test "Can reconnect client after disconnecting" do
EasyClient.start_link
EasyClient.close
EasyClient.reconnect
rsp = EasyClient.getUserStates(["foo"])
rsp = EasyClient.getUserStates!(["foo"])
assert 1 == rsp["foo"]
end

test "Can send empty strings" do
{:ok, client} = HostAndPortClient.start_link("localhost", 22831)

assert nil == HostAndPortClient.echoString(client, nil)
assert nil == HostAndPortClient.echoString!(client, nil)
end

test "can handle exceptions" do
EasyClient.start_link
assert {:error, %EasyClient.Models.UsageException{}} = EasyClient.callAndBlowUp("foo", "bar")
assert_raise EasyClient.Models.UsageException, fn ->
EasyClient.callAndBlowUp("foo", "bar")
EasyClient.callAndBlowUp!("foo", "bar")
end
end
end
4 changes: 2 additions & 2 deletions test/riffed/shared_client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ defmodule SharedClientTest do

test_with_mock "it should get preferences", :thrift_client,
[call: respond_with({:Preferences, 1234, true})] do
assert Factory.preferences(1234) == PrefClient.getPreferences(1234)
assert Factory.preferences(1234) == PrefClient.getPreferences!(1234)
end

test_with_mock "it should get the account", :thrift_client,
[call: respond_with({:Account, 1234, {:Preferences, 1234, true},
"[email protected]", 12345, 67890})] do
assert Factory.account(1234) == AccountClient.getAccount(1234)
assert Factory.account(1234) == AccountClient.getAccount!(1234)
end
end