1: %%============================================================================== 2: %% Copyright 2015 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: 17: -module(mod_time_SUITE). 18: -compile([export_all, nowarn_export_all]). 19: -include_lib("escalus/include/escalus.hrl"). 20: -include_lib("common_test/include/ct.hrl"). 21: -include_lib("eunit/include/eunit.hrl"). 22: -include_lib("escalus/include/escalus_xmlns.hrl"). 23: -include_lib("exml/include/exml.hrl"). 24: %%-------------------------------------------------------------------- 25: %% Suite configuration 26: %%-------------------------------------------------------------------- 27: 28: all() -> 29: [{group, mod_time}]. 30: 31: groups() -> 32: [{mod_time, [parallel], [ask_for_time, time_service_discovery]}]. 33: 34: suite() -> 35: escalus:suite(). 36: 37: %%-------------------------------------------------------------------- 38: %% Init & teardown 39: %%-------------------------------------------------------------------- 40: 41: init_per_suite(Config) -> 42: dynamic_modules:start(domain_helper:host_type(), mod_time, config_parser_helper:default_mod_config(mod_time)), 43: escalus:init_per_suite(Config). 44: 45: end_per_suite(Config) -> 46: dynamic_modules:stop(domain_helper:host_type(), mod_time), 47: escalus_fresh:clean(), 48: escalus:end_per_suite(Config). 49: 50: init_per_group(mod_time, Config) -> 51: Config. 52: 53: end_per_group(mod_time, Config) -> 54: Config. 55: 56: init_per_testcase(CaseName, Config) -> 57: escalus:init_per_testcase(CaseName, Config). 58: 59: end_per_testcase(CaseName, Config) -> 60: escalus:end_per_testcase(CaseName, Config). 61: 62: %%-------------------------------------------------------------------- 63: %% Time request test 64: %%-------------------------------------------------------------------- 65: 66: ask_for_time(Config) -> 67: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 68: Server = escalus_users:get_server(Config, alice), 69: ID = escalus_stanza:id(), 70: TimeStanza = time_request_stanza(Server, ID), 71: escalus_client:send(Alice, TimeStanza), 72: Reply = escalus:wait_for_stanza(Alice, 5000), 73: escalus:assert(is_iq_result, Reply), 74: escalus:assert(fun check_ns/1, Reply), 75: {Tzo, Utc} = time_from_stanza(Reply), 76: ?assertEqual(true, tzo_regex(Tzo)), 77: ?assertEqual(true, utc_regex(Utc)) 78: end). 79: 80: %%-------------------------------------------------------------------- 81: %% Service discovery test 82: %%-------------------------------------------------------------------- 83: 84: time_service_discovery(Config) -> 85: escalus:fresh_story( 86: Config, [{alice, 1}], 87: fun(Client) -> 88: ServJID = escalus_client:server(Client), 89: Res = escalus:send_and_wait(Client, 90: escalus_stanza:disco_info(ServJID)), 91: escalus:assert(is_iq_result, Res), 92: escalus:assert(has_feature, [?NS_TIME], Res) 93: end). 94: %%-------------------------------------------------------------------- 95: %% Helpers 96: %%-------------------------------------------------------------------- 97: 98: time_request_stanza(Server, ID) -> 99: #xmlel{name = <<"iq">>, 100: attrs = [{<<"type">>, <<"get">>}, 101: {<<"id">>, ID}, {<<"to">>, Server}], 102: children = [#xmlel{name = <<"time">>, 103: attrs = [{<<"xmlns">>, ?NS_TIME}]}]}. 104: 105: check_ns(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> 106: case Child of 107: #xmlel{name = <<"time">>, attrs = [{<<"xmlns">>, ?NS_TIME}], children = _} -> true; 108: _ -> false 109: end; 110: 111: check_ns(_) -> 112: false. 113: 114: time_from_stanza(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> 115: case Child of 116: #xmlel{name = <<"time">>, attrs = [{<<"xmlns">>, ?NS_TIME}], children = Times} -> 117: case Times of 118: [#xmlel{name = <<"tzo">>, attrs = _, children = [#xmlcdata{content = Tzo}]}, 119: #xmlel{name = <<"utc">>, attrs = _, children = [#xmlcdata{content = Utc}]}] -> 120: {Tzo, Utc}; 121: _ -> no_timezone 122: end; 123: _ -> wrong_stanza 124: end. 125: 126: %% check XEP-0082: XMPP Date and Time Profiles 127: tzo_regex(Tzo) -> 128: String = binary_to_list(Tzo), 129: {match, [{0, 6}]} = re:run(String, "^[+|-][0-9]{2}:[0-9]{2}"), 130: true. 131: 132: utc_regex(Utc) -> 133: String = binary_to_list(Utc), 134: {match, _} = re:run(String, "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3})?Z"), 135: true.