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