123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- %% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*-
- %% ``The contents of this file are subject to the Erlang Public License,
- %% Version 1.1, (the "License"); you may not use this file except in
- %% compliance with the License. You should have received a copy of the
- %% Erlang Public License along with this software. If not, it can be
- %% retrieved via the world wide web at http://www.erlang.org/.
- %%
- %% Software distributed under the License is distributed on an "AS IS"
- %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- %% the License for the specific language governing rights and limitations
- %% under the License.
- %%
- %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- %% AB. All Rights Reserved.''
- %%
- %% @author Ulf Wiger <ulf@wiger.net>
- %%
- -module(gproc_dist_tests).
- -ifdef(TEST).
- -include_lib("eunit/include/eunit.hrl").
- -export([t_spawn/1, t_spawn_reg/2]).
- -define(f(E), fun() -> ?debugVal(E) end).
- dist_test_() ->
- {timeout, 120,
- [
- %% {setup,
- %% fun dist_setup/0,
- %% fun dist_cleanup/1,
- %% fun(skip) -> [];
- %% (Ns) when is_list(Ns) ->
- %% {inorder, basic_tests(Ns)}
- %% end
- %% },
- {foreach,
- fun dist_setup/0,
- fun dist_cleanup/1,
- [
- fun(Ns) ->
- [{inorder, basic_tests(Ns)}]
- end,
- fun(Ns) ->
- tests(Ns, [?f(t_sync_cand_dies(Ns))])
- end,
- fun(Ns) ->
- tests(Ns, [?f(t_fail_node(Ns))])
- end,
- fun(Ns) ->
- tests(Ns, [?f(t_master_dies(Ns))])
- end
- ]}
- ]}.
- tests(skip, _) ->
- [];
- tests(_, L) ->
- L.
- basic_tests(skip) ->
- [];
- basic_tests(Ns) ->
- [
- ?f(t_simple_reg(Ns)),
- ?f(t_simple_reg_other(Ns)),
- ?f(t_simple_ensure(Ns)),
- ?f(t_simple_ensure_other(Ns)),
- ?f(t_simple_reg_or_locate(Ns)),
- ?f(t_simple_counter(Ns)),
- ?f(t_aggr_counter(Ns)),
- ?f(t_awaited_aggr_counter(Ns)),
- ?f(t_simple_resource_count(Ns)),
- ?f(t_awaited_resource_count(Ns)),
- ?f(t_resource_count_on_zero(Ns)),
- ?f(t_update_counters(Ns)),
- ?f(t_shared_counter(Ns)),
- ?f(t_prop(Ns)),
- ?f(t_mreg(Ns)),
- ?f(t_await_reg(Ns)),
- ?f(t_await_self(Ns)),
- ?f(t_await_reg_exists(Ns)),
- ?f(t_give_away(Ns)),
- ?f(t_sync(Ns)),
- ?f(t_monitor(Ns)),
- ?f(t_standby_monitor(Ns)),
- ?f(t_follow_monitor(Ns)),
- ?f(t_subscribe(Ns))
- ].
- dist_setup() ->
- case run_dist_tests() of
- true ->
- Ns = start_slaves([dist_test_n1, dist_test_n2, dist_test_n3]),
- ?assertMatch({[ok,ok,ok],[]},
- rpc:multicall(Ns, application, set_env,
- [gproc, gproc_dist, Ns])),
- ?assertMatch({[ok,ok,ok],[]},
- rpc:multicall(
- Ns, application, start, [gproc])),
- Ns;
- false ->
- skip
- end.
- dist_cleanup(skip) ->
- ok;
- dist_cleanup(Ns) ->
- [slave:stop(N) || N <- Ns],
- ok.
- run_dist_tests() ->
- case os:getenv("GPROC_DIST") of
- "true" -> true;
- "false" -> false;
- false ->
- case code:ensure_loaded(gen_leader) of
- {error, nofile} ->
- false;
- _ ->
- true
- end
- end.
- -define(T_NAME, {n, g, {?MODULE, ?LINE, os:timestamp()}}).
- -define(T_KVL, [{foo, "foo"}, {bar, "bar"}]).
- -define(T_COUNTER, {c, g, {?MODULE, ?LINE}}).
- -define(T_RESOURCE, {r, g, {?MODULE, ?LINE}}).
- -define(T_PROP, {p, g, ?MODULE}).
- t_simple_reg([H|_] = Ns) ->
- Name = ?T_NAME,
- P = t_spawn_reg(H, Name),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P)),
- ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
- ?assertMatch(ok, t_call(P, die)).
- t_simple_reg_other([A, B|_] = Ns) ->
- Name = ?T_NAME,
- P1 = t_spawn(A),
- P2 = t_spawn(B),
- ?assertMatch(true, t_call(P1, {apply, gproc, reg_other, [Name, P2]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P2)),
- ?assertMatch(true, t_call(P1, {apply, gproc, unreg_other, [Name, P2]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
- ?assertMatch(ok, t_call(P1, die)),
- ?assertMatch(ok, t_call(P2, die)).
- t_simple_ensure([H|_] = Ns) ->
- Name = ?T_NAME,
- P = t_spawn_reg(H, Name),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P)),
- ?assertMatch(
- updated, t_call(
- P, {apply, gproc, ensure_reg, [Name, new_val, [{a,1}]]})),
- ?assertMatch(
- [{a,1}], t_call(
- P, {apply, gproc, get_attributes, [Name]})),
- ?assertMatch(ok, t_read_everywhere(Name, P, Ns, new_val)),
- ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
- ?assertMatch(ok, t_call(P, die)).
- t_simple_ensure_other([A, B|_] = Ns) ->
- Name = ?T_NAME,
- P1 = t_spawn(A),
- P2 = t_spawn(B),
- ?assertMatch(true, t_call(P1, {apply, gproc, reg_other, [Name, P2]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P2)),
- ?assertMatch(
- updated, t_call(
- P1, {apply, gproc, ensure_reg_other, [Name, P2, new_val]})),
- ?assertMatch(ok, t_read_everywhere(Name, P2, Ns, new_val)),
- ?assertMatch(true, t_call(P1, {apply, gproc, unreg_other, [Name, P2]})),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
- ?assertMatch(ok, t_call(P1, die)),
- ?assertMatch(ok, t_call(P2, die)).
- t_simple_reg_or_locate([A,B|_] = _Ns) ->
- Name = ?T_NAME,
- P1 = t_spawn(A),
- Ref = erlang:monitor(process, P1),
- ?assertMatch({P1, the_value},
- t_call(P1, {apply, gproc, reg_or_locate, [Name, the_value]})),
- P2 = t_spawn(B),
- Ref2 = erlang:monitor(process, P2),
- ?assertMatch({P1, the_value},
- t_call(P2, {apply, gproc, reg_or_locate, [Name, other_value]})),
- ?assertMatch(ok, t_call(P1, die)),
- ?assertMatch(ok, t_call(P2, die)),
- flush_down(Ref),
- flush_down(Ref2).
- flush_down(Ref) ->
- receive
- {'DOWN', Ref, _, _, _} ->
- ok
- after 1000 ->
- erlang:error({timeout, [flush_down, Ref]})
- end.
- t_simple_counter([H|_] = Ns) ->
- Ctr = ?T_COUNTER,
- P = t_spawn_reg(H, Ctr, 3),
- ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 3)),
- ?assertMatch(5, t_call(P, {apply, gproc, update_counter, [Ctr, 2]})),
- ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 5)),
- ?assertMatch(ok, t_call(P, die)).
- t_shared_counter([H|_] = Ns) ->
- Ctr = ?T_COUNTER,
- P = t_spawn_reg_shared(H, Ctr, 3),
- ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 3)),
- ?assertMatch(5, t_call(P, {apply, gproc, update_shared_counter, [Ctr, 2]})),
- ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)),
- ?assertMatch(ok, t_call(P, die)),
- ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)),
- ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)), % twice
- P1 = t_spawn(H),
- ?assertMatch(true, t_call(P1, {apply, gproc, unreg_shared, [Ctr]})),
- ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, badarg)).
- t_aggr_counter([H1,H2|_] = Ns) ->
- {c,g,Nm} = Ctr = ?T_COUNTER,
- Aggr = {a,g,Nm},
- Pc1 = t_spawn_reg(H1, Ctr, 3),
- Pa = t_spawn_reg(H2, Aggr),
- ?assertMatch(ok, t_read_everywhere(Ctr, Pc1, Ns, 3)),
- ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 3)),
- Pc2 = t_spawn_reg(H2, Ctr, 3),
- ?assertMatch(ok, t_read_everywhere(Ctr, Pc2, Ns, 3)),
- ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 6)),
- ?assertMatch(5, t_call(Pc1, {apply, gproc, update_counter, [Ctr, 2]})),
- ?assertMatch(ok, t_read_everywhere(Ctr, Pc1, Ns, 5)),
- ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 8)),
- ?assertMatch(ok, t_call(Pc1, die)),
- ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 3)),
- ?assertMatch(ok, t_call(Pc2, die)),
- ?assertMatch(ok, t_call(Pa, die)).
- t_awaited_aggr_counter([H1,H2|_] = Ns) ->
- {c,g,Nm} = Ctr = ?T_COUNTER,
- Aggr = {a,g,Nm},
- Pc1 = t_spawn_reg(H1, Ctr, 3),
- P = t_spawn(H2),
- Ref = erlang:monitor(process, P),
- P ! {self(), Ref, {apply, gproc, await, [Aggr]}},
- t_sleep(),
- P1 = t_spawn_reg(H2, Aggr),
- ?assert(P1 == receive
- {P, Ref, Res} ->
- element(1, Res);
- {'DOWN', Ref, _, _, Reason} ->
- erlang:error(Reason);
- Other ->
- erlang:error({received, Other})
- end),
- ?assertMatch(ok, t_read_everywhere(Aggr, P1, Ns, 3)),
- ?assertMatch(ok, t_call(Pc1, die)),
- ?assertMatch(ok, t_call(P, die)),
- flush_down(Ref),
- ?assertMatch(ok, t_call(P1, die)).
- t_simple_resource_count([H1,H2|_] = Ns) ->
- {r,g,Nm} = R = ?T_RESOURCE,
- RC = {rc,g,Nm},
- Pr1 = t_spawn_reg(H1, R, 3),
- Prc = t_spawn_reg(H2, RC),
- ?assertMatch(ok, t_read_everywhere(R, Pr1, Ns, 3)),
- ?assertMatch(ok, t_read_everywhere(RC, Prc, Ns, 1)),
- Pr2 = t_spawn_reg(H2, R, 4),
- ?assertMatch(ok, t_read_everywhere(R, Pr2, Ns, 4)),
- ?assertMatch(ok, t_read_everywhere(RC, Prc, Ns, 2)),
- ?assertMatch(ok, t_call(Pr1, die)),
- ?assertMatch(ok, t_read_everywhere(RC, Prc, Ns, 1)),
- ?assertMatch(ok, t_call(Pr2, die)),
- ?assertMatch(ok, t_call(Prc, die)).
- t_awaited_resource_count([H1,H2|_] = Ns) ->
- {r,g,Nm} = R = ?T_RESOURCE,
- RC = {rc,g,Nm},
- Pr1 = t_spawn_reg(H1, R, 3),
- P = t_spawn(H2),
- Ref = erlang:monitor(process, P),
- P ! {self(), Ref, {apply, gproc, await, [RC]}},
- t_sleep(),
- P1 = t_spawn_reg(H2, RC),
- ?assert(P1 == receive
- {P, Ref, Res} ->
- element(1, Res);
- {'DOWN', Ref, _, _, Reason} ->
- erlang:error(Reason);
- Other ->
- erlang:error({received, Other})
- end),
- ?assertMatch(ok, t_read_everywhere(RC, P1, Ns, 1)),
- ?assertMatch(ok, t_call(Pr1, die)),
- ?assertMatch(ok, t_call(P, die)),
- flush_down(Ref),
- ?assertMatch(ok, t_call(P1, die)).
- t_resource_count_on_zero([H1,H2|_] = Ns) ->
- {r,g,Nm} = R = ?T_RESOURCE,
- Prop = ?T_PROP,
- RC = {rc,g,Nm},
- Pr1 = t_spawn_reg(H1, R, 3),
- Pp = t_spawn_reg(H2, Prop),
- ?assertMatch(ok, t_call(Pp, {selective, true})),
- Prc = t_spawn_reg(H2, RC, undefined, [{on_zero, [{send, Prop}]}]),
- ?assertMatch(ok, t_read_everywhere(R, Pr1, Ns, 3)),
- ?assertMatch(ok, t_read_everywhere(RC, Prc, Ns, 1)),
- ?assertMatch(ok, t_call(Pr1, die)),
- ?assertMatch(ok, t_read_everywhere(RC, Prc, Ns, 0)),
- ?assertMatch({gproc, resource_on_zero, g, Nm, Prc},
- t_call(Pp, {apply_fun, fun() ->
- receive
- {gproc, _, _, _, _} = M ->
- M
- after 10000 ->
- timeout
- end
- end})),
- ?assertMatch(ok, t_call(Pp, {selective, false})),
- ?assertMatch(ok, t_call(Pp, die)),
- ?assertMatch(ok, t_call(Prc, die)).
- t_update_counters([H1,H2|_] = Ns) ->
- {c,g,N1} = C1 = ?T_COUNTER,
- A1 = {a,g,N1},
- C2 = ?T_COUNTER,
- P1 = t_spawn_reg(H1, C1, 2),
- P12 = t_spawn_reg(H2, C1, 2),
- P2 = t_spawn_reg(H2, C2, 1),
- Pa1 = t_spawn_reg(H2, A1),
- ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 2)),
- ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 2)),
- ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 1)),
- ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 4)),
- ?assertMatch([{C1,P1, 3},
- {C1,P12,4},
- {C2,P2, 0}], t_call(P1, {apply, gproc, update_counters,
- [g, [{C1,P1,1},{C1,P12,2},{C2,P2,{-2,0,0}}]]})),
- ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 3)),
- ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 4)),
- ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 0)),
- ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 7)),
- ?assertMatch(ok, t_call(P1, die)),
- ?assertMatch(ok, t_call(P12, die)),
- ?assertMatch(ok, t_call(P2, die)).
- t_prop([H1,H2|_] = Ns) ->
- {p, g, _} = P = ?T_PROP,
- P1 = t_spawn_reg(H1, P, 1),
- P2 = t_spawn_reg(H2, P, 2),
- ?assertMatch(ok, t_read_everywhere(P, P1, Ns, 1)),
- ?assertMatch(ok, t_read_everywhere(P, P2, Ns, 2)),
- ?assertMatch(ok, t_call(P1, die)),
- ?assertMatch(ok, t_read_everywhere(P, P1, Ns, badarg)),
- ?assertMatch(ok, t_call(P2, die)).
- t_mreg([H|_] = Ns) ->
- Kvl = ?T_KVL,
- Keys = [K || {K,_} <- Kvl],
- P = t_spawn_mreg(H, Kvl),
- [?assertMatch(ok, t_lookup_everywhere({n,g,K}, Ns, P)) || K <- Keys],
- ?assertMatch(true, t_call(P, {apply, gproc, munreg, [n, g, Keys]})),
- [?assertMatch(ok, t_lookup_everywhere({n,g,K},Ns,undefined)) || K <- Keys],
- ?assertMatch(ok, t_call(P, die)).
- t_await_reg([A,B|_] = Ns) ->
- Name = ?T_NAME,
- P = t_spawn(A),
- Ref = erlang:monitor(process, P),
- P ! {self(), Ref, {apply, gproc, await, [Name]}},
- t_sleep(),
- P1 = t_spawn_reg(B, Name),
- ?assert(P1 == receive
- {P, Ref, Res} ->
- element(1, Res);
- {'DOWN', Ref, _, _, Reason} ->
- erlang:error(Reason);
- Other ->
- erlang:error({received,Other})
- end),
- ?assertMatch(ok, t_call(P, die)),
- flush_down(Ref),
- ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P1)),
- ?assertMatch(ok, t_call(P1, die)).
- t_await_self([A|_]) ->
- Name = ?T_NAME,
- P = t_spawn(A, false), % don't buffer unknowns
- Ref = t_call(P, {apply, gproc, nb_wait, [Name]}),
- ?assertMatch(ok, t_call(P, {selective, true})),
- ?assertMatch(true, t_call(P, {apply, gproc, reg, [Name, some_value]})),
- ?assertMatch({registered, {Name, P, some_value}},
- t_call(P, {apply_fun, fun() ->
- receive
- {gproc, Ref, R, Wh} ->
- {R, Wh}
- after 10000 ->
- timeout
- end
- end})),
- ?assertMatch(ok, t_call(P, {selective, false})),
- ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})).
- t_await_reg_exists([A,B|_]) ->
- Name = ?T_NAME,
- P = t_spawn(A),
- Ref = erlang:monitor(process, P),
- P1 = t_spawn_reg(B, Name),
- P ! {self(), Ref, {apply, gproc, await, [Name]}},
- ?assert(P1 == receive
- {P, Ref, Res} ->
- element(1, Res);
- {'DOWN', Ref, _, _, Reason} ->
- erlang:error(Reason);
- Other ->
- erlang:error({received,Other})
- end),
- ?assertMatch(ok, t_call(P, die)),
- ?assertMatch(ok, t_call(P1, die)).
- t_give_away([A,B|_] = Ns) ->
- Na = ?T_NAME,
- Nb = ?T_NAME,
- Pa = t_spawn_reg(A, Na),
- Pb = t_spawn_reg(B, Nb),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
- ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
- ?assertMatch(Pb, t_call(Pa, {apply, gproc, give_away, [Na, Nb]})),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pb)),
- ?assertMatch(Pa, t_call(Pb, {apply, gproc, give_away, [Na, Pa]})),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
- ?assertMatch(ok, t_call(Pa, die)),
- ?assertMatch(ok, t_call(Pb, die)).
- t_sync(Ns) ->
- %% Don't really know how to test this...
- [?assertMatch(true, rpc:call(N, gproc_dist, sync, []))
- || N <- Ns].
- t_monitor([A,B|_]) ->
- Na = ?T_NAME,
- Pa = t_spawn_reg(A, Na),
- Pb = t_spawn(B, _Selective = true),
- Ref = t_call(Pb, {apply, gproc, monitor, [Na]}),
- ?assert(is_reference(Ref)),
- ?assertMatch(ok, t_call(Pa, die)),
- ?assertMatch({gproc,unreg,Ref,Na}, got_msg(Pb, gproc)),
- Pc = t_spawn_reg(A, Na),
- Ref1 = t_call(Pb, {apply, gproc, monitor, [Na]}),
- ?assertMatch(true, t_call(Pc, {apply, gproc, unreg, [Na]})),
- ?assertMatch({gproc,unreg,Ref1,Na}, got_msg(Pb, gproc)).
- t_standby_monitor([A,B|_] = Ns) ->
- Na = ?T_NAME,
- Pa = t_spawn_reg(A, Na),
- Pb = t_spawn(B, _Selective = true),
- Ref = t_call(Pb, {apply, gproc, monitor, [Na, standby]}),
- ?assert(is_reference(Ref)),
- ?assertMatch(ok, t_call(Pa, die)),
- ?assertMatch({gproc,{failover,Pb},Ref,Na}, got_msg(Pb, gproc)),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pb)),
- Pc = t_spawn(A, true),
- Ref1 = t_call(Pc, {apply, gproc, monitor, [Na, standby]}),
- ?assertMatch(true, t_call(Pb, {apply, gproc, unreg, [Na]})),
- ?assertMatch({gproc,unreg,Ref1,Na}, got_msg(Pc, gproc)),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, undefined)).
- t_follow_monitor([A,B|_]) ->
- Na = ?T_NAME,
- Pa = t_spawn(A, _Selective = true),
- Ref = t_call(Pa, {apply, gproc, monitor, [Na, follow]}),
- {gproc,unreg,Ref,Na} = got_msg(Pa),
- Pb = t_spawn_reg(B, Na),
- {gproc,registered,Ref,Na} = got_msg(Pa),
- ok = t_call(Pb, die),
- ok = t_call(Pa, die).
- t_subscribe([A,B|_] = Ns) ->
- Na = ?T_NAME,
- Pb = t_spawn(B, _Selective = true),
- ?assertEqual(ok, t_call(Pb, {apply, gproc_monitor, subscribe, [Na]})),
- ?assertMatch({gproc_monitor, Na, undefined}, got_msg(Pb, gproc_monitor)),
- Pa = t_spawn_reg(A, Na),
- ?assertMatch({gproc_monitor, Na, Pa}, got_msg(Pb, gproc_monitor)),
- Pc = t_spawn(A),
- t_call(Pa, {apply, gproc, give_away, [Na, Pc]}),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pc)),
- ?assertEqual({gproc_monitor,Na,{migrated,Pc}}, got_msg(Pb, gproc_monitor)),
- ?assertEqual(ok, t_call(Pc, die)),
- ?assertEqual({gproc_monitor,Na,undefined}, got_msg(Pb, gproc_monitor)),
- ok.
- %% got_msg(Pb, Tag) ->
- %% t_call(Pb,
- %% {apply_fun,
- %% fun() ->
- %% receive
- %% M when element(1, M) == Tag ->
- %% M
- %% after 1000 ->
- %% erlang:error({timeout, got_msg, [Pb, Tag]})
- %% end
- %% end}).
- %% Verify that the gproc_dist:sync() call returns true even if a candidate dies
- %% while the sync is underway. This test makes use of sys:suspend() to ensure that
- %% the other candidate doesn't respond too quickly.
- t_sync_cand_dies([A,B|_]) ->
- Leader = rpc:call(A, gproc_dist, get_leader, []),
- Other = case Leader of
- A -> B;
- B -> A
- end,
- ?assertMatch(ok, rpc:call(Other, sys, suspend, [gproc_dist])),
- P = rpc:call(Other, erlang, whereis, [gproc_dist]),
- Key = rpc:async_call(Leader, gproc_dist, sync, []),
- %% The overall timeout for gproc_dist:sync() is 5 seconds. Here, we should
- %% still be waiting.
- ?assertMatch(timeout, rpc:nb_yield(Key, 1000)),
- exit(P, kill),
- %% The leader should detect that the other candidate died and respond
- %% immediately. Therefore, we should have our answer well within 1 sec.
- ?assertMatch({value, true}, rpc:nb_yield(Key, 1000)).
- t_fail_node([A,B|_] = Ns) ->
- Na = ?T_NAME,
- Nb = ?T_NAME,
- Pa = t_spawn_reg(A, Na),
- Pb = t_spawn_reg(B, Nb),
- ?assertMatch(ok, rpc:call(A, application, stop, [gproc])),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns -- [A], undefined)),
- ?assertMatch(ok, t_lookup_everywhere(Nb, Ns -- [A], Pb)),
- ?assertMatch(ok, rpc:call(A, application, start, [gproc])),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, undefined)),
- ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
- ?assertMatch(ok, t_call(Pa, die)),
- ?assertMatch(ok, t_call(Pb, die)).
- t_master_dies([A,B,C] = Ns) ->
- Na = ?T_NAME,
- Nb = ?T_NAME,
- Nc = ?T_NAME,
- Pa = t_spawn_reg(A, Na),
- Pb = t_spawn_reg(B, Nb),
- Pc = t_spawn_reg(C, Nc),
- L = rpc:call(A, gproc_dist, get_leader, []),
- ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
- ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
- ?assertMatch(ok, t_lookup_everywhere(Nc, Ns, Pc)),
- {Nl, Pl} = case L of
- A -> {Na, Pa};
- B -> {Nb, Pb};
- C -> {Nc, Pc}
- end,
- ?assertMatch(true, rpc:call(A, gproc_dist, sync, [])),
- ?assertMatch(ok, rpc:call(L, application, stop, [gproc])),
- Names = [{Na,Pa}, {Nb,Pb}, {Nc,Pc}] -- [{Nl, Pl}],
- RestNs = Ns -- [L],
- ?assertMatch(true, rpc:call(hd(RestNs), gproc_dist, sync, [])),
- ?assertMatch(ok, t_lookup_everywhere(Nl, RestNs, undefined)),
- [?assertMatch(ok, t_lookup_everywhere(Nx, RestNs, Px))
- || {Nx, Px} <- Names],
- ok.
- t_sleep() ->
- timer:sleep(500).
- t_lookup_everywhere(Key, Nodes, Exp) ->
- t_lookup_everywhere(Key, Nodes, Exp, 3).
- t_lookup_everywhere(Key, _, Exp, 0) ->
- {lookup_failed, Key, Exp};
- t_lookup_everywhere(Key, Nodes, Exp, I) ->
- Expected = [{N, Exp} || N <- Nodes],
- Found = [{N,rpc:call(N, gproc, where, [Key])} || N <- Nodes],
- if Expected =/= Found ->
- ?debugFmt("lookup ~p failed~n"
- "(Expected: ~p;~n"
- " Found : ~p), retrying...~n",
- [Key, Expected, Found]),
- t_sleep(),
- t_lookup_everywhere(Key, Nodes, Exp, I-1);
- true ->
- ok
- end.
- t_read_everywhere(Key, Pid, Nodes, Exp) ->
- t_read_everywhere(Key, Pid, Nodes, Exp, 3).
- t_read_everywhere(Key, _, _, Exp, 0) ->
- {read_failed, Key, Exp};
- t_read_everywhere(Key, Pid, Nodes, Exp, I) ->
- Expected = [{N, Exp} || N <- Nodes],
- Found = [{N, read_result(rpc:call(N, gproc, get_value, [Key, Pid]))}
- || N <- Nodes],
- if Expected =/= Found ->
- ?debugFmt("read ~p failed~n"
- "(Expected: ~p;~n"
- " Found : ~p), retrying...~n",
- [{Key, Pid}, Expected, Found]),
- t_sleep(),
- t_read_everywhere(Key, Pid, Nodes, Exp, I-1);
- true ->
- ok
- end.
- read_result({badrpc, {'EXIT', {badarg, _}}}) -> badarg;
- read_result(R) -> R.
- t_spawn(Node) -> gproc_test_lib:t_spawn(Node).
- t_spawn(Node, Selective) -> gproc_test_lib:t_spawn(Node, Selective).
- t_spawn_mreg(Node, KVL) -> gproc_test_lib:t_spawn_mreg(Node, KVL).
- t_spawn_reg(Node, N) -> gproc_test_lib:t_spawn_reg(Node, N).
- t_spawn_reg(Node, N, V) -> gproc_test_lib:t_spawn_reg(Node, N, V).
- t_spawn_reg(Node, N, V, As) -> gproc_test_lib:t_spawn_reg(Node, N, V, As).
- t_spawn_reg_shared(Node, N, V) -> gproc_test_lib:t_spawn_reg_shared(Node, N, V).
- got_msg(P) -> gproc_test_lib:got_msg(P).
- got_msg(P, Tag) -> gproc_test_lib:got_msg(P, Tag).
- t_call(P, Req) ->
- gproc_test_lib:t_call(P, Req).
- start_slaves(Ns) ->
- [H|T] = Nodes = [start_slave(N) || N <- Ns],
- _ = [rpc:call(H, net_adm, ping, [N]) || N <- T],
- Nodes.
- start_slave(Name) ->
- case node() of
- nonode@nohost ->
- os:cmd("epmd -daemon"),
- {ok, _} = net_kernel:start([gproc_master, shortnames]);
- _ ->
- ok
- end,
- {Pa, Pz} = paths(),
- Paths = "-pa ./ -pz ../ebin" ++
- lists:flatten([[" -pa " ++ Path || Path <- Pa],
- [" -pz " ++ Path || Path <- Pz]]),
- {ok, Node} = slave:start(host(), Name, Paths),
- Node.
- paths() ->
- Path = code:get_path(),
- {ok, [[Root]]} = init:get_argument(root),
- {Pas, Rest} = lists:splitwith(fun(P) ->
- not lists:prefix(Root, P)
- end, Path),
- {_, Pzs} = lists:splitwith(fun(P) ->
- lists:prefix(Root, P)
- end, Rest),
- {Pas, Pzs}.
- host() ->
- [_Name, Host] = re:split(atom_to_list(node()), "@", [{return, list}]),
- list_to_atom(Host).
- -endif.
|