%%
%% %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.