+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule ACLTest do
- @author "mremond@process-one.net"
-
- use ExUnit.Case, async: false
-
- setup_all do
- :ok = :mnesia.start
- :ejabberd_mnesia.start
- :jid.start
- :ejabberd_hooks.start_link
- :stringprep.start
- :ok = :ejabberd_config.start(["domain1", "domain2"], [])
- {:ok, _} = :acl.start_link
- :ok
- end
-
- setup do
- :acl.clear
- end
-
- test "access rule match with user part ACL" do
- :acl.add(:global, :basic_acl_1, {:user, "test1"})
- :acl.add(:global, :basic_acl_1, {:user, "test2"})
- :acl.add_access(:global, :basic_rule_1, [{:allow, [{:acl, :basic_acl_1}]}])
- # JID can only be passes as jid record.
- # => TODO: Support passing JID as binary.
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test1@domain1")) == :allow
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test1@domain2")) == :allow
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test2@domain1")) == :allow
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test2@domain2")) == :allow
- # We match on user part only for local domain. As an implicit rule remote domain are not matched
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test1@otherdomain")) == :deny
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test2@otherdomain")) == :deny
- assert :acl.match_rule(:global, :basic_rule_1, :jid.from_string("test11@domain1")) == :deny
-
- :acl.add(:global, :basic_acl_2, {:user, {"test2", "domain1"}})
- :acl.add_access(:global, :basic_rule_2, [{:allow, [{:acl, :basic_acl_2}]}])
- assert :acl.match_rule(:global, :basic_rule_2, :jid.from_string("test2@domain1")) == :allow
- assert :acl.match_rule(:global, :basic_rule_2, :jid.from_string("test2@domain2")) == :deny
- assert :acl.match_rule(:global, :basic_rule_2, :jid.from_string("test2@otherdomain")) == :deny
- assert :acl.match_rule(:global, :basic_rule_2, {127,0,0,1}) == :deny
- end
-
- test "IP based ACL" do
- :acl.add(:global, :ip_acl_1, {:ip, "127.0.0.0/24"})
- :acl.add_access(:global, :ip_rule_1, [{:allow, [{:acl, :ip_acl_1}]}])
- # IP must be expressed as a tuple when calling match rule
- assert :acl.match_rule(:global, :ip_rule_1, {127,0,0,1}) == :allow
- assert :acl.match_rule(:global, :ip_rule_1, {127,0,1,1}) == :deny
- assert :acl.match_rule(:global, :ip_rule_1, :jid.from_string("test1@domain1")) == :deny
- end
-
- test "Access rule are evaluated sequentially" do
- :acl.add(:global, :user_acl_1, {:user, {"test1", "domain2"}})
- :acl.add(:global, :user_acl_2, {:user, "test1"})
- :acl.add_access(:global, :user_rule_1, [{:deny, [{:acl, :user_acl_1}]}, {:allow, [{:acl, :user_acl_2}]}])
- assert :acl.match_rule(:global, :user_rule_1, :jid.from_string("test1@domain1")) == :allow
- assert :acl.match_rule(:global, :user_rule_1, :jid.from_string("test1@domain2")) == :deny
- end
-
- # Access rules are sometimes used to provide values (i.e.: max_s2s_connections, max_user_sessions)
- test "Access rules providing values" do
- :acl.add(:global, :user_acl, {:user_regexp, ""})
- :acl.add(:global, :admin_acl, {:user, "admin"})
- :acl.add_access(:global, :value_rule_1, [{10, [{:acl, :admin_acl}]}, {5, [{:acl, :user_acl}]}])
- assert :acl.match_rule(:global, :value_rule_1, :jid.from_string("test1@domain1")) == 5
- assert :acl.match_rule(:global, :value_rule_1, :jid.from_string("admin@domain1")) == 10
-
- # If we have no match, :deny is still the default value
- # => TODO maybe we should have a match rule which allow passing custom default value ?
- assert :acl.match_rule(:global, :value_rule_1, :jid.from_string("user@otherdomain")) == :deny
- end
-
-
- # At the moment IP and user rules to no go well together: There is
- # no way to combine IP and user restrictions.
- # => TODO we need to implement access rules that implement both and will deny the access
- # if either IP or user returns deny
- test "mixing IP and user access rules" do
- :acl.add(:global, :user_acl_1, {:user, "test1"})
- :acl.add(:global, :ip_acl_1, {:ip, "127.0.0.0/24"})
- :acl.add_access(:global, :mixed_rule_1, [{:allow, [{:acl, :user_acl_1}]}, {:allow, [{:acl, :ip_acl_1}]}])
- assert :acl.match_rule(:global, :mixed_rule_1, :jid.from_string("test1@domain1")) == :allow
- assert :acl.match_rule(:global, :mixed_rule_1, {127,0,0,1}) == :allow
-
- :acl.add_access(:global, :mixed_rule_2, [{:deny, [{:acl, :user_acl_1}]}, {:allow, [{:acl, :ip_acl_1}]}])
- assert :acl.match_rule(:global, :mixed_rule_2, :jid.from_string("test1@domain1")) == :deny
- assert :acl.match_rule(:global, :mixed_rule_2, {127,0,0,1}) == :allow
- end
-
- test "access_matches works with predefined access rules" do
- :acl.add(:global, :user_acl_2, {:user, "user"})
- :acl.add_access(:global, :user_rule_2, [{:allow, [{:acl, :user_acl_2}]}, {:deny, [:all]}])
-
- assert :acl.access_matches(:user_rule_2, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches(:user_rule_2, %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches rule all always matches" do
- assert :acl.access_matches(:all, %{}, :global) == :allow
- assert :acl.access_matches(:all, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- end
-
- test "access_matches rule none never matches" do
- assert :acl.access_matches(:none, %{}, :global) == :deny
- assert :acl.access_matches(:none, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches with not existing rule never matches" do
- assert :acl.access_matches(:bleble, %{}, :global) == :deny
- assert :acl.access_matches(:bleble, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches works with inlined access rules" do
- :acl.add(:global, :user_acl_3, {:user, "user"})
-
- assert :acl.access_matches([{:allow, [{:acl, :user_acl_3}]}, {:deny, [:all]}],
- %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches([{:allow, [{:acl, :user_acl_3}]}, {:deny, [:all]}],
- %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches allow to have acl rules inlined" do
- assert :acl.access_matches([{:allow, [{:user, "user"}]}, {:deny, [:all]}],
- %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches([{:allow, [{:user, "user"}]}, {:deny, [:all]}],
- %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches test have implicit deny at end" do
- assert :acl.access_matches([{:allow, [{:user, "user"}]}],
- %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches([{:allow, [{:user, "user"}]}],
- %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches requires that all subrules match" do
- rules = [{:allow, [{:user, "user"}, {:ip, {{127,0,0,1}, 32}}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,2}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches rules are matched in order" do
- rules = [{:allow, [{:user, "user"}]}, {:deny, [{:user, "user2"}]}, {:allow, [{:user_regexp, "user"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user2", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user22", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- end
-
- test "access_matches rules that require ip but no one is provided don't crash" do
- rules = [{:allow, [{:ip, {{127,0,0,1}, 32}}]},
- {:allow, [{:user, "user"}]},
- {:allow, [{:user, "user2"}, {:ip, {{127,0,0,1}, 32}}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user2", "domain1", ""}}, :global) == :deny
- end
-
- test "access_matches rules that require usr but no one is provided don't crash" do
- rules = [{:allow, [{:ip, {{127,0,0,1}, 32}}]},
- {:allow, [{:user, "user"}]},
- {:allow, [{:user, "user2"}, {:ip, {{127,0,0,2}, 32}}]}]
- assert :acl.access_matches(rules, %{ip: {127,0,0,1}}, :global) == :allow
- assert :acl.access_matches(rules, %{ip: {127,0,0,2}}, :global) == :deny
- end
-
- test "access_matches rules with all always matches" do
- rules = [{:allow, [:all]}, {:deny, {:user, "user"}}]
- assert :acl.access_matches(rules, %{}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- end
-
- test "access_matches rules with {acl, all} always matches" do
- rules = [{:allow, [{:acl, :all}]}, {:deny, {:user, "user"}}]
- assert :acl.access_matches(rules, %{}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :allow
- end
-
- test "access_matches rules with none never matches" do
- rules = [{:allow, [:none]}, {:deny, [:all]}]
- assert :acl.access_matches(rules, %{}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches with no rules never matches" do
- assert :acl.access_matches([], %{}, :global) == :deny
- assert :acl.access_matches([], %{usr: {"user", "domain1", ""}, ip: {127,0,0,1}}, :global) == :deny
- end
-
- test "access_matches ip rule accepts {ip, port}" do
- rules = [{:allow, [{:ip, {{127,0,0,1}, 32}}]}]
- assert :acl.access_matches(rules, %{ip: {{127,0,0,1}, 5000}}, :global) == :allow
- assert :acl.access_matches(rules, %{ip: {{127,0,0,2}, 5000}}, :global) == :deny
- end
-
- test "access_matches user rule works" do
- rules = [{:allow, [{:user, "user1"}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "domain1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user2", "domain1", ""}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "domain3", ""}}, :global) == :deny
- end
-
- test "access_matches 2 arg user rule works" do
- rules = [{:allow, [{:user, {"user1", "server1"}}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "server1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user1", "server2", ""}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user2", "server1", ""}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user2", "server2", ""}}, :global) == :deny
- end
-
- test "access_matches server rule works" do
- rules = [{:allow, [{:server, "server1"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "server1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "server2", ""}}, :global) == :deny
- end
-
- test "access_matches resource rule works" do
- rules = [{:allow, [{:resource, "res1"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "res2"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user", "domain3", "res1"}}, :global) == :allow
- end
-
- test "access_matches user_regexp rule works" do
- rules = [{:allow, [{:user_regexp, "user[0-9]"}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "domain1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"userA", "domain1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "domain3", "res1"}}, :global) == :deny
- end
-
- test "access_matches 2 arg user_regexp rule works" do
- rules = [{:allow, [{:user_regexp, {"user[0-9]", "server1"}}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "server1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"userA", "server1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "server2", "res1"}}, :global) == :deny
- end
-
- test "access_matches server_regexp rule works" do
- rules = [{:allow, [{:server_regexp, "server[0-9]"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "server1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "serverA", ""}}, :global) == :deny
- end
-
- test "access_matches resource_regexp rule works" do
- rules = [{:allow, [{:resource_regexp, "res[0-9]"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "resA"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user", "domain3", "res1"}}, :global) == :allow
- end
-
- test "access_matches node_regexp rule works" do
- rules = [{:allow, [{:node_regexp, {"user[0-9]", "server[0-9]"}}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "server1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"userA", "server1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "serverA", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"userA", "serverA", "res1"}}, :global) == :deny
- end
-
- test "access_matches user_glob rule works" do
- rules = [{:allow, [{:user_glob, "user?"}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "domain1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user11", "domain1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "domain3", "res1"}}, :global) == :deny
- end
-
- test "access_matches 2 arg user_glob rule works" do
- rules = [{:allow, [{:user_glob, {"user?", "server1"}}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "server1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user11", "server1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "server2", "res1"}}, :global) == :deny
- end
-
- test "access_matches server_glob rule works" do
- rules = [{:allow, [{:server_glob, "server?"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "server1", ""}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "server11", ""}}, :global) == :deny
- end
-
- test "access_matches resource_glob rule works" do
- rules = [{:allow, [{:resource_glob, "res?"}]}]
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user", "domain1", "res11"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user", "domain3", "res1"}}, :global) == :allow
- end
-
- test "access_matches node_glob rule works" do
- rules = [{:allow, [{:node_glob, {"user?", "server?"}}]}]
- assert :acl.access_matches(rules, %{usr: {"user1", "server1", "res1"}}, :global) == :allow
- assert :acl.access_matches(rules, %{usr: {"user11", "server1", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user1", "server11", "res1"}}, :global) == :deny
- assert :acl.access_matches(rules, %{usr: {"user11", "server11", "res1"}}, :global) == :deny
- end
-
- test "transform_access_rules_config expands allow rule" do
- assert :acl.transform_access_rules_config([:allow]) == [{:allow, [:all]}]
- end
-
- test "transform_access_rules_config expands deny rule" do
- assert :acl.transform_access_rules_config([:deny]) == [{:deny, [:all]}]
- end
-
- test "transform_access_rules_config expands <integer> rule" do
- assert :acl.transform_access_rules_config([100]) == [{100, [:all]}]
- end
-
- test "transform_access_rules_config expands <shaper_name> rule" do
- assert :acl.transform_access_rules_config([:fast]) == [{:fast, [:all]}]
- end
-
- test "transform_access_rules_config expands allow: <acl_name> rule" do
- assert :acl.transform_access_rules_config([{:allow, :test1}]) == [{:allow, [{:acl, :test1}]}]
- end
-
- test "transform_access_rules_config expands deny: <acl_name> rule" do
- assert :acl.transform_access_rules_config([{:deny, :test1}]) == [{:deny, [{:acl, :test1}]}]
- end
-
- test "transform_access_rules_config expands integer: <acl_name> rule" do
- assert :acl.transform_access_rules_config([{100, :test1}]) == [{100, [{:acl, :test1}]}]
- end
-
- test "transform_access_rules_config expands <shaper_name>: <acl_name> rule" do
- assert :acl.transform_access_rules_config([{:fast, :test1}]) == [{:fast, [{:acl, :test1}]}]
- end
-
- test "transform_access_rules_config expands allow rule (no list)" do
- assert :acl.transform_access_rules_config(:allow) == [{:allow, [:all]}]
- end
-
- test "transform_access_rules_config expands deny rule (no list)" do
- assert :acl.transform_access_rules_config(:deny) == [{:deny, [:all]}]
- end
-
- test "transform_access_rules_config expands <integer> rule (no list)" do
- assert :acl.transform_access_rules_config(100) == [{100, [:all]}]
- end
-
- test "transform_access_rules_config expands <shaper_name> rule (no list)" do
- assert :acl.transform_access_rules_config(:fast) == [{:fast, [:all]}]
- end
-
- test "access_rules_validator works with <AccessName>" do
- assert :acl.access_rules_validator(:my_access) == :my_access
- end
-
- test "shapes_rules_validator works with <AccessName>" do
- assert :acl.shaper_rules_validator(:my_access) == :my_access
- end
-
- ## Checking ACL on both user pattern and IP
- ## ========================================
-
- # Typical example is mod_register
-
- # Deprecated approach
- test "module can test both IP and user through two independent :acl.match_rule check (deprecated)" do
- :acl.add(:global, :user_acl, {:user, {"test1", "domain1"}})
- :acl.add(:global, :ip_acl, {:ip, "127.0.0.0/24"})
- :acl.add_access(:global, :user_rule, [{:allow, [{:acl, :user_acl}]}])
- :acl.add_access(:global, :ip_rule, [{:allow, [{:acl, :ip_acl}]}])
-
- # acl module in 16.03 is not able to provide a function for compound result:
- assert :acl.match_rule(:global, :user_rule, :jid.from_string("test1@domain1")) == :allow
- assert :acl.match_rule(:global, :ip_rule, {127,0,0,1}) == :allow
- assert :acl.match_rule(:global, :user_rule, :jid.from_string("test2@domain1")) == :deny
- assert :acl.match_rule(:global, :ip_rule, {127,0,1,1}) == :deny
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule EjabberdAdminTest do
- use ExUnit.Case, async: false
-
- @author "jsautret@process-one.net"
-
- setup_all do
- :mnesia.start
- :ejabberd_mnesia.start
- # For some myterious reason, :ejabberd_commands.init mays
- # sometimes fails if module is not loaded before
- :ejabberd_config.start(["domain"], [])
- {:module, :ejabberd_commands} = Code.ensure_loaded(:ejabberd_commands)
- :ejabberd_hooks.start_link
- {:ok, _} = :acl.start_link
- {:ok, _} = :ejabberd_access_permissions.start_link()
- :ejabberd_commands.start_link
- :ejabberd_admin.start_link
- :ok
- end
-
- setup do
- :ok
- end
-
- test "Logvel can be set and retrieved" do
- :ejabberd_logger.start()
-
- assert :lager == call_command(:set_loglevel, [1])
- assert {1, :critical, 'Critical'} ==
- call_command(:get_loglevel, [])
-
- assert :lager == call_command(:set_loglevel, [2])
- assert {2, :error, 'Error'} ==
- call_command(:get_loglevel, [])
-
- assert :lager == call_command(:set_loglevel, [3])
- assert {3, :warning, 'Warning'} ==
- call_command(:get_loglevel, [])
-
-# assert {:wrong_loglevel, 6} ==
-# catch_throw call_command(:set_loglevel, [6])
-# assert {3, :warning, 'Warning'} ==
-# call_command(:get_loglevel, [])
-
- assert :lager == call_command(:set_loglevel, [4])
- assert {4, :info, 'Info'} ==
- call_command(:get_loglevel, [])
-
- assert :lager == call_command(:set_loglevel, [5])
- assert {5, :debug, 'Debug'} ==
- call_command(:get_loglevel, [])
-
- assert :lager == call_command(:set_loglevel, [0])
- assert {0, :no_log, 'No log'} ==
- call_command(:get_loglevel, [])
-
- end
-
- defp call_command(name, args) do
- :ejabberd_commands.execute_command2(name, args, %{:caller_module => :ejabberd_ctl})
- end
-
- test "command status works with ejabberd stopped" do
- assert :ejabberd_not_running ==
- elem(call_command(:status, []), 0)
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule EjabberdAuthMock do
-
- @author "jsautret@process-one.net"
- @agent __MODULE__
-
- def init do
- try do
- Agent.stop(@agent)
- catch
- :exit, _e -> :ok
- end
-
- {:ok, _pid} = Agent.start_link(fn -> %{} end, name: @agent)
-
- mock(:ejabberd_auth, :user_exists,
- fn (user, domain) ->
- Agent.get(@agent, fn users -> Map.get(users, {user, domain}) end) != nil
- end)
- mock(:ejabberd_auth, :get_password_s,
- fn (user, domain) ->
- Agent.get(@agent, fn users -> Map.get(users, {user, domain}, "") end )
- end)
- mock(:ejabberd_auth, :check_password,
- fn (user, _authzid, domain, password) ->
- Agent.get(@agent, fn users ->
- Map.get(users, {user, domain}) end) == password
- end)
- mock(:ejabberd_auth, :set_password,
- fn (user, domain, password) ->
- Agent.update(@agent, fn users ->
- Map.put(users, {user, domain}, password) end)
- end)
- end
-
- def create_user(user, domain, password) do
- Agent.update(@agent, fn users -> Map.put(users, {user, domain}, password) end)
- end
-
- ####################################################################
- # Helpers
- ####################################################################
-
- # TODO refactor: Move to ejabberd_test_mock
- def mock(module, function, fun) do
- try do
- :meck.new(module)
- catch
- :error, {:already_started, _pid} -> :ok
- end
-
- :meck.expect(module, function, fun)
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-# Notes on the tests:
-#
-# This test suite will print out errors in logs for tests:
-#
-# test "Error in run_fold is ignored"
-# test "Throw in run_fold is ignored"
-# test "Exit in run_fold is ignored"
-#
-# Those tests are not failing and we can safely ignore those errors in
-# log as we are exercising hook handler recovery from that situation.
-
-defmodule EjabberdHooksTest do
- use ExUnit.Case, async: false
-
- @author "mremond@process-one.net"
- @host <<"domain.net">>
- @self __MODULE__
-
- setup_all do
- {:ok, _pid} = :ejabberd_hooks.start_link
- :ok
- end
-
- setup do
- :meck.unload
- :true = :ejabberd_hooks.delete_all_hooks
- :ok
- end
-
- test "An anonymous function can be added as a hook" do
- hookname = :test_fun_hook
- :ok = :ejabberd_hooks.add(hookname, @host, fn _ -> :ok end, 50)
- [{50, :undefined, _}] = :ejabberd_hooks.get_handlers(hookname, @host)
- end
-
- test "A module function can be added as a hook" do
- hookname = :test_mod_hook
- callback = :hook_callback
- :ok = :ejabberd_hooks.add(hookname, @host, @self, callback, 40)
- [{40, @self, _callback}] = :ejabberd_hooks.get_handlers(hookname, @host)
- end
-
- test "An anonymous function can be removed from hook handlers" do
- hookname = :test_fun_hook
- anon_fun = fn _ -> :ok end
- :ok = :ejabberd_hooks.add(hookname, @host, anon_fun, 50)
- :ok = :ejabberd_hooks.delete(hookname, @host, anon_fun, 50)
- [] = :ejabberd_hooks.get_handlers(hookname, @host)
- end
-
- test "An module function can be removed from hook handlers" do
- hookname = :test_mod_hook
- callback = :hook_callback
- :ok = :ejabberd_hooks.add(hookname, @host, @self, callback, 40)
- :ok = :ejabberd_hooks.delete(hookname, @host, @self, callback, 40)
- [] = :ejabberd_hooks.get_handlers(hookname, @host)
- # TODO: Check that removed function is not call anymore
- end
-
- test "'Run hook' call registered handler once" do
- test_result = :hook_result
- run_hook([], fn -> test_result end, test_result)
- end
-
- test "'Run hook' can call registered handler with parameters" do
- test_result = :hook_result_with_params
- run_hook([:hook_params], fn _ -> test_result end, test_result)
- end
-
- # TODO test "Several handlers are run in order by hook"
-
- test "Hook run chain is stopped when handler return 'stop'" do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- mock(modulename, :hook_callback1, fn _ -> :stop end)
- mock(modulename, :hook_callback2, fn _ -> :end_result end)
-
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 40)
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 50)
-
- :ok = :ejabberd_hooks.run(hookname, @host, [:hook_params])
- # callback2 is never run:
- [{_pid, {^modulename, _callback, [:hook_params]}, :stop}] = :meck.history(modulename)
- end
-
- test "Run fold hooks accumulate state in correct order through handlers" do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- mock(modulename, :hook_callback1, fn(list, user) -> [user|list] end)
- mock(modulename, :hook_callback2, fn(list, _user) -> ["jid2"|list] end)
-
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 40)
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback2, 50)
-
- ["jid2", "jid1"] = :ejabberd_hooks.run_fold(hookname, @host, [], ["jid1"])
- end
-
- test "Hook run_fold are executed based on priority order, not registration order" do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- mock(modulename, :hook_callback1, fn(_acc) -> :first end)
- mock(modulename, :hook_callback2, fn(_acc) -> :second end)
-
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback2, 50)
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 40)
-
- :second = :ejabberd_hooks.run_fold(hookname, @host, :started, [])
- # Both module have been called:
- 2 = length(:meck.history(modulename))
- end
-
- # TODO: Test with ability to stop and return a value
- test "Hook run_fold chain is stopped when handler return 'stop'" do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- mock(modulename, :hook_callback1, fn(_acc) -> :stop end)
- mock(modulename, :hook_callback2, fn(_acc) -> :executed end)
-
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 40)
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback2, 50)
-
- :stopped = :ejabberd_hooks.run_fold(hookname, @host, :started, [])
- # Only one module has been called
- [{_pid, {^modulename, :hook_callback1, [:started]}, :stop}] = :meck.history(modulename)
- end
-
- test "Error in run_fold is ignored" do
- run_fold_crash(fn(_acc) -> raise "crashed" end)
- end
-
- test "Throw in run_fold is ignored" do
- run_fold_crash(fn(_acc) -> throw :crashed end)
- end
-
- test "Exit in run_fold is ignored" do
- run_fold_crash(fn(_acc) -> exit :crashed end)
- end
-
- # test for run hook with various number of params
- def run_hook(params, fun, result) do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- callback = :hook_callback
- mock(modulename, callback, fun)
-
- # Then check
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, callback, 40)
- :ok = :ejabberd_hooks.run(hookname, @host, params)
- [{_pid, {^modulename, ^callback, ^params}, ^result}] = :meck.history(modulename)
- end
-
- def run_fold_crash(crash_fun) do
- # setup test
- hookname = :test_mod_hook
- modulename = :hook_module
- mock(modulename, :hook_callback1, crash_fun)
- mock(modulename, :hook_callback2, fn(_acc) -> :final end)
-
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback1, 40)
- :ok = :ejabberd_hooks.add(hookname, @host, modulename, :hook_callback2, 50)
-
- :final = :ejabberd_hooks.run_fold(hookname, @host, :started, [])
- # Both handlers were called
- 2 = length(:meck.history(modulename))
- end
-
- # TODO refactor: Move to ejabberd_test_mock
- def mock(module, function, fun) do
- try do
- :meck.new(module, [:non_strict])
- catch
- :error, {:already_started, _pid} -> :ok
- end
-
- :meck.expect(module, function, fun)
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule EjabberdOauthMock do
-
- @author "jsautret@process-one.net"
-
- def init() do
- :mnesia.start
- :mnesia.create_table(:oauth_token,
- [ram_copies: [node],
- attributes: [:oauth_token, :us, :scope, :expire]])
- :application.start(:cache_tab)
- :cache_tab.new(:oauth_token,
- [{:max_size, 1000}, {:life_time, 3600}])
- end
-
- def get_token(user, domain, command, expiration \\ 3600) do
- now = {megasecs, secs, _} = :os.timestamp
- expire = 1000000 * megasecs + secs + expiration
- :random.seed now
- token = to_string :random.uniform(100000000)
-
- {:ok, _} = :ejabberd_oauth.associate_access_token(token,
- [{"resource_owner",
- {:user, user, domain}},
- {"scope", [to_string command]},
- {"expiry_time", expire}],
- [])
- token
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule EjabberdSmMock do
- @author "jsautret@process-one.net"
-
- require Record
- Record.defrecord :session, Record.extract(:session, from_lib: "ejabberd/include/ejabberd_sm.hrl")
- Record.defrecord :jid, Record.extract(:jid, from_lib: "xmpp/include/jid.hrl")
-
- @agent __MODULE__
-
- def init do
- ModLastMock.init
-
- try do
- Agent.stop(@agent)
- catch
- :exit, _e -> :ok
- end
-
- {:ok, _pid} = Agent.start_link(fn -> [] end, name: @agent)
-
- mock(:ejabberd_sm, :get_user_resources,
- fn (user, domain) -> for s <- get_sessions(user, domain), do: s.resource end)
-
- mock(:ejabberd_sm, :route,
- fn (to, {:exit, _reason}) ->
- user = jid(to, :user)
- domain = jid(to, :server)
- resource = jid(to, :resource)
- disconnect_resource(user, domain, resource)
- :ok
- (_, _) -> :ok
- end)
-
- end
-
- def connect_resource(user, domain, resource,
- opts \\ [priority: 1, conn: :c2s]) do
- Agent.update(@agent, fn sessions ->
- session = %{user: user, domain: domain, resource: resource,
- timestamp: :os.timestamp, pid: self, node: node,
- auth_module: :ejabberd_auth, ip: :undefined,
- priority: opts[:priority], conn: opts[:conn]}
- [session | sessions]
- end)
- end
-
- def disconnect_resource(user, domain, resource) do
- disconnect_resource(user, domain, resource, ModLastMock.now)
- end
-
- def disconnect_resource(user, domain, resource, timestamp) do
- Agent.update(@agent, fn sessions ->
- for s <- sessions,
- s.user != user or s.domain != domain or s.resource != resource, do: s
- end)
- ModLastMock.set_last user, domain, "", timestamp
- end
-
- def get_sessions() do
- Agent.get(@agent, fn sessions -> sessions end)
- end
-
- def get_sessions(user, domain) do
- Agent.get(@agent, fn sessions ->
- for s <- sessions, s.user == user, s.domain == domain, do: s
- end)
- end
-
- def get_session(user, domain, resource) do
- Agent.get(@agent, fn sessions ->
- for s <- sessions,
- s.user == user, s.domain == domain, s.resource == resource, do: s
- end)
- end
-
- def to_record(s) do
- session(usr: {s.user, s.domain, s.ressource},
- us: {s.user, s.domain},
- sid: {s.timestamp, s.pid},
- priority: s.priority,
- info: [conn: s.conn, ip: s.ip, node: s.node,
- oor: false, auth_module: s.auth_module])
- end
-
- ####################################################################
- # Helpers
- ####################################################################
-
-
- # TODO refactor: Move to ejabberd_test_mock
- def mock(module, function, fun) do
- try do
- :meck.new(module)
- catch
- :error, {:already_started, _pid} -> :ok
- end
-
- :meck.expect(module, function, fun)
- end
-
-end
+++ /dev/null
-%%%-------------------------------------------------------------------
-%%% Author : Mickael Remond <mremond@process-one.net>
-%%% Created : 19 Feb 2015 by Mickael Remond <mremond@process-one.net>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-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.
-%%%
-%%%----------------------------------------------------------------------
-
-%%% This is a common test wrapper to run our ejabberd tests written in
-%%% Elixir from standard common test code.
-%%%
-%%% Example: Is run with:
-%%% ./rebar skip_deps=true ct suites=elixir
-%%% or from ejabber overall test suite:
-%%% make quicktest
-
--module(elixir_SUITE).
-
--compile(export_all).
-
-init_per_suite(Config) ->
- suite:setup_ejabberd_lib_path(Config),
- check_meck(),
- code:add_pathz(filename:join(test_dir(), "../include")),
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config) ->
- process_flag(error_handler, ?MODULE),
- Config.
-
-all() ->
- case is_elixir_available() of
- true ->
- Dir = test_dir(),
- filelib:fold_files(Dir, ".*test\.exs$", false,
- fun(Filename, Acc) -> [list_to_atom(filename:basename(Filename)) | Acc] end,
- []);
- false ->
- []
- end.
-
-check_meck() ->
- case catch meck:module_info(module) of
- meck ->
- ok;
- {'EXIT',{undef, _}} ->
- ct:print("meck is not available. Please make sure you configured ejabberd with --enable-elixir --enable-tools"),
- ok
- end.
-
-is_elixir_available() ->
- case catch elixir:module_info() of
- {'EXIT',{undef,_}} ->
- ct:print("ejabberd has not been build with Elixir support, skipping Elixir tests."),
- false;
- ModInfo when is_list(ModInfo) ->
- true
- end.
-
-undefined_function(?MODULE, Func, Args) ->
- case lists:suffix(".exs", atom_to_list(Func)) of
- true ->
- run_elixir_test(Func);
- false ->
- error_handler:undefined_function(?MODULE, Func, Args)
- end;
-undefined_function(Module, Func, Args) ->
- error_handler:undefined_function(Module, Func,Args).
-
-run_elixir_test(Func) ->
- %% Elixir tests can be tagged as follow to be ignored (place before test start)
- %% @tag pending: true
- 'Elixir.ExUnit':start([{exclude, [{pending, true}]},
- {formatters,
- ['Elixir.ExUnit.CLIFormatter',
- 'Elixir.ExUnit.CTFormatter']},
- {autorun, false}]),
-
- filelib:fold_files(test_dir(), ".*mock\.exs\$", true,
- fun (File, N) ->
- 'Elixir.Code':load_file(list_to_binary(File)),
- N+1
- end, 0),
-
- 'Elixir.Code':load_file(list_to_binary(filename:join(test_dir(), atom_to_list(Func)))),
- %% I did not use map syntax, so that this file can still be build under R16
- catch 'Elixir.ExUnit.Server':cases_loaded(),
- ResultMap = 'Elixir.ExUnit':run(),
- case maps:find(failures, ResultMap) of
- {ok, 0} ->
- %% Zero failures
- ok;
- {ok, Failures} ->
- ct:print("Tests failed in module '~s': ~.10B failures.~nSee logs for details", [Func, Failures]),
- ct:fail(elixir_test_failure),
- error
- end.
-
-test_dir() ->
- {ok, CWD} = file:get_cwd(),
- filename:join(CWD, "../../test").
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule JidTest do
- @author "mremond@process-one.net"
-
- use ExUnit.Case, async: true
-
- require Record
- Record.defrecord :jid, Record.extract(:jid, from_lib: "xmpp/include/jid.hrl")
-
- setup_all do
- :stringprep.start
- :jid.start
- :ok
- end
-
- test "create a jid from a binary" do
- jid = :jid.from_string("test@localhost/resource")
- assert jid(jid, :user) == "test"
- assert jid(jid, :server) == "localhost"
- assert jid(jid, :resource) == "resource"
- end
-
- test "Check that sending a list to from_string/1 does not crash the jid process" do
- {:error, :need_jid_as_binary} = :jid.from_string('test@localhost/resource')
- end
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule EjabberdModAdminExtraTest do
- use ExUnit.Case, async: false
-
- require EjabberdAuthMock
- require EjabberdSmMock
- require ModLastMock
- require ModRosterMock
-
- @author "jsautret@process-one.net"
-
- @user "user"
- @domain "domain"
- @password "password"
- @resource "resource"
-
- require Record
- Record.defrecord :jid, Record.extract(:jid, from_lib: "xmpp/include/jid.hrl")
-
- setup_all do
- try do
- :jid.start
- :stringprep.start
- :mnesia.start
- :ejabberd_mnesia.start
- :p1_sha.load_nif
- :ejabberd_hooks.start_link
- rescue
- _ -> :ok
- end
- :ok = :ejabberd_config.start(["domain"], [])
- :gen_mod.start_link
- :acl.start_link
- :ejabberd_access_permissions.start_link()
- :ejabberd_commands.start_link
- :mod_admin_extra.start(@domain, [])
- :ejabberd_hooks.start_link
- :ok
- end
-
- setup do
- :meck.unload
- EjabberdAuthMock.init
- EjabberdSmMock.init
- ModRosterMock.init(@domain, :mod_admin_extra)
- :ok
- end
-
- ###################### Accounts
- test "check_account works" do
- EjabberdAuthMock.create_user @user, @domain, @password
-
- assert call_command(:check_account, [@user, @domain])
- refute call_command(:check_account, [@user, "bad_domain"])
- refute call_command(:check_account, ["bad_user", @domain])
-
- assert :meck.validate :ejabberd_auth
- end
-
- test "check_password works" do
-
- EjabberdAuthMock.create_user @user, @domain, @password
-
- assert call_command(:check_password,
- [@user, @domain, @password])
- refute call_command(:check_password,
- [@user, @domain, "bad_password"])
- refute call_command(:check_password,
- [@user, "bad_domain", @password])
- refute call_command(:check_password,
- ["bad_user", @domain, @password])
-
- assert :meck.validate :ejabberd_auth
-
- end
-
- test "check_password_hash works" do
-
- EjabberdAuthMock.create_user @user, @domain, @password
- hash = "5F4DCC3B5AA765D61D8327DEB882CF99" # echo -n password|md5
-
- assert call_command(:check_password_hash,
- [@user, @domain, hash, "md5"])
- refute call_command(:check_password_hash,
- [@user, @domain, "bad_hash", "md5"])
- refute call_command(:check_password_hash,
- [@user, "bad_domain", hash, "md5"])
- refute call_command(:check_password_hash,
- ["bad_user", @domain, hash, "md5"])
-
- hash = "5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8" # echo -n password|shasum
- assert call_command(:check_password_hash,
- [@user, @domain, hash, "sha"])
-
- assert :unkown_hash_method ==
- catch_throw call_command(:check_password_hash,
- [@user, @domain, hash, "bad_method"])
-
- assert :meck.validate :ejabberd_auth
-
- end
-
- test "set_password works" do
- EjabberdAuthMock.create_user @user, @domain, @password
-
- assert call_command(:change_password,
- [@user, @domain, "new_password"])
- refute call_command(:check_password,
- [@user, @domain, @password])
- assert call_command(:check_password,
- [@user, @domain, "new_password"])
- assert {:not_found, 'unknown_user'} ==
- catch_throw call_command(:change_password,
- ["bad_user", @domain,
- @password])
- assert :meck.validate :ejabberd_auth
- end
-
- ###################### Sessions
-
- test "num_resources works" do
- assert 0 == call_command(:num_resources,
- [@user, @domain])
-
- EjabberdSmMock.connect_resource @user, @domain, @resource
- assert 1 == call_command(:num_resources,
- [@user, @domain])
-
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"2"
- assert 2 == call_command(:num_resources,
- [@user, @domain])
-
- EjabberdSmMock.connect_resource @user<>"1", @domain, @resource
- assert 2 == call_command(:num_resources,
- [@user, @domain])
-
- EjabberdSmMock.disconnect_resource @user, @domain, @resource
- assert 1 == call_command(:num_resources,
- [@user, @domain])
-
- assert :meck.validate :ejabberd_sm
- end
-
- test "resource_num works" do
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"3"
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"2"
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"1"
-
- assert :bad_argument ==
- elem(catch_throw(call_command(:resource_num,
- [@user, @domain, 0])), 0)
- assert @resource<>"1" ==
- call_command(:resource_num, [@user, @domain, 1])
- assert @resource<>"3" ==
- call_command(:resource_num, [@user, @domain, 3])
- assert :bad_argument ==
- elem(catch_throw(call_command(:resource_num,
- [@user, @domain, 4])), 0)
- assert :meck.validate :ejabberd_sm
- end
-
- test "kick_session works" do
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"1"
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"2"
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"3"
-
- assert 3 == length EjabberdSmMock.get_sessions @user, @domain
- assert 1 == length EjabberdSmMock.get_session @user, @domain, @resource<>"2"
-
- assert :ok ==
- call_command(:kick_session,
- [@user, @domain,
- @resource<>"2", "kick"])
-
- assert 2 == length EjabberdSmMock.get_sessions @user, @domain
- assert 0 == length EjabberdSmMock.get_session @user, @domain, @resource<>"2"
-
- assert :meck.validate :ejabberd_sm
- end
-
- ###################### Last
-
- test "get_last works" do
-
- assert {_, 'NOT FOUND'} =
- call_command(:get_last, [@user, @domain])
-
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"1"
- EjabberdSmMock.connect_resource @user, @domain, @resource<>"2"
-
- assert {_, 'ONLINE'} =
- call_command(:get_last, [@user, @domain])
-
- EjabberdSmMock.disconnect_resource @user, @domain, @resource<>"1"
-
- assert {_, 'ONLINE'} =
- call_command(:get_last, [@user, @domain])
-
- now = {megasecs, secs, _microsecs} = :os.timestamp
- timestamp = megasecs * 1000000 + secs
- EjabberdSmMock.disconnect_resource(@user, @domain, @resource<>"2",
- timestamp)
- {{year, month, day}, {hour, minute, second}} = :calendar.now_to_universal_time now
- result = IO.iodata_to_binary(:io_lib.format(
- "~w-~.2.0w-~.2.0wT~.2.0w:~.2.0w:~.2.0wZ",
- [year, month, day, hour, minute, second]))
- assert {result, ""} ==
- call_command(:get_last, [@user, @domain])
-
- assert :meck.validate :mod_last
- end
-
- ###################### Roster
-
- @tag :skip
- test "add_rosteritem and delete_rosteritem work" do
- # Connect user
- # Add user1 & user2 to user's roster
- # Remove user1 & user2 from user's roster
-
- EjabberdSmMock.connect_resource @user, @domain, @resource
-
- assert [] == ModRosterMock.get_roster(@user, @domain)
-
- assert :ok ==
- call_command(:add_rosteritem, [@user, @domain,
- @user<>"1", @domain,
- "nick1",
- "group1",
- "both"])
- # Check that user1 is the only item of the user's roster
- result = ModRosterMock.get_roster(@user, @domain)
- assert 1 == length result
- [{{@user, @domain, jid}, opts}] = result
- assert @user<>"1@"<>@domain == jid
- assert "nick1" == opts.nick
- assert ["group1"] == opts.groups
- assert :both == opts.subs
-
- # Check that the item roster user1 was pushed with subscription
- # 'both' to user online ressource
- jid = :jlib.make_jid(@user, @domain, @resource)
- assert 1 ==
- :meck.num_calls(:ejabberd_sm, :route,
- [jid,
- {:item, {@user<>"1", @domain, ""}, :both}])
-
- assert :ok ==
- call_command(:add_rosteritem, [@user, @domain,
- @user<>"2", @domain,
- "nick2",
- "group2",
- "both"])
- result = ModRosterMock.get_roster(@user, @domain)
- assert 2 == length result
-
-
- # Check that the item roster user2 was pushed with subscription
- # 'both' to user online ressource
- assert 1 ==
- :meck.num_calls(:ejabberd_sm, :route,
- [jid,
- {:item, {@user<>"2", @domain, ""}, :both}])
-
-
- call_command(:delete_rosteritem, [@user, @domain,
- @user<>"1", @domain])
- result = ModRosterMock.get_roster(@user, @domain)
- assert 1 == length result
- [{{@user, @domain, jid}, opts}] = result
- assert @user<>"2@"<>@domain == jid
- assert "nick2" == opts.nick
- assert ["group2"] == opts.groups
- assert :both == opts.subs
-
- # Check that the item roster user1 was pushed with subscription
- # 'none' to user online ressource
- jid = :jlib.make_jid(@user, @domain, @resource)
- assert 1 ==
- :meck.num_calls(:ejabberd_sm, :route,
- [jid,
- {:item, {@user<>"1", @domain, ""}, :none}])
-
- call_command(:delete_rosteritem, [@user, @domain,
- @user<>"2", @domain])
-
- # Check that the item roster user2 was pushed with subscription
- # 'none' to user online ressource
- assert 1 ==
- :meck.num_calls(:ejabberd_sm, :route,
- [jid,
- {:item, {@user<>"2", @domain, ""}, :none}])
-
- # Check that nothing else was pushed to user resource
- jid = jid(user: @user, server: @domain, resource: :_,
- luser: @user, lserver: @domain, lresource: :_)
- assert 4 ==
- :meck.num_calls(:ejabberd_sm, :route,
- [jid,
- {:item, :_, :_}])
-
- assert [] == ModRosterMock.get_roster(@user, @domain)
- assert :meck.validate :ejabberd_sm
-
- end
-
- @tag :skip
- test "get_roster works" do
- assert [] == ModRosterMock.get_roster(@user, @domain)
- assert [] == call_command(:get_roster, [@user, @domain],
- :admin)
-
- assert :ok ==
- call_command(:add_rosteritem, [@user, @domain,
- @user<>"1", @domain,
- "nick1",
- "group1",
- "both"])
- assert [{@user<>"1@"<>@domain, "", 'both', 'none', "group1"}] ==
- call_command(:get_roster, [@user, @domain], :admin)
- assert :ok ==
- call_command(:add_rosteritem, [@user, @domain,
- @user<>"2", @domain,
- "nick2",
- "group2",
- "none"])
- result = call_command(:get_roster, [@user, @domain], :admin)
- assert 2 == length result
- assert Enum.member?(result, {@user<>"1@"<>@domain, "", 'both', 'none', "group1"})
- assert Enum.member?(result, {@user<>"2@"<>@domain, "", 'none', 'none', "group2"})
-
- end
-
- defp call_command(name, args) do
- :ejabberd_commands.execute_command2(name, args, %{:caller_module => :ejabberd_ctl})
- end
-
- defp call_command(name, args, mode) do
- call_command(name, args)
- end
-
-# kick_user command is defined in ejabberd_sm, move to extra?
-# test "kick_user works" do
-# assert 0 == call_command(:num_resources,
-# [@user, @domain])
-# EjabberdSmMock.connect_resource(@user, @domain, @resource<>"1")
-# EjabberdSmMock.connect_resource(@user, @domain, @resource<>"2")
-# assert 2 ==
-# call_command(:kick_user, [@user, @domain])
-# assert 0 == call_command(:num_resources,
-# [@user, @domain])
-# assert :meck.validate :ejabberd_sm
-# end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule ModHttpApiMockTest do
- use ExUnit.Case, async: false
-
- @author "jsautret@process-one.net"
-
- # Admin user
- @admin "admin"
- @adminpass "adminpass"
- # Non admin user
- @user "user"
- @userpass "userpass"
- # XMPP domain
- @domain "domain"
- # mocked command
- @command "command_test"
- @acommand String.to_atom(@command)
- # default API version
- @version 0
-
- require Record
- Record.defrecord :request, Record.extract(:request, from_lib: "ejabberd/include/ejabberd_http.hrl")
-
- setup_all do
- try do
- :jid.start
- :mnesia.start
- :ejabberd_mnesia.start
- :stringprep.start
- :ejabberd_hooks.start_link
- :ejabberd_config.start([@domain], [])
- {:ok, _} = :ejabberd_access_permissions.start_link()
- :ejabberd_commands.start_link
- rescue
- _ -> :ok
- end
- :mod_http_api.start(@domain, [])
- EjabberdOauthMock.init
- :ok
- end
-
- setup do
- :meck.unload
- :meck.new :ejabberd_commands
- :meck.new(:acl, [:passthrough]) # Need to fake acl to allow oauth
- EjabberdAuthMock.init
- :ok
- end
-
- test "HTTP GET simple command call with Basic Auth" do
- EjabberdAuthMock.create_user @user, @domain, @userpass
-
- # Mock a simple command() -> :ok
- :meck.expect(:ejabberd_commands, :get_command_format,
- fn (@acommand, %{usr: {@user, @domain, _}}, @version) ->
- {[], {:res, :rescode}}
- end)
- :meck.expect(:ejabberd_commands, :get_exposed_commands,
- fn () -> [@acommand] end)
- :meck.expect(:ejabberd_commands, :execute_command2,
- fn (@acommand, [], %{usr: {@user, @domain, _}}, @version) ->
- :ok
- end)
-
- :ejabberd_config.add_local_option(:commands, [[{:add_commands, [@acommand]}]])
-
- # Correct Basic Auth call
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # Basic auth
- auth: {@user<>"@"<>@domain, @userpass},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
-
- # history = :meck.history(:ejabberd_commands)
-
- assert 200 == elem(result, 0) # HTTP code
- assert "0" == elem(result, 2) # command result
-
- # Bad password
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # Basic auth
- auth: {@user<>"@"<>@domain, @userpass<>"bad"},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 401 == elem(result, 0) # HTTP code
-
- # Check that the command was executed only once
- assert 1 ==
- :meck.num_calls(:ejabberd_commands, :execute_command2, :_)
-
- assert :meck.validate :ejabberd_auth
- assert :meck.validate :ejabberd_commands
- end
-
- test "HTTP GET simple command call with OAuth" do
- EjabberdAuthMock.create_user @user, @domain, @userpass
-
- # Mock a simple command() -> :ok
- :meck.expect(:ejabberd_commands, :get_command_format,
- fn (@acommand, %{usr: {@user, @domain, _}}, @version) ->
- {[], {:res, :rescode}}
- end)
- :meck.expect(:ejabberd_commands, :get_exposed_commands,
- fn () -> [@acommand] end)
- :meck.expect(:ejabberd_commands, :execute_command2,
- fn (@acommand, [], %{usr: {@user, @domain, _}, oauth_scope: ["ejabberd:user"]}, @version) ->
- :ok
- (@acommand, [], %{usr: {@user, @domain, _}, oauth_scope: [@command]}, @version) ->
- :ok
- (@acommand, [], %{usr: {@user, @domain, _}, oauth_scope: _}, @version) ->
- throw({:error, :access_rules_unauthorized})
- end)
-
-
- # Correct OAuth call using specific scope
- token = EjabberdOauthMock.get_token @user, @domain, @command
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # OAuth
- auth: {:oauth, token, []},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 200 == elem(result, 0) # HTTP code
- assert "0" == elem(result, 2) # command result
-
- # Correct OAuth call using specific ejabberd:user scope
- token = EjabberdOauthMock.get_token @user, @domain, "ejabberd:user"
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # OAuth
- auth: {:oauth, token, []},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 200 == elem(result, 0) # HTTP code
- assert "0" == elem(result, 2) # command result
-
- # Wrong OAuth token
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # OAuth
- auth: {:oauth, "bad"<>token, []},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 401 == elem(result, 0) # HTTP code
-
- # Expired OAuth token
- token = EjabberdOauthMock.get_token @user, @domain, @command, 1
- :timer.sleep 1500
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # OAuth
- auth: {:oauth, token, []},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 401 == elem(result, 0) # HTTP code
-
- # Wrong OAuth scope
- token = EjabberdOauthMock.get_token @user, @domain, "bad_command"
- :timer.sleep 1500
- req = request(method: :GET,
- path: ["api", @command],
- q: [nokey: ""],
- # OAuth
- auth: {:oauth, token, []},
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :mod_http_api.process([@command], req)
- assert 403 == elem(result, 0) # HTTP code
-
- # Check that the command was executed twice
- assert 3 ==
- :meck.num_calls(:ejabberd_commands, :execute_command2, :_)
-
- assert :meck.validate :ejabberd_auth
- #assert :meck.validate :ejabberd_commands
- #assert :ok = :meck.history(:ejabberd_commands)
- end
-
- test "Request oauth token, resource owner password credentials" do
- EjabberdAuthMock.create_user @user, @domain, @userpass
- :application.set_env(:oauth2, :backend, :ejabberd_oauth)
- :application.start(:oauth2)
-
- # Mock a simple command() -> :ok
- :meck.expect(:ejabberd_commands, :get_command_format,
- fn (@acommand, {@user, @domain, {:oauth, _token}, false}, @version) ->
- {[], {:res, :rescode}}
- end)
- :meck.expect(:ejabberd_commands, :get_exposed_commands,
- fn () -> [@acommand] end)
-
- #Mock acl to allow oauth authorizations
- :meck.expect(:acl, :match_rule, fn(_Server, _Access, _Jid) -> :allow end)
-
-
- # Correct password
- req = request(method: :POST,
- path: ["oauth", "token"],
- q: [{"grant_type", "password"}, {"scope", @command}, {"username", @user<>"@"<>@domain}, {"ttl", "4000"}, {"password", @userpass}],
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :ejabberd_oauth.process([], req)
- assert 200 = elem(result, 0) #http code
- {kv} = :jiffy.decode(elem(result,2))
- assert {_, "bearer"} = List.keyfind(kv, "token_type", 0)
- assert {_, @command} = List.keyfind(kv, "scope", 0)
- assert {_, 4000} = List.keyfind(kv, "expires_in", 0)
- {"access_token", _token} = List.keyfind(kv, "access_token", 0)
-
- #missing grant_type
- req = request(method: :POST,
- path: ["oauth", "token"],
- q: [{"scope", @command}, {"username", @user<>"@"<>@domain}, {"password", @userpass}],
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :ejabberd_oauth.process([], req)
- assert 400 = elem(result, 0) #http code
- {kv} = :jiffy.decode(elem(result,2))
- assert {_, "unsupported_grant_type"} = List.keyfind(kv, "error", 0)
-
-
- # incorrect user/pass
- req = request(method: :POST,
- path: ["oauth", "token"],
- q: [{"grant_type", "password"}, {"scope", @command}, {"username", @user<>"@"<>@domain}, {"password", @userpass<>"aa"}],
- ip: {{127,0,0,1},60000},
- host: @domain)
- result = :ejabberd_oauth.process([], req)
- assert 400 = elem(result, 0) #http code
- {kv} = :jiffy.decode(elem(result,2))
- assert {_, "invalid_grant"} = List.keyfind(kv, "error", 0)
-
- assert :meck.validate :ejabberd_auth
- assert :meck.validate :ejabberd_commands
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule ModHttpApiTest do
- @author "mremond@process-one.net"
-
- use ExUnit.Case, async: true
-
- require Record
- Record.defrecord :request, Record.extract(:request, from_lib: "ejabberd/include/ejabberd_http.hrl")
- Record.defrecord :ejabberd_commands, Record.extract(:ejabberd_commands, from_lib: "ejabberd/include/ejabberd_commands.hrl")
-
- setup_all do
- :ok = :mnesia.start
- :ejabberd_mnesia.start
- :stringprep.start
- :ejabberd_hooks.start_link
- :ok = :ejabberd_config.start(["localhost"], [])
- :acl.start_link
- {:ok, _} = :ejabberd_access_permissions.start_link()
- {:ok, _} = :ejabberd_commands.start_link
- :ok = :ejabberd_commands.register_commands(cmds)
- on_exit fn ->
- :meck.unload
- unregister_commands(cmds) end
- end
-
- test "We can expose several commands to API at a time" do
- setup_mocks()
- assert :ok == :ejabberd_commands.expose_commands([:open_cmd, :user_cmd])
- commands = :ejabberd_commands.get_exposed_commands()
- assert Enum.member?(commands, :open_cmd)
- assert Enum.member?(commands, :user_cmd)
- end
-
-# test "We can call open commands without authentication" do
-# setup_mocks()
-# :ejabberd_commands.expose_commands([:open_cmd])
-# request = request(method: :POST, ip: {{127,0,0,1},50000}, data: "[]")
-# {200, _, _} = :mod_http_api.process(["open_cmd"], request)
-# end
-
- # This related to the commands config file option
- test "Attempting to access a command that is not exposed as HTTP API returns 403" do
- setup_mocks()
- assert :ok == :ejabberd_commands.expose_commands([])
- request = request(method: :POST, ip: {{127,0,0,1},50000}, data: "{}")
- {403, _, _} = :mod_http_api.process(["open_cmd"], request)
- end
-
- test "Call to user, admin or restricted commands without authentication are rejected" do
- setup_mocks()
- assert :ok == :ejabberd_commands.expose_commands([:user_cmd, :admin_cmd, :restricted])
- request = request(method: :POST, ip: {{127,0,0,1},50000}, data: "{}")
- {400, _, _} = :mod_http_api.process(["user_cmd"], request)
- {403, _, _} = :mod_http_api.process(["admin_cmd"], request)
- {403, _, _} = :mod_http_api.process(["restricted_cmd"], request)
- end
-
- @tag pending: true
- test "If admin_ip_access is enabled, we can call restricted API without authentication from that IP" do
- setup_mocks()
- end
-
- # Define a set of test commands that we expose through API
- # We define one for each policy type
- defp cmds do
- [:open, :user, :admin, :restricted]
- |> Enum.map(&({&1, String.to_atom(to_string(&1) <> "_cmd")}))
- |> Enum.map(fn({cmd_type, cmd}) ->
- ejabberd_commands(name: cmd, tags: [:test],
- policy: cmd_type,
- module: __MODULE__,
- function: cmd,
- args: [],
- result: {:res, :rescode})
- end)
- end
-
- def open_cmd, do: :ok
- def user_cmd(_, _), do: :ok
- def admin_cmd, do: :ok
- def restricted_cmd, do: :ok
-
- defp setup_mocks() do
- :meck.unload
- mock(:gen_mod, :get_module_opt,
- fn (_server, :mod_http_api, _admin_ip_access, _, _) ->
- [{:allow, [{:ip, {{127,0,0,2}, 32}}]}]
- end)
- end
-
- defp mock(module, function, fun) do
- try do
- :meck.new(module)
- catch
- :error, {:already_started, _pid} -> :ok
- end
- :meck.expect(module, function, fun)
- end
-
- defp unregister_commands(commands) do
- try do
- :ejabberd_commands.unregister_commands(commands)
- catch
- _,_ -> :ok
- end
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule ModLastMock do
-
- require Record
- Record.defrecord :session, Record.extract(:session, from_lib: "ejabberd/include/ejabberd_sm.hrl")
- Record.defrecord :jid, Record.extract(:jid, from_lib: "xmpp/include/jid.hrl")
-
- @author "jsautret@process-one.net"
- @agent __MODULE__
-
- def init do
- try do
- Agent.stop(@agent)
- catch
- :exit, _e -> :ok
- end
-
- {:ok, _pid} = Agent.start_link(fn -> %{} end, name: @agent)
-
- mock(:mod_last, :get_last_info,
- fn (user, domain) ->
- Agent.get(@agent, fn last ->
- case Map.get(last, {user, domain}, :not_found) do
- {ts, status} -> {:ok, ts, status}
- result -> result
- end
- end)
- end)
- end
-
- def set_last(user, domain, status) do
- set_last(user, domain, status, now)
- end
-
- def set_last(user, domain, status, timestamp) do
- Agent.update(@agent, fn last ->
- Map.put(last, {user, domain}, {timestamp, status})
- end)
- end
-
- ####################################################################
- # Helpers
- ####################################################################
- def now() do
- {megasecs, secs, _microsecs} = :os.timestamp
- megasecs * 1000000 + secs
- end
-
- # TODO refactor: Move to ejabberd_test_mock
- def mock(module, function, fun) do
- try do
- :meck.new(module)
- catch
- :error, {:already_started, _pid} -> :ok
- end
-
- :meck.expect(module, function, fun)
- end
-
-end
+++ /dev/null
-# ----------------------------------------------------------------------
-#
-# ejabberd, Copyright (C) 2002-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.
-#
-# ----------------------------------------------------------------------
-
-defmodule ModRosterMock do
- @author "jsautret@process-one.net"
-
- require Record
- Record.defrecord :roster, Record.extract(:roster, from_lib: "ejabberd/include/mod_roster.hrl")
- Record.defrecord :roster_version, Record.extract(:roster_version, from_lib: "ejabberd/include/mod_roster.hrl")
-
- @agent __MODULE__
-
- def init(domain, module) do
- try do
- Agent.stop(@agent)
- catch
- :exit, _e -> :ok
- end
-
- {:ok, _pid} = Agent.start_link(fn -> %{} end, name: @agent)
-
- mock_with_meck
-
- :ejabberd_mnesia.create(:mod_roster_mnesia, :roster,
- [ram_copies: [node()],
- attributes: Keyword.keys(roster(roster())),
- index: [:us]])
- :ejabberd_mnesia.create(:mod_roster_mnesia, :roster_version,
- [ram_copies: [node()],
- attributes: Keyword.keys(roster_version(roster_version()))])
- #:mod_roster.stop(domain)
- :gen_mod.start_module(domain, :mod_roster)
- end
-
- def mock_with_meck do
-# mock(:gen_mod, :db_type,
-# fn (_server, :mod_roster_mnesia) ->
-# :mnesia
-# end)
-#
-# mock(:mnesia, :transaction,
-# fn (_server, function) ->
-# {:atomic, function.()}
-# end)
-#
-# mock(:mnesia, :write,
-# fn (Item) ->
-# throw Item
-# {:atomic, :ok}
-# end)
-
- mock(:mod_roster_mnesia, :init,
- fn (_server, _opts) ->
- :ok
- end)
- mock(:mod_roster_mnesia, :transaction,
- fn (_server, function) ->
- {:atomic, function.()}
- end)
-
- mock(:mod_roster_mnesia, :update_roster_t,
- fn (user, domain, {u, d, _r}, item) ->
- add_roster_item(user, domain, u<>"@"<>d,
- roster(item, :name),
- roster(item, :subscription),
- roster(item, :groups),
- roster(item, :ask),
- roster(item, :askmessage))
- end)
-
- mock(:mod_roster_mnesia, :invalidate_roster_cache,
- fn (_user, _server) ->
- :ok
- end)
-
- end
-
- def add_roster_item(user, domain, jid, nick, subs \\ :none, groups \\ [],
- ask \\ :none, askmessage \\ "")
- when is_binary(user) and byte_size(user) > 0
- and is_binary(domain) and byte_size(domain) > 0
- and is_binary(jid) and byte_size(jid) > 0
- and is_binary(nick)
- and is_atom(subs)
- and is_list(groups)
- and is_atom(ask)
- and is_binary(askmessage)
- do
- Agent.update(@agent, fn roster ->
- Map.put(roster, {user, domain, jid}, %{nick: nick,
- subs: subs, groups: groups,
- ask: ask, askmessage: askmessage})
- end)
- end
-
- def remove_roster_item(user, domain, jid) do
- Agent.update(@agent, fn roster ->
- Map.delete(roster, {user, domain, jid})
- end)
- end
-
- def get_rosters() do
- Agent.get(@agent, fn roster -> roster end)
- end
-
- def get_roster(user, domain) do
- Agent.get(@agent, fn roster ->
- for {u, d, jid} <- Map.keys(roster), u == user, d == domain,
- do: {{u, d, jid}, Map.fetch!(roster, {u, d, jid})}
- end)
- end
-
- def to_record({{user, domain, jid}, r}) do
- roster(usj: {user, domain, jid},
- us: {user, domain},
- jid: :jid.from_string(jid),
- subscription: r.subs,
- ask: r.ask,
- groups: r.groups,
- askmessage: r.askmessage
- )
- end
- def to_records(rosters) do
- for item <- rosters, do: to_record(item)
- end
-
-####################################################################
-# Helpers
-####################################################################
-
- # TODO refactor: Move to ejabberd_test_mock
- def mock(module, function, fun) do
- try do
- :meck.new(module, [:non_strict, :passthrough, :unstick])
- catch
- :error, {:already_started, _pid} -> :ok
- end
-
- :meck.expect(module, function, fun)
- end
-
-end
+++ /dev/null
-Code.require_file "ejabberd_auth_mock.exs", __DIR__
-Code.require_file "ejabberd_oauth_mock.exs", __DIR__
-Code.require_file "ejabberd_sm_mock.exs", __DIR__
-Code.require_file "mod_last_mock.exs", __DIR__
-Code.require_file "mod_roster_mock.exs", __DIR__
-
-ExUnit.start