Current section

Files

Jump to
eredis test eredis_tests.erl
Raw

test/eredis_tests.erl

-module(eredis_tests).
-include_lib("eunit/include/eunit.hrl").
-include("eredis.hrl").
-import(eredis, [create_multibulk/1]).
get_set_test() ->
C = c(),
?assertMatch({ok, _}, eredis:q(C, ["DEL", foo])),
?assertEqual({ok, undefined}, eredis:q(C, ["GET", foo])),
?assertEqual({ok, <<"OK">>}, eredis:q(C, ["SET", foo, bar])),
?assertEqual({ok, <<"bar">>}, eredis:q(C, ["GET", foo])).
delete_test() ->
C = c(),
?assertMatch({ok, _}, eredis:q(C, ["DEL", foo])),
?assertEqual({ok, <<"OK">>}, eredis:q(C, ["SET", foo, bar])),
?assertEqual({ok, <<"1">>}, eredis:q(C, ["DEL", foo])),
?assertEqual({ok, undefined}, eredis:q(C, ["GET", foo])).
mset_mget_test() ->
C = c(),
Keys = lists:seq(1, 1000),
?assertMatch({ok, _}, eredis:q(C, ["DEL" | Keys])),
KeyValuePairs = [[K, K*2] || K <- Keys],
ExpectedResult = [list_to_binary(integer_to_list(K * 2)) || K <- Keys],
?assertEqual({ok, <<"OK">>}, eredis:q(C, ["MSET" | lists:flatten(KeyValuePairs)])),
?assertEqual({ok, ExpectedResult}, eredis:q(C, ["MGET" | Keys])),
?assertMatch({ok, _}, eredis:q(C, ["DEL" | Keys])).
exec_test() ->
C = c(),
?assertMatch({ok, _}, eredis:q(C, ["LPUSH", "k1", "b"])),
?assertMatch({ok, _}, eredis:q(C, ["LPUSH", "k1", "a"])),
?assertMatch({ok, _}, eredis:q(C, ["LPUSH", "k2", "c"])),
?assertEqual({ok, <<"OK">>}, eredis:q(C, ["MULTI"])),
?assertEqual({ok, <<"QUEUED">>}, eredis:q(C, ["LRANGE", "k1", "0", "-1"])),
?assertEqual({ok, <<"QUEUED">>}, eredis:q(C, ["LRANGE", "k2", "0", "-1"])),
ExpectedResult = [[<<"a">>, <<"b">>], [<<"c">>]],
?assertEqual({ok, ExpectedResult}, eredis:q(C, ["EXEC"])),
?assertMatch({ok, _}, eredis:q(C, ["DEL", "k1", "k2"])).
exec_nil_test() ->
C1 = c(),
C2 = c(),
?assertEqual({ok, <<"OK">>}, eredis:q(C1, ["WATCH", "x"])),
?assertMatch({ok, _}, eredis:q(C2, ["INCR", "x"])),
?assertEqual({ok, <<"OK">>}, eredis:q(C1, ["MULTI"])),
?assertEqual({ok, <<"QUEUED">>}, eredis:q(C1, ["GET", "x"])),
?assertEqual({ok, undefined}, eredis:q(C1, ["EXEC"])),
?assertMatch({ok, _}, eredis:q(C1, ["DEL", "x"])).
pipeline_test() ->
C = c(),
P1 = [["SET", a, "1"],
["LPUSH", b, "3"],
["LPUSH", b, "2"]],
?assertEqual([{ok, <<"OK">>}, {ok, <<"1">>}, {ok, <<"2">>}],
eredis:qp(C, P1)),
P2 = [["MULTI"],
["GET", a],
["LRANGE", b, "0", "-1"],
["EXEC"]],
?assertEqual([{ok, <<"OK">>},
{ok, <<"QUEUED">>},
{ok, <<"QUEUED">>},
{ok, [<<"1">>, [<<"2">>, <<"3">>]]}],
eredis:qp(C, P2)),
?assertMatch({ok, _}, eredis:q(C, ["DEL", a, b])).
pipeline_mixed_test() ->
C = c(),
P1 = [["LPUSH", c, "1"] || _ <- lists:seq(1, 100)],
P2 = [["LPUSH", d, "1"] || _ <- lists:seq(1, 100)],
Expect = [{ok, list_to_binary(integer_to_list(I))} || I <- lists:seq(1, 100)],
spawn(fun () ->
erlang:yield(),
?assertEqual(Expect, eredis:qp(C, P1))
end),
spawn(fun () ->
?assertEqual(Expect, eredis:qp(C, P2))
end),
timer:sleep(10),
?assertMatch({ok, _}, eredis:q(C, ["DEL", c, d])).
q_noreply_test() ->
C = c(),
?assertEqual(ok, eredis:q_noreply(C, ["GET", foo])),
?assertEqual(ok, eredis:q_noreply(C, ["SET", foo, bar])),
%% Even though q_noreply doesn't wait, it is sent before subsequent requests:
?assertEqual({ok, <<"bar">>}, eredis:q(C, ["GET", foo])).
c() ->
Res = eredis:start_link(),
?assertMatch({ok, _}, Res),
{ok, C} = Res,
C.
c_no_reconnect() ->
Res = eredis:start_link("127.0.0.1", 6379, 0, "", no_reconnect),
?assertMatch({ok, _}, Res),
{ok, C} = Res,
C.
multibulk_test_() ->
[?_assertEqual(<<"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n">>,
list_to_binary(create_multibulk(["SET", "foo", "bar"]))),
?_assertEqual(<<"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n">>,
list_to_binary(create_multibulk(['SET', foo, bar]))),
?_assertEqual(<<"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n123\r\n">>,
list_to_binary(create_multibulk(['SET', foo, 123]))),
?_assertThrow({cannot_store_floats, 123.5},
list_to_binary(create_multibulk(['SET', foo, 123.5])))
].
undefined_database_test() ->
?assertMatch({ok,_}, eredis:start_link("localhost", 6379, undefined)).
tcp_closed_test() ->
C = c(),
tcp_closed_rig(C).
tcp_closed_no_reconnect_test() ->
C = c_no_reconnect(),
tcp_closed_rig(C).
tcp_closed_rig(C) ->
%% fire async requests to add to redis client queue and then trick
%% the client into thinking the connection to redis has been
%% closed. This behavior can be observed when Redis closes an idle
%% connection just as a traffic burst starts.
DoSend = fun(tcp_closed) ->
C ! {tcp_closed, fake_socket};
(Cmd) ->
eredis:q(C, Cmd)
end,
%% attach an id to each message for later
Msgs = [{1, ["GET", "foo"]},
{2, ["GET", "bar"]},
{3, tcp_closed}],
Pids = [ remote_query(DoSend, M) || M <- Msgs ],
Results = gather_remote_queries(Pids),
?assertEqual({error, tcp_closed}, proplists:get_value(1, Results)),
?assertEqual({error, tcp_closed}, proplists:get_value(2, Results)).
remote_query(Fun, {Id, Cmd}) ->
Parent = self(),
spawn(fun() ->
Result = Fun(Cmd),
Parent ! {self(), Id, Result}
end).
gather_remote_queries(Pids) ->
gather_remote_queries(Pids, []).
gather_remote_queries([], Acc) ->
Acc;
gather_remote_queries([Pid | Rest], Acc) ->
receive
{Pid, Id, Result} ->
gather_remote_queries(Rest, [{Id, Result} | Acc])
after
10000 ->
error({gather_remote_queries, timeout})
end.