diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/ejabberd_SUITE.erl | 12 | ||||
-rw-r--r-- | test/ejabberd_SUITE_data/ejabberd.yml | 16 | ||||
-rwxr-xr-x | test/ejabberd_SUITE_data/extauth.py | 26 | ||||
-rw-r--r-- | test/muc_tests.erl | 29 | ||||
-rw-r--r-- | test/push_tests.erl | 234 |
5 files changed, 300 insertions, 17 deletions
diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 17465617b..97c56159a 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -431,6 +431,7 @@ db_tests(DB) when DB == mnesia; DB == redis -> mam_tests:single_cases(), carbons_tests:single_cases(), csi_tests:single_cases(), + push_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), @@ -441,7 +442,8 @@ db_tests(DB) when DB == mnesia; DB == redis -> vcard_tests:master_slave_cases(), announce_tests:master_slave_cases(), carbons_tests:master_slave_cases(), - csi_tests:master_slave_cases()]; + csi_tests:master_slave_cases(), + push_tests:master_slave_cases()]; db_tests(_) -> [{single_user, [sequence], [test_register, @@ -748,25 +750,25 @@ test_component_send(Config) -> disconnect(Config). s2s_dialback(Config) -> - ejabberd_s2s:stop_all_connections(), + ejabberd_s2s:stop_s2s_connections(), ejabberd_config:add_option(s2s_use_starttls, false), ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), s2s_ping(Config). s2s_optional(Config) -> - ejabberd_s2s:stop_all_connections(), + ejabberd_s2s:stop_s2s_connections(), ejabberd_config:add_option(s2s_use_starttls, optional), ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), s2s_ping(Config). s2s_required(Config) -> - ejabberd_s2s:stop_all_connections(), + ejabberd_s2s:stop_s2s_connections(), ejabberd_config:add_option(s2s_use_starttls, required), ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), s2s_ping(Config). s2s_required_trusted(Config) -> - ejabberd_s2s:stop_all_connections(), + ejabberd_s2s:stop_s2s_connections(), ejabberd_config:add_option(s2s_use_starttls, required), ejabberd_config:add_option(domain_certfile, "cert.pem"), s2s_ping(Config). diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 89618c0c0..a648cb422 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -231,7 +231,11 @@ Welcome to this XMPP server." mod_disco: [] mod_ping: [] mod_proxy65: [] + mod_push: [] + mod_push_keepalive: [] mod_s2s_dialback: [] + mod_stream_mgmt: + resume_timeout: 3 mod_legacy_auth: [] mod_register: welcome_message: @@ -290,7 +294,11 @@ Welcome to this XMPP server." mod_disco: [] mod_ping: [] mod_proxy65: [] + mod_push: [] + mod_push_keepalive: [] mod_s2s_dialback: [] + mod_stream_mgmt: + resume_timeout: 3 mod_legacy_auth: [] mod_register: welcome_message: @@ -450,6 +458,8 @@ listen: port: @@web_port@@ module: ejabberd_http captcha: true + request_handlers: + "/api": mod_http_api - port: @@component_port@@ module: ejabberd_service @@ -466,6 +476,7 @@ modules: mod_proxy65: [] mod_legacy: [] mod_muc: [] + mod_muc_admin: [] mod_register: welcome_message: subject: "Welcome!" @@ -488,3 +499,8 @@ outgoing_s2s_port: @@s2s_port@@ shaper: fast: 50000 normal: 10000 + +api_permissions: + "public commands": + who: all + what: "*" diff --git a/test/ejabberd_SUITE_data/extauth.py b/test/ejabberd_SUITE_data/extauth.py index fa2c9efd0..263d6464e 100755 --- a/test/ejabberd_SUITE_data/extauth.py +++ b/test/ejabberd_SUITE_data/extauth.py @@ -3,23 +3,27 @@ import struct def read(): (pkt_size,) = struct.unpack('>H', sys.stdin.read(2)) - pkt = sys.stdin.read(pkt_size).split(':') - cmd = pkt[0] - args_num = len(pkt) - 1 - if cmd == 'auth' and args_num >= 3: - if pkt[1] == "wrong": + pkt = sys.stdin.read(pkt_size) + cmd = pkt.split(':')[0] + if cmd == 'auth': + u, s, p = pkt.split(':', 3)[1:] + if u == "wrong": write(False) else: write(True) - elif cmd == 'isuser' and args_num == 2: + elif cmd == 'isuser': + u, s = pkt.split(':', 2)[1:] + elif cmd == 'setpass': + u, s, p = pkt.split(':', 3)[1:] write(True) - elif cmd == 'setpass' and args_num >= 3: + elif cmd == 'tryregister': + u, s, p = pkt.split(':', 3)[1:] write(True) - elif cmd == 'tryregister' and args_num >= 3: + elif cmd == 'removeuser': + u, s = pkt.split(':', 2)[1:] write(True) - elif cmd == 'removeuser' and args_num == 2: - write(True) - elif cmd == 'removeuser3' and args_num >= 3: + elif cmd == 'removeuser3': + u, s, p = pkt.split(':', 3)[1:] write(True) else: write(False) diff --git a/test/muc_tests.erl b/test/muc_tests.erl index 9ded2e0fe..bcceb6938 100644 --- a/test/muc_tests.erl +++ b/test/muc_tests.erl @@ -53,7 +53,8 @@ single_cases() -> single_test(service_vcard), single_test(configure_non_existent), single_test(cancel_configure_non_existent), - single_test(service_subscriptions)]}. + single_test(service_subscriptions), + single_test(set_room_affiliation)]}. service_presence_error(Config) -> Service = muc_jid(Config), @@ -242,6 +243,32 @@ service_subscriptions(Config) -> end, Rooms), disconnect(Config). +set_room_affiliation(Config) -> + #jid{server = RoomService} = muc_jid(Config), + RoomName = <<"set_room_affiliation">>, + RoomJID = jid:make(RoomName, RoomService), + MyJID = my_jid(Config), + PeerJID = jid:remove_resource(?config(slave, Config)), + + ct:pal("joining room ~p", [RoomJID]), + ok = join_new(Config, RoomJID), + + ct:pal("setting affiliation in room ~p to 'member' for ~p", [RoomJID, PeerJID]), + ServerHost = ?config(server_host, Config), + WebPort = ct:get_config(web_port, 5280), + RequestURL = "http://" ++ ServerHost ++ ":" ++ integer_to_list(WebPort) ++ "/api/set_room_affiliation", + Headers = [{"X-Admin", "true"}], + ContentType = "application/json", + Body = jiffy:encode(#{name => RoomName, service => RoomService, jid => jid:encode(PeerJID), affiliation => member}), + {ok, {{_, 200, _}, _, _}} = httpc:request(post, {RequestURL, Headers, ContentType, Body}, [], []), + + #message{id = _, from = RoomJID, to = MyJID, sub_els = [ + #muc_user{items = [ + #muc_item{affiliation = member, role = none, jid = PeerJID}]}]} = recv_message(Config), + + ok = leave(Config, RoomJID), + disconnect(Config). + %%%=================================================================== %%% Master-slave tests %%%=================================================================== diff --git a/test/push_tests.erl b/test/push_tests.erl new file mode 100644 index 000000000..b1f3a8b78 --- /dev/null +++ b/test/push_tests.erl @@ -0,0 +1,234 @@ +%%%------------------------------------------------------------------- +%%% Author : Holger Weiss <holger@zedat.fu-berlin.de> +%%% Created : 15 Jul 2017 by Holger Weiss <holger@zedat.fu-berlin.de> +%%% +%%% +%%% ejabberd, Copyright (C) 2017 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- + +-module(push_tests). + +%% API +-compile(export_all). +-import(suite, [close_socket/1, connect/1, disconnect/1, get_event/1, + get_features/2, make_iq_result/1, my_jid/1, put_event/2, recv/1, + recv_iq/1, recv_message/1, self_presence/2, send/2, send_recv/2, + server_jid/1]). + +-include("suite.hrl"). + +-define(PUSH_NODE, <<"d3v1c3">>). +-define(PUSH_XDATA_FIELDS, + [#xdata_field{var = <<"FORM_TYPE">>, + values = [?NS_PUBSUB_PUBLISH_OPTIONS]}, + #xdata_field{var = <<"secret">>, + values = [<<"c0nf1d3nt14l">>]}]). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {push_single, [sequence], + [single_test(feature_enabled), + single_test(unsupported_iq)]}. + +feature_enabled(Config) -> + BareMyJID = jid:remove_resource(my_jid(Config)), + Features = get_features(Config, BareMyJID), + true = lists:member(?NS_PUSH_0, Features), + disconnect(Config). + +unsupported_iq(Config) -> + PushJID = my_jid(Config), + lists:foreach( + fun(SubEl) -> + #iq{type = error} = + send_recv(Config, #iq{type = get, sub_els = [SubEl]}) + end, [#push_enable{jid = PushJID}, #push_disable{jid = PushJID}]), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {push_master_slave, [sequence], + [master_slave_test(sm), + master_slave_test(offline), + master_slave_test(mam)]}. + +sm_master(Config) -> + ct:comment("Waiting for the slave to close the socket"), + peer_down = get_event(Config), + ct:comment("Waiting a bit in order to test the keepalive feature"), + ct:sleep(5000), % Without mod_push_keepalive, the session would time out. + ct:comment("Sending message to the slave"), + send_test_message(Config), + ct:comment("Handling push notification"), + handle_notification(Config), + ct:comment("Receiving bounced message from the slave"), + #message{type = error} = recv_message(Config), + ct:comment("Closing the connection"), + disconnect(Config). + +sm_slave(Config) -> + ct:comment("Enabling push notifications"), + ok = enable_push(Config), + ct:comment("Enabling stream management"), + ok = enable_sm(Config), + ct:comment("Closing the socket"), + close_socket(Config). + +offline_master(Config) -> + ct:comment("Waiting for the slave to be ready"), + ready = get_event(Config), + ct:comment("Sending message to the slave"), + send_test_message(Config), % No push notification, slave is online. + ct:comment("Waiting for the slave to disconnect"), + peer_down = get_event(Config), + ct:comment("Sending message to offline storage"), + send_test_message(Config), + ct:comment("Handling push notification for offline message"), + handle_notification(Config), + ct:comment("Closing the connection"), + disconnect(Config). + +offline_slave(Config) -> + ct:comment("Re-enabling push notifications"), + ok = enable_push(Config), + ct:comment("Letting the master know that we're ready"), + put_event(Config, ready), + ct:comment("Receiving message from the master"), + recv_test_message(Config), + ct:comment("Closing the connection"), + disconnect(Config). + +mam_master(Config) -> + ct:comment("Waiting for the slave to be ready"), + ready = get_event(Config), + ct:comment("Sending message to the slave"), + send_test_message(Config), + ct:comment("Handling push notification for MAM message"), + handle_notification(Config), + ct:comment("Closing the connection"), + disconnect(Config). + +mam_slave(Config) -> + self_presence(Config, available), + ct:comment("Receiving message from offline storage"), + recv_test_message(Config), + %% Don't re-enable push notifications, otherwise the notification would be + %% suppressed while the slave is online. + ct:comment("Enabling MAM"), + ok = enable_mam(Config), + ct:comment("Letting the master know that we're ready"), + put_event(Config, ready), + ct:comment("Receiving message from the master"), + recv_test_message(Config), + ct:comment("Waiting for the master to disconnect"), + peer_down = get_event(Config), + ct:comment("Disabling push notifications"), + ok = disable_push(Config), + ct:comment("Closing the connection and cleaning up"), + clean(disconnect(Config)). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("push_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("push_" ++ atom_to_list(T)), [parallel], + [list_to_atom("push_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("push_" ++ atom_to_list(T) ++ "_slave")]}. + +enable_sm(Config) -> + send(Config, #sm_enable{xmlns = ?NS_STREAM_MGMT_3, resume = true}), + case recv(Config) of + #sm_enabled{resume = true} -> + ok; + #sm_failed{reason = Reason} -> + Reason + end. + +enable_mam(Config) -> + case send_recv( + Config, #iq{type = set, sub_els = [#mam_prefs{xmlns = ?NS_MAM_1, + default = always}]}) of + #iq{type = result} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +enable_push(Config) -> + %% Usually, the push JID would be a server JID (such as push.example.com). + %% We specify the peer's full user JID instead, so the push notifications + %% will be sent to the peer. + PushJID = ?config(peer, Config), + XData = #xdata{type = submit, fields = ?PUSH_XDATA_FIELDS}, + case send_recv( + Config, #iq{type = set, + sub_els = [#push_enable{jid = PushJID, + node = ?PUSH_NODE, + xdata = XData}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +disable_push(Config) -> + PushJID = ?config(peer, Config), + case send_recv( + Config, #iq{type = set, + sub_els = [#push_disable{jid = PushJID, + node = ?PUSH_NODE}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +send_test_message(Config) -> + Peer = ?config(peer, Config), + Msg = #message{to = Peer, body = [#text{data = <<"test">>}]}, + send(Config, Msg). + +recv_test_message(Config) -> + Peer = ?config(peer, Config), + #message{from = Peer, + body = [#text{data = <<"test">>}]} = recv_message(Config). + +handle_notification(Config) -> + From = server_jid(Config), + Item = #ps_item{xml_els = [xmpp:encode(#push_notification{})]}, + Publish = #ps_publish{node = ?PUSH_NODE, items = [Item]}, + XData = #xdata{type = submit, fields = ?PUSH_XDATA_FIELDS}, + PubSub = #pubsub{publish = Publish, publish_options = XData}, + IQ = #iq{type = set, from = From, sub_els = [PubSub]} = recv_iq(Config), + send(Config, make_iq_result(IQ)). + +clean(Config) -> + {U, S, _} = jid:tolower(my_jid(Config)), + mod_push:remove_user(U, S), + mod_mam:remove_user(U, S), + Config. |