chut / src / chut_SUITE.erl

%%%-------------------------------------------------------------------
%%% File    : chut_user_SUITE.erl
%%% Description: Basic tests for a user and its clients
%%%
%%% Created : 2009/12/23
%%%-------------------------------------------------------------------
-module(chut_SUITE).
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
%% Function: suite() -> Info
%% Info = [tuple()]
%%--------------------------------------------------------------------
suite() ->
    [{timetrap,{seconds,30}}].
%%--------------------------------------------------------------------
%% Function: init_per_suite(Config0) ->
%%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
%% Config0 = Config1 = [tuple()]
%% Reason = term()
%%--------------------------------------------------------------------
init_per_suite(Config) ->
    {ok, Pid} = chut_user_supersup:start_link(),
    unlink(Pid),
    Config.
%%--------------------------------------------------------------------
%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
%% Config0 = Config1 = [tuple()]
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
    exit(whereis(chut_user_supersup), kill),
    ok.
%%--------------------------------------------------------------------
%% Function: init_per_group(GroupName, Config0) ->
%%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
%% GroupName = atom()
%% Config0 = Config1 = [tuple()]
%% Reason = term()
%%--------------------------------------------------------------------
init_per_group(_GroupName, Config) ->
    Config.
%%--------------------------------------------------------------------
%% Function: end_per_group(GroupName, Config0) ->
%%               void() | {save_config,Config1}
%% GroupName = atom()
%% Config0 = Config1 = [tuple()]
%%--------------------------------------------------------------------
end_per_group(_GroupName, _Config) ->
    ok.
%%--------------------------------------------------------------------
%% Function: init_per_testcase(TestCase, Config0) ->
%%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
%% TestCase = atom()
%% Config0 = Config1 = [tuple()]
%% Reason = term()
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
    Config.
%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config0) ->
%%               void() | {save_config,Config1} | {fail,Reason}
%% TestCase = atom()
%% Config0 = Config1 = [tuple()]
%% Reason = term()
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
    ok.
%%--------------------------------------------------------------------
%% Function: groups() -> [Group]
%% Group = {GroupName,Properties,GroupsAndTestCases}
%% GroupName = atom()
%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
%% TestCase = atom()
%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
%%              repeat_until_any_ok | repeat_until_any_fail
%% N = integer() | forever
%%--------------------------------------------------------------------
groups() ->
    [].
%%--------------------------------------------------------------------
%% Function: all() -> GroupsAndTestCases | {skip,Reason}
%% GroupsAndTestCases = [{group,GroupName} | TestCase]
%% GroupName = atom()
%% TestCase = atom()
%% Reason = term()
%%--------------------------------------------------------------------
all() -> 
    [chut_user_timeout, chut_user_subscribe, chut_user_message, chut_user_relay, chut_user_conv,
     chut_user_hist,
     chut_client_conv, two_chut_clients_one_chut_user, chut_client_aware_crashed_user,
     chut_client_hist].

%%--------------------------------------------------------------------
%% Function: chut_user_timeout(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: tests that a user without any clients attached to it
%% times out in due time.
%%--------------------------------------------------------------------
chut_user_timeout(_Config) ->
    Id = make_ref(),
    [Sleep, Expected] = [500, [{monitor, Id}, Id, {manager,Id}]],
    IsProc = fun(Name) -> lists:member(Name, global:registered_names()) end,
    chut_user:start(Id, Sleep, 0),
    true = lists:all(IsProc, Expected),
    timer:sleep(Sleep*3),
    false = lists:any(IsProc, Expected),
    ok.

%%--------------------------------------------------------------------
%% Function: chut_user_subscribe(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Checks that a client listening to a user keeps it from
%% timing out, and that once it stops listening, the user does time out.
%%--------------------------------------------------------------------
chut_user_subscribe(_Config) ->
    Id = make_ref(),
    [Sleep, Expected] = [500, [{monitor, Id}, Id, {manager,Id}]],
    IsProc = fun(Name) -> lists:member(Name, global:registered_names()) end,
    chut_user:start(Id, Sleep, 0),
    {ok, Handler} = chut_user:subscribe(Id),
    timer:sleep(Sleep*3),
    true = lists:all(IsProc, Expected),
    chut_user:unsubscribe(Id, Handler),
    process_flag(trap_exit, true),
    timer:sleep(Sleep*3),
    false = lists:any(IsProc, Expected),
    receive
        {'EXIT',_Pid, killed} -> ok
    after 500 ->
        io:format("Process won't die after the event manager did!~n")
    end,
    ok.

%%--------------------------------------------------------------------
%% Function: chut_user_message(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Tests that a client's listener notifies said client
%% whenever a message is sent from the user the listener is attached
%% to.
%%--------------------------------------------------------------------
chut_user_message(_Config) ->
    chut_user:start(send_id, 500, 0),
    {ok, Handler} = chut_user:subscribe(send_id),
    chut_user:message(send_id, invalid_id, hello),
    X = receive
            {{send_id, Handler}, {sent, invalid_id, hello}} -> true
        after 1000 -> throw("Message not sent")
        end,
    chut_user:unsubscribe(send_id, Handler),
    true = X.

%%--------------------------------------------------------------------
%% Function: chut_user_relay(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Confirms that a client listening to a user that
%% receives a message also receives the same message.
%%--------------------------------------------------------------------
chut_user_relay(_Config) ->
    chut_user:start(sender, 500, 0),
    {ok, HandlerS} = chut_user:subscribe(sender),
    chut_user:start(rec, 500, 0),
    {ok, HandlerR} = chut_user:subscribe(rec),
    chut_user:message(sender, rec, hello),
    X = receive
            {{rec,HandlerR}, {received, sender, hello}} -> true
        after 1000 -> throw("Message not received")
        end,
    chut_user:unsubscribe(sender, HandlerS),
    chut_user:unsubscribe(rec, HandlerR),
    true = X.

%%--------------------------------------------------------------------
%% Function: chut_user_conv(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Simulates a conversation between two different users
%% with one client each.
%%--------------------------------------------------------------------
chut_user_conv(_Config) ->
    {A,B} = {make_ref(), make_ref()},
    chut_user:start(A, 500, 0),
    {ok, HandlerA} = chut_user:subscribe(A),
    chut_user:start(B, 500, 0),
    {ok, HandlerB} = chut_user:subscribe(B),
    chut_user:message(A,B,"Hello, B"),
    chut_user:message(B,A,"Oh, Hello, A!"),
    receive {{B,HandlerB}, {received, A, "Hello, B"}} -> ok
    after 500 -> throw("Message not received")
    end,
    receive {{A,HandlerA}, {sent, B, "Hello, B"}} -> ok
    after 500 -> throw("Message not sent")
    end,
    receive {{A,HandlerA}, {received, B, "Oh, Hello, A!"}} -> ok
    after 500 -> throw("Message not received")
    end,
    receive {{B,HandlerB}, {sent, A, "Oh, Hello, A!"}} -> ok
    after 500 -> throw ("Message not sent")
    end,
    chut_user:message(A,B, "Well, goodbye!"),
    chut_user:message(B,A, "Have a nice day..."),
    receive {{B,HandlerB}, {received, A, "Well, goodbye!"}} -> ok
    after 500 -> throw("Message not received")
    end,
    receive {{A,HandlerA}, {sent, B, "Well, goodbye!"}} -> ok
    after 500 -> throw("Message not sent")
    end,
    receive {{A,HandlerA}, {received, B, "Have a nice day..."}} -> ok
    after 500 -> throw("Message not received")
    end,
    receive {{B,HandlerB}, {sent, A, "Have a nice day..."}} -> ok
    after 500 -> throw ("Message not sent")
    end,
    chut_user:unsubscribe(A, HandlerA),
    chut_user:unsubscribe(B, HandlerB).


%%--------------------------------------------------------------------
%% Function: chut_user_hist(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Simulates a short conversation and checks that a
%% history log can be obtained.
%%--------------------------------------------------------------------
chut_user_hist(_Config) ->
    {A,B} = {make_ref(), make_ref()},
    chut_user:start(A, 500, 2),
    {ok, HandlerA} = chut_user:subscribe(A),
    chut_user:start(B, 500, 0),
    {ok, HandlerB} = chut_user:subscribe(B),
    [] = chut_user:history(A),
    chut_user:message(A,B,"Hello, B"),
    chut_user:message(B,A,"Oh, Hello, A!"),
    timer:sleep(500),
    [{sent,B,"Hello, B"},
     {received,B,"Oh, Hello, A!"}] = chut_user:history(A),
    chut_user:message(A,B,"Hello2, B"),
    timer:sleep(500),
    [{received,B,"Oh, Hello, A!"},
     {sent,B,"Hello2, B"}] = chut_user:history(A),
    chut_user:unsubscribe(A,HandlerA),
    chut_user:unsubscribe(B,HandlerB).

%%--------------------------------------------------------------------
%% Function: chut_client_conv(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Simulates a conversation between two different users
%% with one client each, through the chut_client module this time.
%%--------------------------------------------------------------------
chut_client_conv(_Config) ->
    {A,B} = {make_ref(), make_ref()},
    {ok, ConnA} = chut_client:connect(A),
    {ok, ConnB} = chut_client:connect(B),
    chut_client:message(A,B,"hi"),
    [{sent, B, "hi"}] = chut_client:listen(A,ConnA),
    chut_client:message(A,B, "you there?"),
    timer:sleep(50), %% simulate delays to group messages
    [{received, A, "hi"},{received, A, "you there?"}] = chut_client:listen(B,ConnB),
    chut_client:message(B,A, "stop harassing me!"),
    timer:sleep(50), %% simulate delays to group messages
    [{sent, B, "you there?"},
     {received,B, "stop harassing me!"}] = chut_client:listen(A,ConnA),
    [{sent, A, "stop harassing me!"}] = chut_client:listen(B,ConnB),
    chut_client:disconnect(A,ConnA),
    chut_client:disconnect(B,ConnB).

%%--------------------------------------------------------------------
%% Function: two_chut_clients_one_chut_user(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: tests that two clients can be listening to the same
%% user within the same process.
%%--------------------------------------------------------------------
two_chut_clients_one_chut_user(_Config) ->
    A = make_ref(),
    {ok, ConnA} = chut_client:connect(A),
    {ok, ConnB} = chut_client:connect(A),
    chut_client:message(A,A,"hi"),
    [{sent, A, "hi"},{received, A, "hi"}] = chut_client:listen(A,ConnA),
    [{sent, A, "hi"},{received, A, "hi"}] = chut_client:listen(A,ConnB),
    chut_client:disconnect(A,ConnA),
    chut_client:disconnect(A,ConnB).

%%--------------------------------------------------------------------
%% Function: chut_client_aware_crashed_user(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Checks that a client listening to a given user is
%% notified of the user's death and exits the same way.
%%--------------------------------------------------------------------
chut_client_aware_crashed_user(_Config) ->
    A = make_ref(),
    {ok, H} = chut_client:connect(A),
    chut_user:terminate(A),
    try chut_client:listen(A,H) of
        _ -> throw(no_dead_signal)
    catch
        exit:Reason -> Reason
    end.

%%--------------------------------------------------------------------
%% Function: chut_client_hist(_) ->
%%               ok | exit() | {skip,Reason} | {comment,Comment} |
%%               {save_config,Config1} | {skip_and_save,Reason,Config1}
%% Reason = term()
%% Comment = term()
%% Description: Checks that a client can receive the history log from
%% the user processes. Should just be a wrapper around chut_user:history/1
%%--------------------------------------------------------------------
chut_client_hist(_Config) ->
    {A,B} = {make_ref(),make_ref()},
    {ok, HA} = chut_client:connect(A),
    {ok, HB} = chut_client:connect(B),
    [] = chut_client:history(B),
    chut_client:message(A,B,"hah!"),
    chut_client:message(A,B,"hoh!"),
    timer:sleep(200),
    [{sent,B,"hah!"},{sent,B,"hoh!"}] = chut_client:history(A),
    chut_client:disconnect(A,HA),
    chut_client:disconnect(B,HB).
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.