We need a Mock Hive Server for tests
以前、thrift_erlを使ってHiveクライアントを作成しました。このHiveクライアントのテストを書こうとすると、Hive Serverが必要になります。テスト実行時に利用可能なHive Serverがあるとは限りません。そこで今回は、thrift_erlを使ってHive Serverのモックを作ってみました。
Thrift Code generation
今回も、.thriftファイルから生成したコードを使います。コードの生成については以下のページに記載しています。
Implementation for services
まず、Hive Serverのどのserviceを実装するか決めます。今回は、テストコードから呼び出している以下の4メソッドにしました。
- execute
- fetchOne
- fetchAll
- getQueryPlan
次にhandle_functionという関数を用意し、service毎に返したいレスポンスを用意します。
test/hive_server_mock.erl:
1-module(hive_server_mock).
2
3-export([start/0, stop/0, handle_function/2]).
4
5-include_lib("eunit/include/eunit.hrl").
6-include("queryplan_types.hrl").
7
8start() ->
9 {ok, _} = thrift_socket_server:start([{name, mock_server}, {port, 10000}, {service, thriftHive_thrift}, {handler, hive_server_mock}]),
10 ok.
11
12stop() ->
13 thrift_socket_server:stop(mock_server).
14
15handle_function(Function, Params) ->
16 ?debugVal(Function),
17 ?debugVal(Params),
18 case Function of
19 execute ->
20 {reply, Params};
21 fetchOne ->
22 {reply, "a\t1"};
23 fetchAll ->
24 {reply, ["a\t1", "b\t2", "c\t3", "d\t1", "e\t2", "f\t3", "a\t4", "b\t5"]};
25 getQueryPlan ->
26 {reply, #queryPlan{queries = [], done = true, started = true}}
27 end.
これで実装は完了です。
Starting and Stoping server in tests
あとは、テストの実行前にmockサーバを起動し、テスト完了後にmockサーバを停止します。
test/thrift_hive_tests.erl:
1-module(thrift_hive_tests).
2-include_lib("eunit/include/eunit.hrl").
3-export([start/0]).
4-export([stop/1]).
5
6fetchOne_test_() ->
7 {timeout, 1200,
8 {setup, fun start/0, fun stop/1,
9 ?_assertEqual(
10 {ok, "a\t1"},
11 begin thrift_hive:fetch_one("select * from test") end
12 )}
13 }.
14
15fetchAll_test_() ->
16 {timeout, 1200,
17 {setup, fun start/0, fun stop/1,
18 fun() ->
19 {ok, Lst} = thrift_hive:fetch_all("select * from test"),
20 ?assertEqual(["a\t1", "b\t2", "c\t3", "d\t1", "e\t2", "f\t3", "a\t4", "b\t5"], Lst)
21 end}
22 }.
23
24getClusterStatus_test_() ->
25 {timeout, 1200,
26 {setup, fun start/0, fun stop/1,
27 fun() ->
28 {ok, Lst} = thrift_hive:fetch_all_async("select c1, count(*) from test group by c1"),
29 %?debugVal(Lst),
30 {ok, Lst}
31 end}
32 }.
33
34start() ->
35 ok = application:start(gproc),
36 ok = application:start(econfig),
37 ok = econfig:register_config(erl_shib, ["../erl_shib.ini"], [autoreload]),
38 true = econfig:subscribe(erl_shib),
39 ok = hive_server_mock:start().
40
41stop(_Result) ->
42 ok = hive_server_mock:stop(),
43 ok = application:stop(econfig),
44 ok = application:stop(gproc),
45 ok.
Conclusion
Mock Hive Serverを作成し、Hive Serverが無くてもHiveクライアントのテストを動かせるようになりました。
並列でテストを実行することを考えると、サーバの起動/停止は全テストの前後に実行する必要があります。
また、実際のHive Serverは、fetchOneやfetchAllを呼び出した際に、直前に実行したexecuteの実行結果を参照することになるので、サーバ側で状態を保持してるものと思われます。今回のコードではこの部分がない為、executeで指定したHQL毎に実行結果を変更することができません。このあたりはもう少し調べてみたいと思います。