-module(regis). -export([ register/3 , unregister/2 , unregister_all/1 , whereis_job/1 , jobs/1 , num_registered_pids/0 , callback/1 ]). -define(SERVER, regis_pnode_s). %% Public API whereis_job(JobMeta) -> gen_server:call(?SERVER, {whereis_job, JobMeta}). jobs(JobMeta) -> gen_server:call(?SERVER, {jobs, JobMeta}). num_registered_pids() -> gen_server:call(?SERVER, {num_registered_pids}). register(JobMeta, VNodeId, Pid) -> gen_server:cast(?SERVER, {reg, JobMeta, VNodeId, Pid}). unregister(JobMeta, Pid) -> gen_server:cast(?SERVER, {unreg, JobMeta, Pid}). unregister_all(Pid) -> gen_server:cast(?SERVER, {unreg_all, Pid}). %% =================================================================== %% EUnit tests %% =================================================================== -include_lib("eunit/include/eunit.hrl"). -define(setup(F), {setup, fun start_t/0, fun stop_t/1, F}). %% Описание спецификаций %%%%%%%%%%%%%%%%%%%%%%%%%% %%% TESTS DESCRIPTIONS %%% %%%%%%%%%%%%%%%%%%%%%%%%%% start_stop_test_() -> {"0. Сервер должен запускаться, останавливаться и иметь зарегистрированное имя", ?setup(fun is_registered/1)}. register_test_() -> [ {"1 Register. Должна иметься возможность регистрации Pid и Job из одной функции", ?setup(fun register_t/1)}, {"2 UnRegister. Должна иметься возможность снятия с регистрации Pid и Job из одной функции обладая полями (JobMeta и Pid)", ?setup(fun unregister_t/1)}, {"3 Search. Должна быть возможность определения Pid по имени Job, извлечения всех зарегистрированных джобов и количества зарегистрированных Pid", ?setup(fun search_t/1)}, {"4 Процесс должен автоматически сниматься с регистрации после завершения или при внезапной смерти", ?setup(fun auto_unregister_t/1)} ]. %%%%%%%%%%%%%%%%%%%%%%% %%% SETUP FUNCTIONS %%% %%%%%%%%%%%%%%%%%%%%%%% start_t() -> {ok, Pid} = ?SERVER:start_link(), Pid. stop_t(_) -> ?SERVER:stop([]). %%%%%%%%%%%%%%%%%%%% %%% ACTUAL TESTS %%% %%%%%%%%%%%%%%%%%%%% is_registered(Pid) -> [ ?_assert(erlang:is_process_alive(Pid)), ?_assertEqual(Pid, whereis(regis_pnode_s)) ]. register_t(_State) -> Self = self(), JobMeta1 = {pscomp1, sample1, Self}, VnodeItem1 = {111111111112234455666, Self}, JobsId=pscomp_proc_jobs, PidsId=pscomp_proc_pids, [ ?_assertMatch(ok, register(JobMeta1, VnodeItem1, Self) ), ?_assertEqual(1, num_items(JobsId, JobMeta1) ), ?_assertEqual(1, num_items(PidsId, Self) ) ]. unregister_t(_State) -> Self = self(), JobMeta1 = {pscomp1, sample1, Self}, VnodeItem1 = {111111111112234455666, Self}, VnodeItem2 = {212313123486898080821, Self}, JobsId=pscomp_proc_jobs, PidsId=pscomp_proc_pids, [ register(JobMeta1, VnodeItem, Self) || VnodeItem <- [ VnodeItem1, VnodeItem2 ] ], [ ?_assertEqual(2, num_items(JobsId, JobMeta1) ), ?_assertEqual(1, num_items(PidsId, Self) ), ?_assertMatch(ok, unregister(JobMeta1, Self) ), ?_assertEqual(0, num_items(JobsId, JobMeta1) ), ?_assertEqual(0, num_items(PidsId, Self) ) ]. search_t(_State) -> Self = self(), JobMeta1 = {pscomp1, sample1, Self}, VnodeItem1 = {111111111112234455666, Self}, VnodeItem2 = {212313123486898080821, Self}, [ ?_assertMatch(ok, register(JobMeta1, VnodeItem1, Self) ), ?_assertEqual(true, is_pid( whereis_job(JobMeta1) ) ), ?_assertMatch(ok, register(JobMeta1, VnodeItem2, Self) ), ?_assertEqual(1, num_registered_pids() ), ?_assertEqual(2, lists:sum( lists:map(fun(_X) -> 1 end, jobs(JobMeta1) ) ) ) ]. auto_unregister_t(_) -> JobMeta = {pscomp1, sample1, self()}, Pid = spawn_link(fun() -> callback(JobMeta) end), timer:sleep(15), Ref = make_ref(), WherePid1 = whereis_job(JobMeta), whereis_job(JobMeta) ! {self(), Ref, hi}, Rec = receive {Ref, hi} -> true after 2000 -> false end, exit(Pid, kill), WherePid2 = whereis_job(JobMeta), [ ?_assert( is_pid(WherePid1) ), ?_assert(Rec), ?_assertEqual(undefined, WherePid2) ]. %%%%%%%%%%%%%%%%%%%%%%%% %%% HELPER FUNCTIONS %%% %%%%%%%%%%%%%%%%%%%%%%%% callback(JobMeta) -> ok = register(JobMeta, _VnodeItem1 = {111111111112234455666, self()}, self()), receive {From, Ref, Msg} -> From ! {Ref, Msg} end. num_items(TabId, LookupItem) -> case ets:lookup(TabId, LookupItem) of [] -> 0; [{_Pid, Items}] -> lists:sum( lists:map(fun(_X) -> 1 end, Items) ) end.