1: %%==============================================================================
    2: %% Copyright 2011 Erlang Solutions Ltd.
    3: %%
    4: %% Licensed under the Apache License, Version 2.0 (the "License");
    5: %% you may not use this file except in compliance with the License.
    6: %% You may obtain a copy of the License at
    7: %%
    8: %% http://www.apache.org/licenses/LICENSE-2.0
    9: %%
   10: %% Unless required by applicable law or agreed to in writing, software
   11: %% distributed under the License is distributed on an "AS IS" BASIS,
   12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13: %% See the License for the specific language governing permissions and
   14: %% limitations under the License.
   15: %%==============================================================================
   16: -module(last_SUITE).
   17: -compile([export_all, nowarn_export_all]).
   18: 
   19: -include_lib("escalus/include/escalus.hrl").
   20: -include_lib("common_test/include/ct.hrl").
   21: 
   22: %%--------------------------------------------------------------------
   23: %% Suite configuration
   24: %%--------------------------------------------------------------------
   25: 
   26: all() ->
   27:     [{group, valid_queries},
   28:      {group, invalid_queries}].
   29: 
   30: groups() ->
   31:     G = [{valid_queries, [sequence], valid_test_cases()},
   32:          {invalid_queries, invalid_test_cases()}],
   33:     ct_helper:repeat_all_until_all_ok(G).
   34: 
   35: valid_test_cases() -> [last_online_user,
   36:                        last_offline_user,
   37:                        last_server].
   38: 
   39: invalid_test_cases() -> [user_not_subscribed_receives_error].
   40: 
   41: suite() ->
   42:     escalus:suite().
   43: 
   44: init_per_suite(Config0) ->
   45:     HostType = domain_helper:host_type(),
   46:     Config1 = dynamic_modules:save_modules(HostType, Config0),
   47:     Backend = mongoose_helper:get_backend_mnesia_rdbms_riak(HostType),
   48:     dynamic_modules:ensure_modules(HostType, required_modules(Backend)),
   49:     escalus:init_per_suite([{backend, Backend} | Config1]).
   50: 
   51: end_per_suite(Config) ->
   52:     dynamic_modules:restore_modules(Config),
   53:     escalus:end_per_suite(Config).
   54: 
   55: init_per_group(valid_queries, Config0) ->
   56:     Config1 = escalus_fresh:create_users(Config0, [{alice, 1}, {bob, 1}]),
   57:     Config2 = escalus:make_everyone_friends(Config1),
   58:     %% This check ensures that there are no registered sessions.
   59:     %% But in ejabberd_c2s we first unset session,
   60:     %% then broadcast presence unavailable.
   61:     %% This check uses ejabberd_sm to get information about sessions.
   62:     escalus_ejabberd:wait_for_session_count(Config2, 0),
   63:     %% Kick "friendly" users
   64:     %% kick_everyone uses ejabberd_c2s_sup to information about client processes.
   65:     mongoose_helper:kick_everyone(),
   66:     Config2;
   67: init_per_group(invalid_queries, Config) ->
   68:     Config.
   69: 
   70: end_per_group(_GroupName, _Config) ->
   71:     escalus_fresh:clean().
   72: 
   73: init_per_testcase(CaseName, Config) ->
   74:     escalus:init_per_testcase(CaseName, Config).
   75: 
   76: end_per_testcase(CaseName, Config) ->
   77:     mongoose_helper:kick_everyone(),
   78:     escalus:end_per_testcase(CaseName, Config).
   79: 
   80: %%--------------------------------------------------------------------
   81: %% Last tests
   82: %%--------------------------------------------------------------------
   83: last_online_user(Config) ->
   84:     %% Alice and Bob are friends
   85:     escalus:story(Config, [{alice, 1}, {bob, 1}],
   86:                   fun(Alice, Bob) ->
   87:                           %% Alice asks about Bob's last activity
   88:                           BobShortJID = escalus_client:short_jid(Bob),
   89:                           escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)),
   90: 
   91:                           %% server replies on Bob's behalf
   92:                           Stanza = escalus_client:wait_for_stanza(Alice),
   93:                           escalus:assert(is_last_result, Stanza),
   94:                           0 = get_last_activity(Stanza)
   95:                   end).
   96: 
   97: last_offline_user(Config) ->
   98:     %% Alice and Bob are friends
   99:     escalus:story(Config, [{alice, 1}],
  100:                   fun(Alice) ->
  101:                           %% Bob logs in
  102:                           {ok, Bob} = escalus_client:start_for(Config, bob, <<"bob">>),
  103: 
  104:                           %% Bob logs out with a status
  105:                           Status = escalus_stanza:tags([{<<"status">>, <<"I am a banana!">>}]),
  106:                           Presence = escalus_stanza:presence(<<"unavailable">>, Status),
  107:                           escalus_client:send(Bob, Presence),
  108:                           escalus_client:stop(Config, Bob),
  109:                           timer:sleep(1024), % more than a second
  110: 
  111:                           %% Alice asks for Bob's last availability
  112:                           BobShortJID = escalus_client:short_jid(Bob),
  113:                           escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)),
  114: 
  115:                           %% Alice receives Bob's status and last online time > 0
  116:                           Stanza = escalus_client:wait_for_stanza(Alice),
  117:                           escalus:assert(is_last_result, Stanza),
  118:                           true = (1 =< get_last_activity(Stanza)),
  119:                           <<"I am a banana!">> = get_last_status(Stanza)
  120:                   end).
  121: 
  122: last_server(Config) ->
  123:     %% This story can be fresh_story
  124:     escalus:story(Config, [{alice, 1}],
  125:                   fun(Alice) ->
  126:                           %% Alice asks for server's uptime
  127:                           Server = escalus_users:get_server(Config, alice),
  128:                           escalus_client:send(Alice, escalus_stanza:last_activity(Server)),
  129: 
  130:                           %% Server replies with the uptime > 0
  131:                           Stanza = escalus_client:wait_for_stanza(Alice),
  132:                           escalus:assert(is_last_result, Stanza),
  133:                           true = (get_last_activity(Stanza) > 0)
  134:                   end).
  135: 
  136: user_not_subscribed_receives_error(Config) ->
  137:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  138:         %% Alice asks about Bob's last activity
  139:         BobShortJID = escalus_client:short_jid(Bob),
  140:         escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)),
  141: 
  142:         %% server replies with an error, since there is no subscription
  143:         Error = escalus_client:wait_for_stanza(Alice),
  144:         escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error),
  145: 
  146:         BobFullJID = escalus_client:full_jid(Bob),
  147:         escalus_client:send(Alice, escalus_stanza:last_activity(BobFullJID)),
  148: 
  149:         Error1 = escalus_client:wait_for_stanza(Alice),
  150:         escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error1),
  151:         ok
  152:     end).
  153: 
  154: 
  155: %%-----------------------------------------------------------------
  156: %% Helpers
  157: %%-----------------------------------------------------------------
  158: get_last_activity(Stanza) ->
  159:     S = exml_query:path(Stanza, [{element, <<"query">>}, {attr, <<"seconds">>}]),
  160:     list_to_integer(binary_to_list(S)).
  161: 
  162: get_last_status(Stanza) ->
  163:     exml_query:path(Stanza, [{element, <<"query">>}, cdata]).
  164: 
  165: required_modules(Backend) ->
  166:     [{mod_last, [{backend, Backend}]}].