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("escalus/include/escalus_xmlns.hrl"). 21: -include_lib("exml/include/exml.hrl"). 22: 23: -import(config_parser_helper, [mod_config_with_auto_backend/2]). 24: 25: %%-------------------------------------------------------------------- 26: %% Suite configuration 27: %%-------------------------------------------------------------------- 28: 29: all() -> 30: [{group, valid_queries}, 31: {group, invalid_queries}]. 32: 33: groups() -> 34: [{valid_queries, [sequence], valid_test_cases()}, 35: {invalid_queries, invalid_test_cases()}]. 36: 37: valid_test_cases() -> [online_user_query, 38: last_online_user, 39: last_offline_user, 40: last_server]. 41: 42: invalid_test_cases() -> [user_not_subscribed_receives_error]. 43: 44: suite() -> 45: escalus:suite(). 46: 47: init_per_suite(Config0) -> 48: HostType = domain_helper:host_type(), 49: Config1 = dynamic_modules:save_modules(HostType, Config0), 50: dynamic_modules:ensure_modules(HostType, required_modules()), 51: escalus:init_per_suite(Config1). 52: 53: end_per_suite(Config) -> 54: dynamic_modules:restore_modules(Config), 55: escalus:end_per_suite(Config). 56: 57: init_per_group(valid_queries, Config0) -> 58: Config1 = escalus_fresh:create_users(Config0, [{alice, 1}, {bob, 1}]), 59: Config2 = escalus:make_everyone_friends(Config1), 60: %% This check ensures that there are no registered sessions. 61: %% But in mongoose_c2s we first unset session, 62: %% then broadcast presence unavailable. 63: %% This check uses ejabberd_sm to get information about sessions. 64: escalus_ejabberd:wait_for_session_count(Config2, 0), 65: %% Kick "friendly" users 66: %% kick_everyone uses mongoose_c2s_sup to information about client processes. 67: mongoose_helper:kick_everyone(), 68: Config2; 69: init_per_group(invalid_queries, Config) -> 70: Config. 71: 72: end_per_group(_GroupName, _Config) -> 73: escalus_fresh:clean(). 74: 75: init_per_testcase(CaseName, Config) -> 76: escalus:init_per_testcase(CaseName, Config). 77: 78: end_per_testcase(CaseName, Config) -> 79: mongoose_helper:kick_everyone(), 80: escalus:end_per_testcase(CaseName, Config). 81: 82: %%-------------------------------------------------------------------- 83: %% Last tests 84: %%-------------------------------------------------------------------- 85: online_user_query(Config) -> 86: %% Alice and Bob are friends 87: escalus:story(Config, [{alice, 1}, {bob, 1}], 88: fun(Alice, Bob) -> 89: %% Alice asks about Bob's last activity 90: BobJid = escalus_utils:get_jid(Bob), 91: escalus_client:send(Alice, escalus_stanza:last_activity(BobJid)), 92: %% Bob gets IQ and answers 93: BobGetsIQ = escalus_client:wait_for_stanza(Bob), 94: escalus_client:send(Bob, answer_last_activity(BobGetsIQ)), 95: Stanza = escalus_client:wait_for_stanza(Alice), 96: escalus:assert(is_last_result, Stanza), 97: 0 = get_last_activity(Stanza) 98: end). 99: 100: last_online_user(Config) -> 101: %% Alice and Bob are friends 102: escalus:story(Config, [{alice, 1}, {bob, 1}], 103: fun(Alice, Bob) -> 104: %% Alice asks about Bob's last activity 105: BobShortJID = escalus_client:short_jid(Bob), 106: escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)), 107: 108: %% server replies on Bob's behalf 109: Stanza = escalus_client:wait_for_stanza(Alice), 110: escalus:assert(is_last_result, Stanza), 111: 0 = get_last_activity(Stanza) 112: end). 113: 114: last_offline_user(Config) -> 115: %% Alice and Bob are friends 116: escalus:story(Config, [{alice, 1}], 117: fun(Alice) -> 118: %% Bob logs in 119: {ok, Bob} = escalus_client:start_for(Config, bob, <<"bob">>), 120: 121: %% Bob logs out with a status 122: Status = escalus_stanza:tags([{<<"status">>, <<"I am a banana!">>}]), 123: Presence = escalus_stanza:presence(<<"unavailable">>, Status), 124: escalus_client:send(Bob, Presence), 125: escalus_client:stop(Config, Bob), 126: timer:sleep(1024), % more than a second 127: 128: %% Alice asks for Bob's last availability 129: BobShortJID = escalus_client:short_jid(Bob), 130: escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)), 131: 132: %% Alice receives Bob's status and last online time > 0 133: Stanza = escalus_client:wait_for_stanza(Alice), 134: escalus:assert(is_last_result, Stanza), 135: true = (1 =< get_last_activity(Stanza)), 136: <<"I am a banana!">> = get_last_status(Stanza) 137: end). 138: 139: last_server(Config) -> 140: %% This story can be fresh_story 141: escalus:fresh_story(Config, [{alice, 1}], 142: fun(Alice) -> 143: %% Alice asks for server's uptime 144: Server = escalus_users:get_server(Config, alice), 145: escalus_client:send(Alice, escalus_stanza:last_activity(Server)), 146: 147: %% Server replies with the uptime > 0 148: Stanza = escalus_client:wait_for_stanza(Alice), 149: escalus:assert(is_last_result, Stanza), 150: true = (get_last_activity(Stanza) > 0) 151: end). 152: 153: user_not_subscribed_receives_error(Config) -> 154: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 155: %% Alice asks about Bob's last activity 156: BobShortJID = escalus_client:short_jid(Bob), 157: escalus_client:send(Alice, escalus_stanza:last_activity(BobShortJID)), 158: 159: %% server replies with an error, since there is no subscription 160: Error = escalus_client:wait_for_stanza(Alice), 161: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error), 162: 163: %% Alice asks Bob directly for last activity 164: BobFullJID = escalus_client:full_jid(Bob), 165: escalus_client:send(Alice, escalus_stanza:last_activity(BobFullJID)), 166: 167: Error1 = escalus_client:wait_for_stanza(Alice), 168: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error1), 169: ok 170: end). 171: 172: 173: %%----------------------------------------------------------------- 174: %% Helpers 175: %%----------------------------------------------------------------- 176: get_last_activity(Stanza) -> 177: S = exml_query:path(Stanza, [{element, <<"query">>}, {attr, <<"seconds">>}]), 178: list_to_integer(binary_to_list(S)). 179: 180: get_last_status(Stanza) -> 181: exml_query:path(Stanza, [{element, <<"query">>}, cdata]). 182: 183: answer_last_activity(IQ = #xmlel{name = <<"iq">>}) -> 184: From = exml_query:attr(IQ, <<"from">>), 185: To = exml_query:attr(IQ, <<"to">>), 186: Id = exml_query:attr(IQ, <<"id">>), 187: #xmlel{name = <<"iq">>, 188: attrs = [{<<"from">>, To}, {<<"to">>, From}, {<<"id">>, Id}, {<<"type">>, <<"result">>}], 189: children = [#xmlel{name = <<"query">>, 190: attrs = [{<<"xmlns">>, ?NS_LAST_ACTIVITY}, 191: {<<"seconds">>, <<"0">>}]} 192: ]}. 193: 194: required_modules() -> 195: [{mod_last, mod_config_with_auto_backend(mod_last, #{iqdisc => one_queue})}].