aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/ejabberd_SUITE.erl12
-rw-r--r--test/ejabberd_SUITE_data/ejabberd.yml16
-rwxr-xr-xtest/ejabberd_SUITE_data/extauth.py26
-rw-r--r--test/muc_tests.erl29
-rw-r--r--test/push_tests.erl234
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.