%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1998-2013. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(ose_SUITE). %-compile(export_all). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,init_per_testcase/2, end_per_testcase/2]). -export([ basic/1,stress/1,multi_msg_numbers/1,multi_mailboxes/1, hunt/1,multi_hunt/1,dehunt/1,multi_dehunt/1, attach/1,multi_attach/1,detach/1,multi_detach/1, open_errors/1,close_errors/1,get_id_errors/1,get_name_errors/1, hunt_errors/1,dehunt_errors/1,attach_errors/1,detach_errors/1, send_errors/1,send_w_s_errors/1,listen_errors/1 ]). -define(INTERFACE,ose). init_per_testcase(_Func, Config) -> Config. end_per_testcase(_Func, _Config) -> ok. suite() -> [{timeout,{30,seconds}}]. all() -> [ basic,stress,multi_msg_numbers,multi_mailboxes, hunt,multi_hunt,dehunt,multi_dehunt, attach,multi_attach,detach,multi_detach, open_errors,close_errors,get_id_errors,get_name_errors, hunt_errors,dehunt_errors,attach_errors,detach_errors, send_errors,send_w_s_errors,listen_errors ]. groups() -> []. init_per_suite(Config) -> case os:type() of {ose,_} -> Config; _Else -> {skip,"Only run on OSE"} end. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. basic(_Config) -> [P1,P2] = multi_open(2,[42]), P1Id = ?INTERFACE:get_id(P1), P2Id = ?INTERFACE:get_id(P2), ok = ?INTERFACE:send(P2,P1Id,42,<<"ping">>), receive {message,P1,V1} -> {P2Id,P1Id,42,<<"ping">>} = V1, ?INTERFACE:send(P1,P2Id,42,<<"pong">>); Else1 -> ct:fail({got_wrong_message,Else1}) end, receive {message,P2,V2} -> {P1Id,P2Id,42,<<"pong">>} = V2; Else2 -> ct:fail({got_wrong_message,Else2}) end, ?INTERFACE:close(P1), ?INTERFACE:close(P2). %% Send 1000 messages and see if we can cope and that msg order is preserved stress(_Config) -> Iterations = 1000, [P1,P2] = multi_open(2,[42]), P1Id = ?INTERFACE:get_id(P1), P2Id = ?INTERFACE:get_id(P2), spawn(fun() -> n(fun(N) -> Msg = [<<"ping">>|integer_to_list(N)], ?INTERFACE:send(P2,P1Id,42,Msg) end,Iterations) end), timer:sleep(100), n(fun(N) -> receive {message,P1,Value} -> Int = integer_to_binary(N), {P2Id,P1Id,42,<<"ping",Int/binary>>} = Value, ok; Else -> ct:fail({got_wrong_message,Else}) end end,Iterations), ?INTERFACE:close(P1), ?INTERFACE:close(P2). %% Listen to 1000 different message numbers and send some random messages multi_msg_numbers(_Config) -> Iterations = 100, [P1,P2] = multi_open(2,lists:seq(2000,3000)), P1Id = ?INTERFACE:get_id(P1), n(fun(_) -> Num = random:uniform(1000)+2000, ?INTERFACE:send(P2,P1Id,Num,<<"ping",(integer_to_binary(Num))/binary>>) end,Iterations), n(fun(_) -> receive {message,P1,{_,_,Id,<<"ping",Num/binary>>}} when Id > 2000; Id =< 3000 -> Id = binary_to_integer(Num), ok; Else -> ct:fail({got_wrong_message,Else}) end end,Iterations), ?INTERFACE:close(P1), ?INTERFACE:close(P2). %% Create 100 mailboxes and send messages to them multi_mailboxes(_Config) -> Mailboxes = 100, [P1|MBs] = multi_open(Mailboxes,[42]), [?INTERFACE:send(P1,?INTERFACE:get_id(P),42,[<<"ping">>,?INTERFACE:get_name(P,?INTERFACE:get_id(P))]) || P <- MBs], [receive {message,P,Value} -> Name = ?INTERFACE:get_name(P,?INTERFACE:get_id(P)), {_,_,42,<<"ping",Name/binary>>} = Value, ok end || P <- MBs], [?INTERFACE:close(P) || P <- [P1|MBs]], ok. hunt(_Config) -> [P1,P2] = multi_open(2,[]), Ref = ?INTERFACE:hunt(P1,"p2"), receive {mailbox_up,P1,Ref,Pid} -> Pid = ?INTERFACE:get_id(P2), ?INTERFACE:close(P1), ?INTERFACE:close(P2); Else -> ct:fail({got_wrong_message,Else,Ref}) end. multi_hunt(_Config) -> Iterations = 100, P = ?INTERFACE:open("p"), Refs = [?INTERFACE:hunt(P,"p"++integer_to_list(N))|| N <- lists:seq(1,Iterations)], Pids = [begin Prt = ?INTERFACE:open("p"++integer_to_list(N)), Pid = ?INTERFACE:get_id(Prt), ?INTERFACE:close(Prt), Pid end || N <- lists:seq(1,Iterations)], [receive {mailbox_up,P,Ref,Pid} -> ok after 10 -> ct:fail({did_not_get,Pid,Ref}) end || {Pid,Ref} <- lists:zip(Pids,Refs)], ?INTERFACE:close(P). dehunt(_Config) -> [P1] = multi_open(1,[]), Ref = ?INTERFACE:hunt(P1,"p2"), receive _Else -> ct:fail({got,_Else}) after 1000 -> ok end, P2 = ?INTERFACE:open("p2"), % Make sure any messages are sent receive after 10 -> ok end, ok = ?INTERFACE:dehunt(P1,Ref), % Make sure no messages are received receive _Else2 -> ct:fail({got,_Else2}) after 1000 -> ?INTERFACE:close(P1), ?INTERFACE:close(P2) end. %%% %%% This testcase basically: %%% spawn 10 processes that in parallel %%% adds some hunts for different OSE processes %%% maybe create hunted OSE process %%% dehunt half of the hunts %%% create more hunts %%% if not created create hunted OSE process %%% veryify that all expected hunt messages are received %%% verify that all processes exited correctly %%% %%% This complex test is done to make sure that the internal handling %%% of dehunt works as expected. %%% multi_dehunt(_Config) -> [P1] = multi_open(1,[]), Scenario = fun(Iterations) -> Hunted = "p"++integer_to_list(Iterations), %% Start a couple of hunts Refs = [?INTERFACE:hunt(P1,Hunted) || _ <- lists:seq(1,Iterations)], %% We alternate if the process is opened before or after the dehunt P2O = if Iterations rem 2 == 0 -> ?INTERFACE:open(Hunted); true -> undefined end, %% Remove half of them {RemRefs,_} = lists:mapfoldl(fun(Ref,Acc) when Acc rem 2 == 0 -> ok = ?INTERFACE:dehunt(P1,Ref), {[],Acc+1}; (Ref,Acc) -> {Ref,Acc+1} end,0,Refs), %% Add some new ones NewRefs = [?INTERFACE:hunt(P1,Hunted) || _ <- lists:seq(1,Iterations div 4)] ++ lists:flatten(RemRefs), P2 = if P2O == undefined -> ?INTERFACE:open(Hunted); true -> P2O end, P2Id = ?INTERFACE:get_id(P2), %% Receive all the expected ones lists:foreach(fun(Ref) -> receive {mailbox_up,P1,Ref,P2Id} -> ok after 1000 -> io:format("Flush: ~p~n",[flush()]), io:format("~p~n",[{Iterations,{did_not_get, Ref}}]), ok = Ref end end,NewRefs), %% Check that no other have arrived receive _Else -> io:format("Flush: ~p~n",[flush()]), io:format("~p~n",[{Iterations,{got, _Else}}]), ok = _Else after 100 -> ok end, ?INTERFACE:close(P2) end, Self = self(), n(fun(N) -> spawn(fun() -> Self ! Scenario(N*25) end), ok end,10), n(fun(_N) -> receive ok -> ok after 60000 -> ct:fail(failed) end end,10), ?INTERFACE:close(P1). attach(_Config) -> [P1,P2] = multi_open(2,[]), P2Id = ?INTERFACE:get_id(P2), Ref = ?INTERFACE:attach(P1,P2Id), ?INTERFACE:close(P2), receive {mailbox_down,P1,Ref,P2Id} -> ?INTERFACE:close(P1); _Else -> ct:fail({got,_Else, {P1,Ref,P2Id}}) after 1000 -> ct:fail({did_not_get,P1,Ref,P2Id}) end. multi_attach(_Config) -> Iterations = 100, [P1|Pids] = multi_open(Iterations,[]), Refs = [{?INTERFACE:get_id(Pid),?INTERFACE:attach(P1,?INTERFACE:get_id(Pid))} || Pid <- Pids], [?INTERFACE:close(Pid) || Pid <- Pids], [receive {mailbox_down,P1,Ref,Pid} -> ok after 10000 -> ct:fail({did_not_get,Pid,Ref}) end || {Pid,Ref} <- Refs], ?INTERFACE:close(P1). detach(_Config) -> [P1,P2] = multi_open(2,[]), P2Id = ?INTERFACE:get_id(P2), Ref = ?INTERFACE:attach(P1,P2Id), receive _Else -> ct:fail({got,_Else}) after 100 -> ok end, ?INTERFACE:close(P2), % Make sure any messages are sent receive after 10 -> ok end, ?INTERFACE:detach(P1,Ref), % Make sure no messages are received receive _Else2 -> ct:fail({got,_Else2}) after 1000 -> ?INTERFACE:close(P1) end. %%% %%% This testcase basically: %%% spawn 10 processes that in parallel %%% adds some attach for different OSE processes %%% maybe close OSE process %%% dehunt half of the hunts %%% create more hunts %%% if not closed close attached OSE process %%% veryify that all expected attach messages are received %%% verify that all processes exited correctly %%% %%% This complex test is done to make sure that the internal handling %%% of dehunt works as expected. %%% multi_detach(_Config) -> [P1] = multi_open(1,[]), Scenario = fun(Iterations) -> Attached = ?INTERFACE:open("p"++integer_to_list(Iterations)), AttachedId = ?INTERFACE:get_id(Attached), %% Start a couple of attachs Refs = [?INTERFACE:attach(P1,AttachedId) || _ <- lists:seq(1,Iterations)], %% We alternate if the process is closed before or after the detach P2O = if Iterations rem 2 == 0 -> ?INTERFACE:close(Attached); true -> undefined end, %% Remove half of them {RemRefs,_} = lists:mapfoldl(fun(Ref,Acc) when Acc rem 2 == 0 -> ok = ?INTERFACE:detach(P1,Ref), {[],Acc+1}; (Ref,Acc) -> {Ref,Acc+1} end,0,Refs), %% Add some new ones NewRefs = [?INTERFACE:attach(P1,AttachedId) || _ <- lists:seq(1,Iterations div 4)] ++ lists:flatten(RemRefs), if P2O == undefined -> ?INTERFACE:close(Attached); true -> P2O end, %% Receive all the expected ones lists:foreach(fun(Ref) -> receive {mailbox_down,P1,Ref,AttachedId} -> ok after 1000 -> io:format("Flush: ~p~n",[flush()]), io:format("~p~n",[{Iterations,{did_not_get, Ref}}]), ok = Ref end end,NewRefs), %% Check that no other have arrived receive _Else -> io:format("Flush: ~p~n",[flush()]), io:format("~p~n",[{Iterations,{got, _Else}}]), ok = _Else after 100 -> ok end end, Self = self(), n(fun(N) -> spawn(fun() -> Self ! Scenario(N*5) end), ok end,10), n(fun(_N) -> receive ok -> ok after 60000 -> ct:fail(failed) end end,10), ?INTERFACE:close(P1). open_errors(_Config) -> {'EXIT',{badarg,[{?INTERFACE,open,[inval],_}|_]}} = (catch ?INTERFACE:open(inval)), {'EXIT',{badarg,[{?INTERFACE,open,[["p"|1]],_}|_]}} = (catch ?INTERFACE:open(["p"|1])), {'EXIT',{badarg,[{?INTERFACE,open,[["p",1234]],_}|_]}} = (catch ?INTERFACE:open(["p",1234])), ok. close_errors(_Config) -> {'EXIT',{badarg,[{?INTERFACE,close,[inval],_}|_]}} = (catch ?INTERFACE:close(inval)), P1 = ?INTERFACE:open("p1"), ok = ?INTERFACE:close(P1), ok = ?INTERFACE:close(P1). get_id_errors(_Config) -> {'EXIT',{badarg,[{?INTERFACE,get_id,[inval],_}|_]}} = (catch ?INTERFACE:get_id(inval)), P1 = ?INTERFACE:open("p1"), ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,get_id,[P1],_}|_]}} = (catch ?INTERFACE:get_id(P1)), ok. get_name_errors(_Config) -> P1 = ?INTERFACE:open("p1"), {'EXIT',{badarg,[{?INTERFACE,get_name,[P1,inval],_}|_]}} = (catch ?INTERFACE:get_name(P1,inval)), undefined = ?INTERFACE:get_name(P1,1234), P2 = ?INTERFACE:open("p2"), P2Id = ?INTERFACE:get_id(P2), ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,get_name,[P1,P2Id],_}|_]}} = (catch ?INTERFACE:get_name(P1,P2Id)), ?INTERFACE:close(P2), P3 = ?INTERFACE:open([255]), <<255>> = ?INTERFACE:get_name(P3, ?INTERFACE:get_id(P3)), ?INTERFACE:close(P3), ok. hunt_errors(_Config) -> {'EXIT',{badarg,[{?INTERFACE,hunt,[inval,"hello"],_}|_]}} = (catch ?INTERFACE:hunt(inval,"hello")), P1 = ?INTERFACE:open("p1"), {'EXIT',{badarg,[{?INTERFACE,hunt,[P1,["hello",12345]],_}|_]}} = (catch ?INTERFACE:hunt(P1,["hello",12345])), P2 = ?INTERFACE:open(<<255>>), P2Pid = ?INTERFACE:get_id(P2), Ref = ?INTERFACE:hunt(P1,[255]), receive {mailbox_up,P1,Ref,P2Pid} -> ok; Else -> ct:fail({got,Else,{mailbox_up,P1,Ref,P2Pid}}) after 150 -> ct:fail({did_not_get,{mailbox_up,P1,Ref,P2Pid}}) end, ok = ?INTERFACE:close(P1), ok = ?INTERFACE:close(P2), {'EXIT',{badarg,[{?INTERFACE,hunt,[P1,["hello"]],_}|_]}} = (catch ?INTERFACE:hunt(P1,["hello"])), ok. dehunt_errors(_Config) -> P1 = ?INTERFACE:open("p1"), Ref = ?INTERFACE:hunt(P1,"p2"), {'EXIT',{badarg,[{?INTERFACE,dehunt,[inval,Ref],_}|_]}} = (catch ?INTERFACE:dehunt(inval,Ref)), {'EXIT',{badarg,[{?INTERFACE,dehunt,[P1,inval],_}|_]}} = (catch ?INTERFACE:dehunt(P1,inval)), ok = ?INTERFACE:dehunt(P1,Ref), ok = ?INTERFACE:dehunt(P1,Ref), ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,dehunt,[P1,Ref],_}|_]}} = (catch ?INTERFACE:dehunt(P1,Ref)), case ?INTERFACE of ose -> ok; _ -> P2 = ?INTERFACE:open("p2"), ok = ?INTERFACE:close(P2) end, receive Else -> ct:fail({got,Else}) after 100 -> ok end. attach_errors(_Config) -> P1 = ?INTERFACE:open("p1"), P2 = ?INTERFACE:open("p2"), P2Id = ?INTERFACE:get_id(P2), {'EXIT',{badarg,[{?INTERFACE,attach,[inval,P2Id],_}|_]}} = (catch ?INTERFACE:attach(inval,P2Id)), {'EXIT',{badarg,[{?INTERFACE,attach,[P1,[12345]],_}|_]}} = (catch ?INTERFACE:attach(P1,[12345])), ok = ?INTERFACE:close(P1), ok = ?INTERFACE:close(P2), {'EXIT',{badarg,[{?INTERFACE,attach,[P1,P2Id],_}|_]}} = (catch ?INTERFACE:attach(P1,P2Id)), ok. detach_errors(_Config) -> P1 = ?INTERFACE:open("p1"), P2 = ?INTERFACE:open("p2"), P2Id = ?INTERFACE:get_id(P2), Ref = ?INTERFACE:attach(P1,P2Id), {'EXIT',{badarg,[{?INTERFACE,detach,[inval,Ref],_}|_]}} = (catch ?INTERFACE:detach(inval,Ref)), {'EXIT',{badarg,[{?INTERFACE,detach,[P1,inval],_}|_]}} = (catch ?INTERFACE:detach(P1,inval)), ok = ?INTERFACE:detach(P1,Ref), ok = ?INTERFACE:detach(P1,Ref), case ?INTERFACE of ose -> ok; _ -> ok = ?INTERFACE:close(P1) end, ok = ?INTERFACE:close(P2), ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,detach,[P1,Ref],_}|_]}} = (catch ?INTERFACE:detach(P1,Ref)), receive Else -> ct:fail({got,Else}) after 100 -> ok end. send_errors(_Config) -> P1 = ?INTERFACE:open("p1"), P2 = ?INTERFACE:open("p2"), P2Id = ?INTERFACE:get_id(P2), {'EXIT',{badarg,[{?INTERFACE,send,[inval,P2Id,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(inval,P2Id,42,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P1,inval,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(P1,inval,42,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P1,P2Id,inval,"hello"],_}|_]}} = (catch ?INTERFACE:send(P1,P2Id,inval,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P1,P2Id,42,inval],_}|_]}} = (catch ?INTERFACE:send(P1,P2Id,42,inval)), ok = ?INTERFACE:close(P2), ok = ?INTERFACE:send(P1,P2Id,42,"hello"), ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,send,[P1,P2Id,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(P1,P2Id,42,"hello")), receive Else -> ct:fail({got,Else}) after 100 -> ok end. send_w_s_errors(_Config) -> P1 = ?INTERFACE:open("p1"), P1Id = ?INTERFACE:get_id(P1), P2 = ?INTERFACE:open("p2"), P2Id = ?INTERFACE:get_id(P2), P3 = ?INTERFACE:open("p3"), P3Id = ?INTERFACE:get_id(P3), {'EXIT',{badarg,[{?INTERFACE,send,[inval,P2Id,P1Id,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(inval,P2Id,P1Id,42,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P2,-1,P1Id,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(P2,-1,P1Id,42,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P2,P2Id,1 bsl 32,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(P2,P2Id,1 bsl 32,42,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P2,P2Id,P1Id,inval,"hello"],_}|_]}} = (catch ?INTERFACE:send(P2,P2Id,P1Id,inval,"hello")), {'EXIT',{badarg,[{?INTERFACE,send,[P2,P2Id,P1Id,42,inval],_}|_]}} = (catch ?INTERFACE:send(P2,P2Id,P1Id,42,inval)), ok = ?INTERFACE:close(P3), ok = ?INTERFACE:send(P2,P3Id,P1Id,42,"hello"), ok = ?INTERFACE:close(P1), ok = ?INTERFACE:send(P2,P2Id,P1Id,42,"hello"), ok = ?INTERFACE:close(P2), {'EXIT',{badarg,[{?INTERFACE,send,[P1,P2Id,P1Id,42,"hello"],_}|_]}} = (catch ?INTERFACE:send(P1,P2Id,P1Id,42,"hello")), receive Else -> ct:fail({got,Else}) after 100 -> ok end. listen_errors(_Config) -> P1 = ?INTERFACE:open("p1"), P1Id = ?INTERFACE:get_id(P1), {'EXIT',{badarg,[{?INTERFACE,listen,[inval,[42]],_}|_]}} = (catch ?INTERFACE:listen(inval,[42])), {'EXIT',{badarg,[{?INTERFACE,listen,[P1,inval],_}|_]}} = (catch ?INTERFACE:listen(P1,inval)), {'EXIT',{badarg,[{?INTERFACE,listen,[P1,[1 bsl 33]],_}|_]}} = (catch ?INTERFACE:listen(P1,[1 bsl 33])), ok = ?INTERFACE:listen(P1,[42,42,42,42,42,42,42,42,42,42,42,42,42]), case ?INTERFACE of ose -> ok; _ -> ?INTERFACE:send(P1,P1Id,42,"hello"), timer:sleep(50), ?INTERFACE:listen(P1,[]), ?INTERFACE:send(P1,P1Id,42,"hello2"), receive {message,P1,42,"hello"} -> ok end, receive Else -> ct:fail({got,Else}) after 100 -> ok end end, ok = ?INTERFACE:close(P1), {'EXIT',{badarg,[{?INTERFACE,listen,[P1,[42]],_}|_]}} = (catch ?INTERFACE:listen(P1,[42])), ok. %% %% Internal functions %% multi_open(N,ListenNums) -> multi_open(N,ListenNums,[]). multi_open(0,_,Acc) -> Acc; multi_open(N,ListenNums,Acc) -> P = ?INTERFACE:open("p"++integer_to_list(N)), ok = ?INTERFACE:listen(P,ListenNums), multi_open(N-1,ListenNums,[P|Acc]). n(_F,0) -> ok; n(F,N) -> ok = F(N), n(F,N-1). flush() -> receive Msg -> [Msg|flush()] after 0 -> [] end.