summaryrefslogtreecommitdiff
path: root/deps/rabbitmq_cli/test/ctl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/rabbitmq_cli/test/ctl')
-rw-r--r--deps/rabbitmq_cli/test/ctl/add_user_command_test.exs86
-rw-r--r--deps/rabbitmq_cli/test/ctl/add_vhost_command_test.exs68
-rw-r--r--deps/rabbitmq_cli/test/ctl/authenticate_user_command_test.exs81
-rw-r--r--deps/rabbitmq_cli/test/ctl/autocomplete_command_test.exs52
-rw-r--r--deps/rabbitmq_cli/test/ctl/await_online_nodes_command_test.exs44
-rw-r--r--deps/rabbitmq_cli/test/ctl/await_startup_command_test.exs49
-rw-r--r--deps/rabbitmq_cli/test/ctl/cancel_sync_command_test.exs64
-rw-r--r--deps/rabbitmq_cli/test/ctl/change_cluster_node_type_command_test.exs84
-rw-r--r--deps/rabbitmq_cli/test/ctl/change_password_command_test.exs80
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_global_parameter_command_test.exs86
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_operator_policy_command_test.exs127
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_parameter_command_test.exs138
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_password_command_test.exs64
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_permissions_command_test.exs100
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_policy_command_test.exs129
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_topic_permissions_command_test.exs107
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_user_limits_command_test.exs115
-rw-r--r--deps/rabbitmq_cli/test/ctl/clear_vhost_limits_command_test.exs103
-rw-r--r--deps/rabbitmq_cli/test/ctl/close_all_connections_command_test.exs147
-rw-r--r--deps/rabbitmq_cli/test/ctl/close_connection_command_test.exs96
-rw-r--r--deps/rabbitmq_cli/test/ctl/cluster_status_command_test.exs50
-rw-r--r--deps/rabbitmq_cli/test/ctl/decode_command_test.exs95
-rw-r--r--deps/rabbitmq_cli/test/ctl/delete_queue_command_test.exs119
-rw-r--r--deps/rabbitmq_cli/test/ctl/delete_user_command_test.exs59
-rw-r--r--deps/rabbitmq_cli/test/ctl/delete_vhost_command_test.exs67
-rw-r--r--deps/rabbitmq_cli/test/ctl/enable_feature_flag_test.exs70
-rw-r--r--deps/rabbitmq_cli/test/ctl/encode_command_test.exs92
-rw-r--r--deps/rabbitmq_cli/test/ctl/environment_command_test.exs45
-rw-r--r--deps/rabbitmq_cli/test/ctl/eval_command_test.exs74
-rw-r--r--deps/rabbitmq_cli/test/ctl/eval_file_command_test.exs72
-rw-r--r--deps/rabbitmq_cli/test/ctl/exec_command_test.exs47
-rw-r--r--deps/rabbitmq_cli/test/ctl/export_definitions_command_test.exs138
-rw-r--r--deps/rabbitmq_cli/test/ctl/force_boot_command_test.exs63
-rw-r--r--deps/rabbitmq_cli/test/ctl/force_gc_command_test.exs46
-rw-r--r--deps/rabbitmq_cli/test/ctl/force_reset_command_test.exs68
-rw-r--r--deps/rabbitmq_cli/test/ctl/forget_cluster_node_command_test.exs132
-rw-r--r--deps/rabbitmq_cli/test/ctl/help_command_test.exs76
-rw-r--r--deps/rabbitmq_cli/test/ctl/import_definitions_command_test.exs88
-rw-r--r--deps/rabbitmq_cli/test/ctl/join_cluster_command_test.exs104
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_bindings_command_test.exs85
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_channels_command_test.exs118
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_ciphers_command_test.exs29
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_connections_command_test.exs90
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_consumers_command_test.exs213
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_exchanges_command_test.exs160
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_feature_flags_command_test.exs122
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_global_parameters_command_test.exs86
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_hashes_command_test.exs29
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_operator_policies_command_test.exs142
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_parameters_command_test.exs154
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_permissions_command_test.exs92
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_policies_command_test.exs144
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_queues_command_test.exs145
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_topic_permissions_command_test.exs85
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_user_limits_command_test.exs103
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_user_permissions_command_test.exs91
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_user_topic_permissions_command_test.exs72
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_users_command_test.exs74
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_vhost_limits_command_test.exs111
-rw-r--r--deps/rabbitmq_cli/test/ctl/list_vhosts_command_test.exs160
-rw-r--r--deps/rabbitmq_cli/test/ctl/node_health_check_command_test.exs65
-rw-r--r--deps/rabbitmq_cli/test/ctl/ping_command_test.exs56
-rw-r--r--deps/rabbitmq_cli/test/ctl/purge_queue_command_test.exs88
-rw-r--r--deps/rabbitmq_cli/test/ctl/rename_cluster_node_command_test.exs102
-rw-r--r--deps/rabbitmq_cli/test/ctl/report_command_test.exs44
-rw-r--r--deps/rabbitmq_cli/test/ctl/reset_command_test.exs68
-rw-r--r--deps/rabbitmq_cli/test/ctl/restart_vhost_command_test.exs95
-rw-r--r--deps/rabbitmq_cli/test/ctl/resume_listeners_command_test.exs67
-rw-r--r--deps/rabbitmq_cli/test/ctl/rotate_logs_command_test.exs40
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_cluster_name_command_test.exs63
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_disk_free_limit_command_test.exs173
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_global_parameter_command_test.exs82
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_log_level_command_test.exs44
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_operator_policy_command_test.exs153
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_parameter_command_test.exs136
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs114
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_policy_command_test.exs217
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_topic_permissions_command_test.exs114
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_user_limits_command_test.exs137
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_user_tags_command_test.exs144
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_vhost_limits_command_test.exs137
-rw-r--r--deps/rabbitmq_cli/test/ctl/set_vm_memory_high_watermark_command_test.exs162
-rw-r--r--deps/rabbitmq_cli/test/ctl/shutdown_command_test.exs53
-rw-r--r--deps/rabbitmq_cli/test/ctl/start_app_command_test.exs50
-rw-r--r--deps/rabbitmq_cli/test/ctl/status_command_test.exs40
-rw-r--r--deps/rabbitmq_cli/test/ctl/stop_app_command_test.exs49
-rw-r--r--deps/rabbitmq_cli/test/ctl/stop_command_test.exs52
-rw-r--r--deps/rabbitmq_cli/test/ctl/suspend_listeners_command_test.exs67
-rw-r--r--deps/rabbitmq_cli/test/ctl/sync_queue_command_test.exs64
-rw-r--r--deps/rabbitmq_cli/test/ctl/trace_off_command_test.exs78
-rw-r--r--deps/rabbitmq_cli/test/ctl/trace_on_command_test.exs79
-rw-r--r--deps/rabbitmq_cli/test/ctl/update_cluster_nodes_command_test.exs80
-rw-r--r--deps/rabbitmq_cli/test/ctl/version_command_test.exs24
-rw-r--r--deps/rabbitmq_cli/test/ctl/wait_command_test.exs114
94 files changed, 8681 insertions, 0 deletions
diff --git a/deps/rabbitmq_cli/test/ctl/add_user_command_test.exs b/deps/rabbitmq_cli/test/ctl/add_user_command_test.exs
new file mode 100644
index 0000000000..ec21691da9
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/add_user_command_test.exs
@@ -0,0 +1,86 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule AddUserCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.AddUserCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn -> delete_user(context[:user]) end)
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: no positional arguments fails" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: too many positional arguments fails" do
+ assert @command.validate(["user", "password", "extra"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: two arguments passes" do
+ assert @command.validate(["user", "password"], %{}) == :ok
+ end
+
+ test "validate: one argument passes" do
+ assert @command.validate(["user"], %{}) == :ok
+ end
+
+ @tag user: "", password: "password"
+ test "validate: an empty username fails", context do
+ assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([context[:user], context[:password]], context[:opts]))
+ end
+
+ # Blank passwords are currently allowed, they make sense
+ # e.g. when a user only authenticates using X.509 certificates.
+ # Credential validators can be used to require passwords of a certain length
+ # or following a certain pattern. This is a core server responsibility. MK.
+ @tag user: "some_rando", password: ""
+ test "validate: an empty password is allowed", context do
+ assert @command.validate([context[:user], context[:password]], context[:opts]) == :ok
+ end
+
+ @tag user: "someone", password: "password"
+ test "run: request to a non-existent node returns a badrpc", context do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([context[:user], context[:password]], opts))
+ end
+
+ @tag user: "someone", password: "password"
+ test "run: default case completes successfully", context do
+ assert @command.run([context[:user], context[:password]], context[:opts]) == :ok
+ assert list_users() |> Enum.count(fn(record) -> record[:user] == context[:user] end) == 1
+ end
+
+ @tag user: "someone", password: "password"
+ test "run: adding an existing user returns an error", context do
+ add_user(context[:user], context[:password])
+ assert @command.run([context[:user], context[:password]], context[:opts]) == {:error, {:user_already_exists, context[:user]}}
+ assert list_users() |> Enum.count(fn(record) -> record[:user] == context[:user] end) == 1
+ end
+
+ @tag user: "someone", password: "password"
+ test "banner", context do
+ assert @command.banner([context[:user], context[:password]], context[:opts])
+ =~ ~r/Adding user \"#{context[:user]}\" \.\.\./
+ end
+
+ @tag user: "someone"
+ test "output: formats a user_already_exists error", context do
+ {:error, 70, "User \"someone\" already exists"} =
+ @command.output({:error, {:user_already_exists, context[:user]}}, %{})
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/add_vhost_command_test.exs b/deps/rabbitmq_cli/test/ctl/add_vhost_command_test.exs
new file mode 100644
index 0000000000..f9f6362c19
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/add_vhost_command_test.exs
@@ -0,0 +1,68 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule AddVhostCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.AddVhostCommand
+ @vhost "test"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ setup context do
+ on_exit(context, fn -> delete_vhost(context[:vhost]) end)
+ :ok
+ end
+
+ test "validate: no arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: too many arguments fails validation" do
+ assert @command.validate(["test", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: one argument passes validation" do
+ assert @command.validate(["new-vhost"], %{}) == :ok
+ assert @command.validate(["new-vhost"], %{description: "Used by team A"}) == :ok
+ assert @command.validate(["new-vhost"], %{description: "Used by team A for QA purposes", tags: "qa,team-a"}) == :ok
+ end
+
+ @tag vhost: @vhost
+ test "run: passing a valid vhost name to a running RabbitMQ node succeeds", context do
+ assert @command.run([context[:vhost]], context[:opts]) == :ok
+ assert list_vhosts() |> Enum.count(fn(record) -> record[:name] == context[:vhost] end) == 1
+ end
+
+ @tag vhost: ""
+ test "run: passing an empty string for vhost name with a running RabbitMQ node still succeeds", context do
+ assert @command.run([context[:vhost]], context[:opts]) == :ok
+ assert list_vhosts() |> Enum.count(fn(record) -> record[:name] == context[:vhost] end) == 1
+ end
+
+ test "run: attempt to use an unreachable node returns a nodedown" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["na"], opts))
+ end
+
+ test "run: adding the same host twice is idempotent", context do
+ add_vhost context[:vhost]
+
+ assert @command.run([context[:vhost]], context[:opts]) == :ok
+ assert list_vhosts() |> Enum.count(fn(record) -> record[:name] == context[:vhost] end) == 1
+ end
+
+ @tag vhost: @vhost
+ test "banner", context do
+ assert @command.banner([context[:vhost]], context[:opts])
+ =~ ~r/Adding vhost \"#{context[:vhost]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/authenticate_user_command_test.exs b/deps/rabbitmq_cli/test/ctl/authenticate_user_command_test.exs
new file mode 100644
index 0000000000..506dfad367
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/authenticate_user_command_test.exs
@@ -0,0 +1,81 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule AuthenticateUserCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands. AuthenticateUserCommand
+ @user "user1"
+ @password "password"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_user(@user, @password)
+ on_exit(context, fn -> delete_user(@user) end)
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: no positional arguments fails" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: too many positional arguments fails" do
+ assert @command.validate(["user", "password", "extra"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: one argument passes" do
+ assert @command.validate(["user"], %{}) == :ok
+ end
+
+ test "validate: two arguments passes" do
+ assert @command.validate(["user", "password"], %{}) == :ok
+ end
+
+ @tag user: @user, password: @password
+ test "run: a valid username and password returns okay", context do
+ assert {:ok, _} = @command.run([context[:user], context[:password]], context[:opts])
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["user", "password"], opts))
+ end
+
+ @tag user: @user, password: "treachery"
+ test "run: a valid username and invalid password returns refused", context do
+ assert {:refused, _, _, _} = @command.run([context[:user], context[:password]], context[:opts])
+ end
+
+ @tag user: "interloper", password: @password
+ test "run: an invalid username returns refused", context do
+ assert {:refused, _, _, _} = @command.run([context[:user], context[:password]], context[:opts])
+ end
+
+ @tag user: @user, password: @password
+ test "banner", context do
+ assert @command.banner([context[:user], context[:password]], context[:opts])
+ =~ ~r/Authenticating user/
+ assert @command.banner([context[:user], context[:password]], context[:opts])
+ =~ ~r/"#{context[:user]}"/
+ end
+
+ test "output: refused error", context do
+ user = "example_user"
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_dataerr
+ assert match?({:error, ^exit_code,
+ "Error: failed to authenticate user \"example_user\"\n" <>
+ "Unable to foo"},
+ @command.output({:refused, user, "Unable to ~s", ["foo"]}, context[:opts]))
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/autocomplete_command_test.exs b/deps/rabbitmq_cli/test/ctl/autocomplete_command_test.exs
new file mode 100644
index 0000000000..52b3c8d026
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/autocomplete_command_test.exs
@@ -0,0 +1,52 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule AutocompleteCommandTest do
+ use ExUnit.Case, async: true
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.AutocompleteCommand
+ setup do
+ {:ok, opts: %{
+ script_name: "rabbitmqctl",
+ node: get_rabbit_hostname()
+ }}
+ end
+
+ test "shows up in help" do
+ s = @command.usage()
+ assert s =~ ~r/autocomplete/
+ end
+
+ test "enforces --silent" do
+ assert @command.merge_defaults(["list_"], %{}) == {["list_"], %{silent: true}}
+ end
+
+ test "validate: providing no arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing two or more arguments fails validation" do
+ assert @command.validate(["list_", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: providing a single argument passes validation" do
+ assert @command.validate(["list_c"], %{}) == :ok
+ end
+
+ test "run: lists completion options", context do
+ {:stream, completion_options} = @command.run(["list_c"], context[:opts])
+
+ assert Enum.member?(completion_options, "list_channels")
+ assert Enum.member?(completion_options, "list_connections")
+ assert Enum.member?(completion_options, "list_consumers")
+ end
+
+ test "banner shows that the name is being set", context do
+ assert @command.banner(["list_"], context[:opts]) == nil
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/await_online_nodes_command_test.exs b/deps/rabbitmq_cli/test/ctl/await_online_nodes_command_test.exs
new file mode 100644
index 0000000000..bf9eeb574d
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/await_online_nodes_command_test.exs
@@ -0,0 +1,44 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule AwaitOnlineNodesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.AwaitOnlineNodesCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 300_000}}
+ end
+
+ setup context do
+ on_exit(context, fn -> delete_vhost(context[:vhost]) end)
+ :ok
+ end
+
+ test "validate: wrong number of arguments results in arg count errors" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["1", "1"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: a call with node count of 1 with a running RabbitMQ node succeeds", context do
+ assert @command.run(["1"], context[:opts]) == :ok
+ end
+
+ test "run: a call to an unreachable RabbitMQ node returns a nodedown" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["1"], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner(["1"], context[:opts])
+ =~ ~r/Will wait for at least 1 nodes to join the cluster of #{context[:opts][:node]}. Timeout: 300 seconds./
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/await_startup_command_test.exs b/deps/rabbitmq_cli/test/ctl/await_startup_command_test.exs
new file mode 100644
index 0000000000..554ec5ee77
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/await_startup_command_test.exs
@@ -0,0 +1,49 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+# Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule AwaitStartupCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.AwaitStartupCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 300_000}}
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "merge_defaults: default timeout is 5 minutes" do
+ assert @command.merge_defaults([], %{}) == {[], %{timeout: 300_000}}
+ end
+
+ test "validate: accepts no arguments", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "run: request to a fully booted node succeeds", context do
+ # this timeout value is in seconds
+ assert @command.run([], Map.merge(context[:opts], %{timeout: 5})) == :ok
+ end
+
+ test "empty banner", context do
+ nil = @command.banner([], context[:opts])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/cancel_sync_command_test.exs b/deps/rabbitmq_cli/test/ctl/cancel_sync_command_test.exs
new file mode 100644
index 0000000000..8503e6ab5f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/cancel_sync_command_test.exs
@@ -0,0 +1,64 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule CancelSyncQueueCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.CancelSyncQueueCommand
+
+ @vhost "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost
+ }}
+ end
+
+ test "validate: specifying no queue name is reported as an error", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: specifying two queue names is reported as an error", context do
+ assert @command.validate(["q1", "q2"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: specifying three queue names is reported as an error", context do
+ assert @command.validate(["q1", "q2", "q3"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: specifying one queue name succeeds", context do
+ assert @command.validate(["q1"], context[:opts]) == :ok
+ end
+
+ test "run: request to a non-existent RabbitMQ node returns a nodedown" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["q1"], opts))
+ end
+
+ test "banner", context do
+ s = @command.banner(["q1"], context[:opts])
+
+ assert s =~ ~r/Stopping synchronising queue/
+ assert s =~ ~r/q1/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/change_cluster_node_type_command_test.exs b/deps/rabbitmq_cli/test/ctl/change_cluster_node_type_command_test.exs
new file mode 100644
index 0000000000..8fcb7de3ae
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/change_cluster_node_type_command_test.exs
@@ -0,0 +1,84 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ChangeClusterNodeTypeCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ChangeClusterNodeTypeCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname()
+ }}
+ end
+
+ test "validate: node type of disc, disk, and ram pass validation", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["foo"], context[:opts]))
+
+ assert :ok == @command.validate(["ram"], context[:opts])
+ assert :ok == @command.validate(["disc"], context[:opts])
+ assert :ok == @command.validate(["disk"], context[:opts])
+ end
+
+ test "validate: providing no arguments fails validation", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+ test "validate: providing too many arguments fails validation", context do
+ assert @command.validate(["a", "b", "c"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ # TODO
+ #test "run: change ram node to disc node", context do
+ #end
+
+ # TODO
+ #test "run: change disk node to ram node", context do
+ #end
+
+ test "run: request to a node with running RabbitMQ app fails", context do
+ assert match?(
+ {:error, :mnesia_unexpectedly_running},
+ @command.run(["ram"], context[:opts]))
+ end
+
+ test "run: request to an unreachable node returns a badrpc", _context do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?(
+ {:badrpc, :nodedown},
+ @command.run(["ram"], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner(["ram"], context[:opts]) =~
+ ~r/Turning #{get_rabbit_hostname()} into a ram node/
+ end
+
+ test "output mnesia is running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code,
+ "Mnesia is still running on node " <> _},
+ @command.output({:error, :mnesia_unexpectedly_running}, context[:opts]))
+
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/change_password_command_test.exs b/deps/rabbitmq_cli/test/ctl/change_password_command_test.exs
new file mode 100644
index 0000000000..3a415085dd
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/change_password_command_test.exs
@@ -0,0 +1,80 @@
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ChangePasswordCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands. ChangePasswordCommand
+ @user "user1"
+ @password "password"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_user(@user, @password)
+ on_exit(context, fn -> delete_user(@user) end)
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: no positional arguments fails" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: too many positional arguments fails" do
+ assert @command.validate(["user", "password", "extra"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: two arguments passes" do
+ assert @command.validate(["user", "password"], %{}) == :ok
+ end
+
+ test "validate: one argument passes" do
+ assert @command.validate(["user"], %{}) == :ok
+ end
+
+ @tag user: @user, password: "new_password"
+ test "run: a valid username and new password return ok", context do
+ assert @command.run([context[:user], context[:password]], context[:opts]) == :ok
+ assert {:ok, _} = authenticate_user(context[:user], context[:password])
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["user", "password"], opts))
+ end
+
+ @tag user: @user, password: @password
+ test "run: changing password to the same thing is ok", context do
+ assert @command.run([context[:user], context[:password]], context[:opts]) == :ok
+ assert {:ok, _} = authenticate_user(context[:user], context[:password])
+ end
+
+ @tag user: "interloper", password: "new_password"
+ test "run: an invalid user returns an error", context do
+ assert @command.run([context[:user], context[:password]], context[:opts]) == {:error, {:no_such_user, "interloper"}}
+ end
+
+ @tag user: @user, password: @password
+ test "banner", context do
+ assert @command.banner([context[:user], context[:password]], context[:opts])
+ =~ ~r/Changing password for user/
+ assert @command.banner([context[:user], context[:password]], context[:opts])
+ =~ ~r/"#{context[:user]}"/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_global_parameter_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_global_parameter_command_test.exs
new file mode 100644
index 0000000000..adadc3c223
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_global_parameter_command_test.exs
@@ -0,0 +1,86 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearGlobalParameterCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearGlobalParameterCommand
+ @key :mqtt_default_vhosts
+ @value "{\"O=client,CN=dummy\":\"somevhost\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_global_parameter context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "validate: expects a single argument" do
+ assert @command.validate(["one"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this is", "too many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag key: @key
+ test "run: when global parameter does not exist, returns an error", context do
+ assert @command.run(
+ [context[:key]],
+ context[:opts]
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([@key], opts))
+ end
+
+ @tag key: @key
+ test "run: clears the parameter", context do
+ set_global_parameter(context[:key], @value)
+
+ assert @command.run(
+ [context[:key]],
+ context[:opts]
+ ) == :ok
+
+ assert_parameter_empty(context)
+ end
+
+ @tag key: @key, value: @value
+ test "banner", context do
+ set_global_parameter(context[:key], @value)
+
+ s = @command.banner(
+ [context[:key]],
+ context[:opts]
+ )
+
+ assert s =~ ~r/Clearing global runtime parameter/
+ assert s =~ ~r/"#{context[:key]}"/
+ end
+
+ defp assert_parameter_empty(context) do
+ parameter = list_global_parameters()
+ |> Enum.filter(fn(param) ->
+ param[:key] == context[:key]
+ end)
+ assert parameter === []
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_operator_policy_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_operator_policy_command_test.exs
new file mode 100644
index 0000000000..834caf89f7
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_operator_policy_command_test.exs
@@ -0,0 +1,127 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearOperatorPolicyCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearOperatorPolicyCommand
+ @vhost "test1"
+ @key "message-expiry"
+ @pattern "^queue\."
+ @value "{\"message-ttl\":10}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_operator_policy(context[:vhost], context[:key])
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "merge_defaults: adds default vhost if missing" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ end
+
+ test "merge_defaults: does not change provided vhost" do
+ assert @command.merge_defaults([], %{vhost: "test_vhost"}) == {[], %{vhost: "test_vhost"}}
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: providing one argument and no options passes validation" do
+ assert @command.validate(["a-policy"], %{}) == :ok
+ end
+
+ @tag pattern: @pattern, key: @key, vhost: @vhost
+ test "run: if policy does not exist, returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+ assert match?({:badrpc, _}, @command.run([@key], opts))
+ end
+
+
+ @tag pattern: @pattern, key: @key, vhost: @vhost
+ test "run: if policy exists, returns ok and removes it", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ set_operator_policy(context[:vhost], context[:key], context[:pattern], @value)
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == :ok
+
+ assert_operator_policy_does_not_exist(context)
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: a non-existent vhost returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_operator_policy(context[:vhost], context[:key], context[:pattern], @value)
+
+ s = @command.banner(
+ [context[:key]],
+ vhost_opts
+ )
+
+ assert s =~ ~r/Clearing operator policy/
+ assert s =~ ~r/"#{context[:key]}"/
+ end
+
+ defp assert_operator_policy_does_not_exist(context) do
+ policy = context[:vhost]
+ |> list_operator_policies
+ |> Enum.filter(fn(param) ->
+ param[:pattern] == context[:pattern] and
+ param[:key] == context[:key]
+ end)
+ assert policy === []
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_parameter_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_parameter_command_test.exs
new file mode 100644
index 0000000000..4f08234cb6
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_parameter_command_test.exs
@@ -0,0 +1,138 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearParameterCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearParameterCommand
+ @vhost "test1"
+ @root "/"
+ @component_name "federation-upstream"
+ @key "reconnect-delay"
+ @value "{\"uri\":\"amqp://127.0.0.1:5672\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ enable_federation_plugin()
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_parameter context[:vhost], context[:component_name], context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "merge_defaults: adds default vhost if missing" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: argument validation" do
+ assert @command.validate(["one", "two"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this", "is", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag component_name: @component_name, key: @key, vhost: @vhost
+ test "run: returns error, if parameter does not exist", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:component_name], context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+ assert match?({:badrpc, _}, @command.run([@component_name, @key], opts))
+ end
+
+
+ @tag component_name: @component_name, key: @key, vhost: @vhost
+ test "run: returns ok and clears parameter, if it exists", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ set_parameter(context[:vhost], context[:component_name], context[:key], @value)
+
+ assert @command.run(
+ [context[:component_name], context[:key]],
+ vhost_opts
+ ) == :ok
+
+ assert_parameter_empty(context)
+ end
+
+ @tag component_name: "bad-component-name", key: @key, value: @value, vhost: @root
+ test "run: an invalid component_name returns a 'parameter does not exist' error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ assert @command.run(
+ [context[:component_name], context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+
+ assert list_parameters(context[:vhost]) == []
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: an invalid vhost returns a 'parameter does not exist' error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:component_name], context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_parameter(context[:vhost], context[:component_name], context[:key], @value)
+
+ s = @command.banner(
+ [context[:component_name], context[:key]],
+ vhost_opts
+ )
+
+ assert s =~ ~r/Clearing runtime parameter/
+ assert s =~ ~r/"#{context[:key]}"/
+ assert s =~ ~r/"#{context[:component_name]}"/
+ assert s =~ ~r/"#{context[:vhost]}"/
+ end
+
+ defp assert_parameter_empty(context) do
+ parameter = context[:vhost]
+ |> list_parameters
+ |> Enum.filter(fn(param) ->
+ param[:component_name] == context[:component_name] and
+ param[:key] == context[:key]
+ end)
+ assert parameter === []
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_password_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_password_command_test.exs
new file mode 100644
index 0000000000..0843ca3970
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_password_command_test.exs
@@ -0,0 +1,64 @@
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearPasswordCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands. ClearPasswordCommand
+ @user "user1"
+ @password "password"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_user(@user, @password)
+ on_exit(context, fn -> delete_user(@user) end)
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: argument count is correct" do
+ assert @command.validate(["username"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["username", "extra"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ @tag user: @user, password: @password
+ test "run: a valid username clears the password and returns okay", context do
+ assert @command.run([context[:user]], context[:opts]) == :ok
+ assert {:refused, _, _, _} = authenticate_user(context[:user], context[:password])
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["user"], opts))
+ end
+
+ @tag user: "interloper"
+ test "run: An invalid username returns a no-such-user error message", context do
+ assert @command.run([context[:user]], context[:opts]) == {:error, {:no_such_user, "interloper"}}
+ end
+
+ @tag user: @user
+ test "banner", context do
+ s = @command.banner([context[:user]], context[:opts])
+
+ assert s =~ ~r/Clearing password/
+ assert s =~ ~r/"#{context[:user]}"/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_permissions_command_test.exs
new file mode 100644
index 0000000000..89bfe8c457
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_permissions_command_test.exs
@@ -0,0 +1,100 @@
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearPermissionsTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands. ClearPermissionsCommand
+ @user "user1"
+ @password "password"
+ @default_vhost "/"
+ @specific_vhost "vhost1"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_user(@user, @password)
+ add_vhost(@specific_vhost)
+
+ on_exit([], fn ->
+ delete_user(@user)
+ delete_vhost(@specific_vhost)
+ end)
+
+ :ok
+ end
+
+ setup context do
+ set_permissions(@user, @default_vhost, ["^#{@user}-.*", ".*", ".*"])
+ set_permissions(@user, @specific_vhost, ["^#{@user}-.*", ".*", ".*"])
+
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), vhost: context[:vhost]}
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: argument count validates" do
+ assert @command.validate(["one"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag user: "fake_user"
+ test "run: can't clear permissions for non-existing user", context do
+ assert @command.run([context[:user]], context[:opts]) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ @tag user: @user, vhost: @default_vhost
+ test "run: a valid username clears permissions", context do
+ assert @command.run([context[:user]], context[:opts]) == :ok
+
+ assert list_permissions(@default_vhost)
+ |> Enum.filter(fn(record) -> record[:user] == context[:user] end) == []
+ end
+
+ test "run: on an invalid node, return a badrpc message" do
+ arg = ["some_name"]
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(arg, opts))
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "run: on a valid specified vhost, clear permissions", context do
+ assert @command.run([context[:user]], context[:opts]) == :ok
+
+ assert list_permissions(context[:vhost])
+ |> Enum.filter(fn(record) -> record[:user] == context[:user] end) == []
+ end
+
+ @tag user: @user, vhost: "bad_vhost"
+ test "run: on an invalid vhost, return no_such_vhost error", context do
+ assert @command.run([context[:user]], context[:opts]) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "banner", context do
+ s = @command.banner([context[:user]], context[:opts])
+
+ assert s =~ ~r/Clearing permissions/
+ assert s =~ ~r/\"#{context[:user]}\"/
+ assert s =~ ~r/\"#{context[:vhost]}\"/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_policy_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_policy_command_test.exs
new file mode 100644
index 0000000000..f36f65d25f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_policy_command_test.exs
@@ -0,0 +1,129 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearPolicyCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearPolicyCommand
+ @vhost "test1"
+ @key "federate"
+ @pattern "^fed\."
+ @value "{\"federation-upstream-set\":\"all\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ enable_federation_plugin()
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_policy context[:vhost], context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "merge_defaults: adds default vhost if missing" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert @command.merge_defaults([], %{vhost: "test_vhost"}) == {[], %{vhost: "test_vhost"}}
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: providing one argument and no options passes validation" do
+ assert @command.validate(["a-policy"], %{}) == :ok
+ end
+
+ @tag pattern: @pattern, key: @key, vhost: @vhost
+ test "run: if policy does not exist, returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+ assert match?({:badrpc, _}, @command.run([@key], opts))
+ end
+
+
+ @tag pattern: @pattern, key: @key, vhost: @vhost
+ test "run: if policy exists, returns ok and removes it", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ set_policy(context[:vhost], context[:key], context[:pattern], @value)
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == :ok
+
+ assert_policy_does_not_exist(context)
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: a non-existent vhost returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key]],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_policy(context[:vhost], context[:key], context[:pattern], @value)
+
+ s = @command.banner(
+ [context[:key]],
+ vhost_opts
+ )
+
+ assert s =~ ~r/Clearing policy/
+ assert s =~ ~r/"#{context[:key]}"/
+ end
+
+ defp assert_policy_does_not_exist(context) do
+ policy = context[:vhost]
+ |> list_policies
+ |> Enum.filter(fn(param) ->
+ param[:pattern] == context[:pattern] and
+ param[:key] == context[:key]
+ end)
+ assert policy === []
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_topic_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_topic_permissions_command_test.exs
new file mode 100644
index 0000000000..2b5fb6e12a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_topic_permissions_command_test.exs
@@ -0,0 +1,107 @@
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearTopicPermissionsTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands. ClearTopicPermissionsCommand
+ @user "user1"
+ @password "password"
+ @specific_vhost "vhost1"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_user(@user, @password)
+ add_vhost(@specific_vhost)
+
+ on_exit([], fn ->
+ clear_topic_permissions(@user, @specific_vhost)
+ delete_user(@user)
+ delete_vhost(@specific_vhost)
+ end)
+
+ :ok
+ end
+
+ setup context do
+ set_topic_permissions(@user, @specific_vhost, "amq.topic", "^a", "^b")
+ set_topic_permissions(@user, @specific_vhost, "topic1", "^a", "^b")
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), vhost: context[:vhost]}
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: expects username and optional exchange" do
+ assert @command.validate(["username"], %{}) == :ok
+ assert @command.validate(["username", "exchange"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag user: "fake_user"
+ test "run: can't clear topic permissions for non-existing user", context do
+ assert @command.run([context[:user]], context[:opts]) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ @tag user: @user, vhost: "bad_vhost"
+ test "run: on an invalid vhost, return no_such_vhost error", context do
+ assert @command.run([context[:user]], context[:opts]) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "run: with a valid username clears all permissions for vhost", context do
+ assert Enum.count(list_user_topic_permissions(@user)) == 2
+ assert @command.run([context[:user]], context[:opts]) == :ok
+
+ assert Enum.count(list_user_topic_permissions(@user)) == 0
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "run: with a valid username and exchange clears only exchange permissions", context do
+ assert Enum.count(list_user_topic_permissions(@user)) == 2
+ assert @command.run([context[:user], "amq.topic"], context[:opts]) == :ok
+
+ assert Enum.count(list_user_topic_permissions(@user)) == 1
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ arg = ["some_name"]
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(arg, opts))
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "banner with username only", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:user]], vhost_opts)
+ =~ ~r/Clearing topic permissions for user \"#{context[:user]}\" in vhost \"#{context[:vhost]}\" \.\.\./
+ end
+
+ @tag user: @user, vhost: @specific_vhost
+ test "banner with username and exchange name", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:user], "amq.topic"], vhost_opts)
+ =~ ~r/Clearing topic permissions on \"amq.topic\" for user \"#{context[:user]}\" in vhost \"#{context[:vhost]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_user_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_user_limits_command_test.exs
new file mode 100644
index 0000000000..eb05a875bc
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_user_limits_command_test.exs
@@ -0,0 +1,115 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ClearUserLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearUserLimitsCommand
+
+ @user "someone"
+ @password "password"
+ @limittype "max-channels"
+ @channel_definition "{\"max-channels\":100}"
+ @definition "{\"max-channels\":500, \"max-connections\":100}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_user @user, @password
+
+ on_exit([], fn ->
+ delete_user @user
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_user_limits(context[:user])
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not-enough"], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@user, @limittype], opts))
+ end
+
+ test "run: if limit exists, returns ok and clears it", context do
+ :ok = set_user_limits(@user, @channel_definition)
+
+ assert get_user_limits(@user) != []
+
+ assert @command.run(
+ [@user, @limittype],
+ context[:opts]
+ ) == :ok
+
+ assert get_user_limits(@user) == %{}
+ end
+
+ test "run: if limit exists, returns ok and clears all limits for the given user", context do
+ :ok = set_user_limits(@user, @definition)
+
+ assert get_user_limits(@user) != []
+
+ assert @command.run(
+ [@user, "all"],
+ context[:opts]
+ ) == :ok
+
+ assert get_user_limits(@user) == %{}
+ end
+
+ @tag user: "bad-user"
+ test "run: a non-existent user returns an error", context do
+
+ assert @command.run(
+ [context[:user], @limittype],
+ context[:opts]
+ ) == {:error, {:no_such_user, "bad-user"}}
+ end
+
+ test "banner: for a limit type", context do
+
+ s = @command.banner(
+ [@user, @limittype],
+ context[:opts]
+ )
+
+ assert s == "Clearing \"#{@limittype}\" limit for user \"#{@user}\" ..."
+ end
+
+ test "banner: for all", context do
+
+ s = @command.banner(
+ [@user, "all"],
+ context[:opts]
+ )
+
+ assert s == "Clearing all limits for user \"#{@user}\" ..."
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/clear_vhost_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/clear_vhost_limits_command_test.exs
new file mode 100644
index 0000000000..4dd681c901
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/clear_vhost_limits_command_test.exs
@@ -0,0 +1,103 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClearVhostLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClearVhostLimitsCommand
+ @vhost "test1"
+ @definition "{\"max-connections\":100}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_vhost_limits(context[:vhost])
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ }
+ }
+ end
+
+ test "merge_defaults: adds default vhost if missing" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert @command.merge_defaults([], %{vhost: "test_vhost"}) == {[], %{vhost: "test_vhost"}}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: providing zero arguments and no options passes validation" do
+ assert @command.validate([], %{}) == :ok
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+
+ @tag vhost: @vhost
+ test "run: if limits exist, returns ok and clears them", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ :ok = set_vhost_limits(context[:vhost], @definition)
+
+ assert get_vhost_limits(context[:vhost]) != []
+
+ assert @command.run(
+ [],
+ vhost_opts
+ ) == :ok
+
+ assert get_vhost_limits(context[:vhost]) == %{}
+ end
+
+ @tag vhost: "bad-vhost"
+ test "run: a non-existent vhost returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [],
+ vhost_opts
+ ) == {:error_string, 'Parameter does not exist'}
+ end
+
+ @tag vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ s = @command.banner(
+ [],
+ vhost_opts
+ )
+
+ assert s =~ ~r/Clearing vhost \"#{context[:vhost]}\" limits .../
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/close_all_connections_command_test.exs b/deps/rabbitmq_cli/test/ctl/close_all_connections_command_test.exs
new file mode 100644
index 0000000000..f08969f319
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/close_all_connections_command_test.exs
@@ -0,0 +1,147 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule CloseAllConnectionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ alias RabbitMQ.CLI.Ctl.RpcStream
+ @helpers RabbitMQ.CLI.Core.Helpers
+ @command RabbitMQ.CLI.Ctl.Commands.CloseAllConnectionsCommand
+
+ @vhost "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ close_all_connections(get_rabbit_hostname())
+
+ on_exit([], fn ->
+ close_all_connections(get_rabbit_hostname())
+ end)
+
+ :ok
+ end
+
+ setup context do
+ node_name = get_rabbit_hostname()
+ close_all_connections(node_name)
+ await_no_client_connections(node_name, 5_000)
+
+ {:ok, context}
+ end
+
+ test "validate: with an invalid number of arguments returns an arg count error", context do
+ assert @command.validate(["random", "explanation"], context[:opts]) == {:validation_failure, :too_many_args}
+ assert @command.validate([], context[:opts]) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: with the correct number of arguments returns ok", context do
+ assert @command.validate(["explanation"], context[:opts]) == :ok
+ end
+
+ test "run: a close connections request in an existing vhost with all defaults closes all connections", context do
+ with_connection(@vhost, fn(_) ->
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ nodes = @helpers.nodes_in_cluster(node)
+ [[vhost: @vhost]] = fetch_connection_vhosts(node, nodes)
+ opts = %{node: node, vhost: @vhost, global: false, per_connection_delay: 0, limit: 0}
+ assert {:ok, "Closed 1 connections"} == @command.run(["test"], opts)
+
+ await_no_client_connections(node, 5_000)
+ assert fetch_connection_vhosts(node, nodes) == []
+ end)
+ end
+
+ test "run: close a limited number of connections in an existing vhost closes a subset of connections", context do
+ with_connections([@vhost, @vhost, @vhost], fn(_) ->
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ nodes = @helpers.nodes_in_cluster(node)
+ [[vhost: @vhost], [vhost: @vhost], [vhost: @vhost]] = fetch_connection_vhosts(node, nodes)
+ opts = %{node: node, vhost: @vhost, global: false, per_connection_delay: 0, limit: 2}
+ assert {:ok, "Closed 2 connections"} == @command.run(["test"], opts)
+ Process.sleep(100)
+ assert fetch_connection_vhosts(node, nodes) == [[vhost: @vhost]]
+ end)
+ end
+
+ test "run: a close connections request for a non-existing vhost does nothing", context do
+ with_connection(@vhost, fn(_) ->
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ nodes = @helpers.nodes_in_cluster(node)
+ [[vhost: @vhost]] = fetch_connection_vhosts(node, nodes)
+ opts = %{node: node, vhost: "non_existent-9288737", global: false, per_connection_delay: 0, limit: 0}
+ assert {:ok, "Closed 0 connections"} == @command.run(["test"], opts)
+ assert fetch_connection_vhosts(node, nodes) == [[vhost: @vhost]]
+ end)
+ end
+
+ test "run: a close connections request to an existing node with --global (all vhosts)", context do
+ with_connection(@vhost, fn(_) ->
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ nodes = @helpers.nodes_in_cluster(node)
+ [[vhost: @vhost]] = fetch_connection_vhosts(node, nodes)
+ opts = %{node: node, global: true, per_connection_delay: 0, limit: 0}
+ assert {:ok, "Closed 1 connections"} == @command.run(["test"], opts)
+ await_no_client_connections(node, 5_000)
+ assert fetch_connection_vhosts(node, nodes) == []
+ end)
+ end
+
+ test "run: a close_all_connections request to non-existent RabbitMQ node returns a badrpc" do
+ opts = %{node: :jake@thedog, vhost: @vhost, global: true, per_connection_delay: 0, limit: 0, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["test"], opts))
+ end
+
+ test "banner for vhost option", context do
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ opts = %{node: node, vhost: "burrow", global: false, per_connection_delay: 0, limit: 0}
+ s = @command.banner(["some reason"], opts)
+ assert s =~ ~r/Closing all connections in vhost burrow/
+ assert s =~ ~r/some reason/
+ end
+
+ test "banner for vhost option with limit", context do
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ opts = %{node: node, vhost: "burrow", global: false, per_connection_delay: 0, limit: 2}
+ s = @command.banner(["some reason"], opts)
+ assert s =~ ~r/Closing 2 connections in vhost burrow/
+ assert s =~ ~r/some reason/
+ end
+
+ test "banner for global option" do
+ opts = %{node: :test@localhost, vhost: "burrow", global: true, per_connection_delay: 0, limit: 0}
+ s = @command.banner(["some reason"], opts)
+ assert s =~ ~r/Closing all connections to node test@localhost/
+ assert s =~ ~r/some reason/
+ end
+
+ defp fetch_connection_vhosts(node, nodes) do
+ fetch_connection_vhosts(node, nodes, 50)
+ end
+
+ defp fetch_connection_vhosts(node, nodes, retries) do
+ stream = RpcStream.receive_list_items(node,
+ :rabbit_networking,
+ :emit_connection_info_all,
+ [nodes, [:vhost]],
+ :infinity,
+ [:vhost],
+ Kernel.length(nodes))
+ xs = Enum.to_list(stream)
+
+ case {xs, retries} do
+ {xs, 0} ->
+ xs
+ {[], n} when n >= 0 ->
+ Process.sleep(10)
+ fetch_connection_vhosts(node, nodes, retries - 1)
+ _ ->
+ xs
+ end
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/close_connection_command_test.exs b/deps/rabbitmq_cli/test/ctl/close_connection_command_test.exs
new file mode 100644
index 0000000000..0d1271a67f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/close_connection_command_test.exs
@@ -0,0 +1,96 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule CloseConnectionCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ alias RabbitMQ.CLI.Ctl.RpcStream
+
+ @helpers RabbitMQ.CLI.Core.Helpers
+
+ @command RabbitMQ.CLI.Ctl.Commands.CloseConnectionCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ close_all_connections(get_rabbit_hostname())
+
+ on_exit([], fn ->
+ close_all_connections(get_rabbit_hostname())
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: :infinity}}
+ end
+
+ test "validate: with an invalid number of arguments returns an arg count error", context do
+ assert @command.validate(["pid", "explanation", "extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ assert @command.validate(["pid"], context[:opts]) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: with the correct number of arguments returns ok", context do
+ assert @command.validate(["pid", "test"], context[:opts]) == :ok
+ end
+
+ test "run: a close connection request on an existing connection", context do
+ with_connection("/", fn(_) ->
+ Process.sleep(500)
+ node = @helpers.normalise_node(context[:node], :shortnames)
+ nodes = @helpers.nodes_in_cluster(node)
+ [[pid: pid]] = fetch_connection_pids(node, nodes)
+ assert :ok == @command.run([:rabbit_misc.pid_to_string(pid), "test"], %{node: node})
+ Process.sleep(500)
+ assert fetch_connection_pids(node, nodes) == []
+ end)
+ end
+
+ test "run: a close connection request on for a non existing connection returns successfully", context do
+ assert match?(:ok,
+ @command.run(["<#{node()}.2.121.12>", "test"], %{node: @helpers.normalise_node(context[:node], :shortnames)}))
+ end
+
+ test "run: a close_connection request on nonexistent RabbitMQ node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["<rabbit@localhost.1.2.1>", "test"], opts))
+ end
+
+ test "banner", context do
+ s = @command.banner(["<rabbit@bananas.1.2.3>", "some reason"], context[:opts])
+ assert s =~ ~r/Closing connection/
+ assert s =~ ~r/<rabbit@bananas.1.2.3>/
+ end
+
+ defp fetch_connection_pids(node, nodes) do
+ fetch_connection_pids(node, nodes, 10)
+ end
+
+ defp fetch_connection_pids(node, nodes, retries) do
+ stream = RpcStream.receive_list_items(node,
+ :rabbit_networking,
+ :emit_connection_info_all,
+ [nodes, [:pid]],
+ :infinity,
+ [:pid],
+ Kernel.length(nodes))
+ xs = Enum.to_list(stream)
+
+ case {xs, retries} do
+ {xs, 0} ->
+ xs
+ {[], n} when n >= 0 ->
+ Process.sleep(100)
+ fetch_connection_pids(node, nodes, retries - 1)
+ _ ->
+ xs
+ end
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/cluster_status_command_test.exs b/deps/rabbitmq_cli/test/ctl/cluster_status_command_test.exs
new file mode 100644
index 0000000000..e582355e7a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/cluster_status_command_test.exs
@@ -0,0 +1,50 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ClusterStatusCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ClusterStatusCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 12000}}
+ end
+
+ test "validate: argument count validates", context do
+ assert @command.validate([], context[:opts]) == :ok
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: status request to a reachable node returns cluster information", context do
+ n = context[:opts][:node]
+ res = @command.run([], context[:opts])
+
+ assert Enum.member?(res[:nodes][:disc], n)
+ assert res[:partitions] == []
+ assert res[:alarms][n] == []
+ end
+
+ test "run: status request on nonexistent RabbitMQ node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ s = @command.banner([], context[:opts])
+
+ assert s =~ ~r/Cluster status of node/
+ assert s =~ ~r/#{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/decode_command_test.exs b/deps/rabbitmq_cli/test/ctl/decode_command_test.exs
new file mode 100644
index 0000000000..79850d7786
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/decode_command_test.exs
@@ -0,0 +1,95 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule DecodeCommandTest do
+ use ExUnit.Case, async: false
+ @command RabbitMQ.CLI.Ctl.Commands.DecodeCommand
+
+ setup _context do
+ {:ok, opts: %{
+ cipher: :rabbit_pbe.default_cipher,
+ hash: :rabbit_pbe.default_hash,
+ iterations: :rabbit_pbe.default_iterations
+ }}
+ end
+
+ test "validate: providing exactly 2 positional arguments passes", context do
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "validate: providing zero or one positional argument fails", context do
+ assert match?({:validation_failure, {:not_enough_args, _}},
+ @command.validate([], context[:opts]))
+ assert match?({:validation_failure, {:not_enough_args, _}},
+ @command.validate(["value"], context[:opts]))
+ end
+
+ test "validate: providing three or more positional argument fails", context do
+ assert match?({:validation_failure, :too_many_args},
+ @command.validate(["value", "secret", "incorrect"], context[:opts]))
+ end
+
+ test "validate: hash and cipher must be supported", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{cipher: :funny_cipher}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{hash: :funny_hash}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{cipher: :funny_cipher, hash: :funny_hash}))
+ )
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "validate: number of iterations must greater than 0", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: 0}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: -1}))
+ )
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "run: encrypt/decrypt", context do
+ # an Erlang list/bitstring
+ encrypt_decrypt(to_charlist("foobar"), context)
+ # a binary
+ encrypt_decrypt("foobar", context)
+ # a tuple
+ encrypt_decrypt({:password, "secret"}, context)
+ end
+
+ defp encrypt_decrypt(secret, context) do
+ passphrase = "passphrase"
+ cipher = context[:opts][:cipher]
+ hash = context[:opts][:hash]
+ iterations = context[:opts][:iterations]
+ output = {:encrypted, _encrypted} = :rabbit_pbe.encrypt_term(cipher, hash, iterations, passphrase, secret)
+
+ {:encrypted, encrypted} = output
+ # decode plain value
+ assert {:ok, secret} === @command.run([format_as_erlang_term(encrypted), passphrase], context[:opts])
+ # decode {encrypted, ...} tuple form
+ assert {:ok, secret} === @command.run([format_as_erlang_term(output), passphrase], context[:opts])
+
+ # wrong passphrase
+ assert match?({:error, _},
+ @command.run([format_as_erlang_term(encrypted), "wrong/passphrase"], context[:opts]))
+ assert match?({:error, _},
+ @command.run([format_as_erlang_term(output), "wrong passphrase"], context[:opts]))
+ end
+
+ defp format_as_erlang_term(value) do
+ :io_lib.format("~p", [value]) |> :lists.flatten() |> to_string()
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/delete_queue_command_test.exs b/deps/rabbitmq_cli/test/ctl/delete_queue_command_test.exs
new file mode 100644
index 0000000000..b0971b8961
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/delete_queue_command_test.exs
@@ -0,0 +1,119 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule DeleteQueueCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.DeleteQueueCommand
+ @user "guest"
+ @vhost "delete-queue-vhost"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost,
+ timeout: context[:test_timeout],
+ if_empty: false,
+ if_unused: false
+ }}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/", if_empty: false, if_unused: false}}
+ assert @command.merge_defaults([], %{vhost: "non_default", if_empty: true}) ==
+ {[], %{vhost: "non_default", if_empty: true, if_unused: false}}
+ end
+
+ test "validate: providing no queue name fails validation", context do
+ assert match?(
+ {:validation_failure, :not_enough_args},
+ @command.validate([], context[:opts])
+ )
+ end
+
+ test "validate: providing an empty queue name fails validation", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, "queue name cannot be an empty string"}},
+ @command.validate([""], context[:opts])
+ )
+ end
+
+ test "validate: providing a non-blank queue name and -u succeeds", context do
+ assert @command.validate(["a-queue"], %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost,
+ timeout: context[:test_timeout],
+ if_unused: false
+ }) == :ok
+ end
+
+ @tag test_timeout: 30000
+ test "run: request to an existent queue on active node succeeds", context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(context, fn -> delete_vhost(@vhost) end)
+
+ q = "foo"
+ n = 20
+
+ declare_queue(q, @vhost)
+ publish_messages(@vhost, q, n)
+
+ assert @command.run([q], context[:opts]) == {:ok, n}
+ {:error, :not_found} = lookup_queue(q, @vhost)
+ end
+
+ @tag test_timeout: 30000
+ test "run: request to a non-existent queue on active node returns not found", context do
+ assert @command.run(["non-existent"], context[:opts]) == {:error, :not_found}
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return a bad RPC", context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(context, fn -> delete_vhost(@vhost) end)
+
+ q = "foo"
+ declare_queue(q, @vhost)
+ assert @command.run([q], context[:opts]) == {:badrpc, :timeout}
+ end
+
+ test "shows up in help" do
+ s = @command.usage()
+ assert s =~ ~r/delete_queue/
+ end
+
+ test "defaults to vhost /" do
+ assert @command.merge_defaults(["foo"], %{bar: "baz"}) == {["foo"], %{bar: "baz", vhost: "/", if_unused: false, if_empty: false}}
+ end
+
+ test "validate: with extra arguments returns an arg count error" do
+ assert @command.validate(["queue-name", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: with no arguments returns an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: with correct args returns ok" do
+ assert @command.validate(["q"], %{}) == :ok
+ end
+
+ test "banner informs that vhost's queue is deleted" do
+ assert @command.banner(["my-q"], %{vhost: "/foo", if_empty: false, if_unused: false}) == "Deleting queue 'my-q' on vhost '/foo' ..."
+ assert @command.banner(["my-q"], %{vhost: "/foo", if_empty: true, if_unused: false}) == "Deleting queue 'my-q' on vhost '/foo' if queue is empty ..."
+ assert @command.banner(["my-q"], %{vhost: "/foo", if_empty: true, if_unused: true}) == "Deleting queue 'my-q' on vhost '/foo' if queue is empty and if queue is unused ..."
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/delete_user_command_test.exs b/deps/rabbitmq_cli/test/ctl/delete_user_command_test.exs
new file mode 100644
index 0000000000..97f09654a9
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/delete_user_command_test.exs
@@ -0,0 +1,59 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule DeleteUserCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.DeleteUserCommand
+ @user "username"
+ @password "password"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ :ok
+ end
+
+ setup context do
+ add_user(context[:user], @password)
+ on_exit(context, fn -> delete_user(context[:user]) end)
+
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ @tag user: @user
+ test "validate: argument count validates" do
+ assert @command.validate(["one"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag user: @user
+ test "run: A valid username returns ok", context do
+ assert @command.run([context[:user]], context[:opts]) == :ok
+
+ assert list_users() |> Enum.count(fn(record) -> record[:user] == context[:user] end) == 0
+ end
+
+ test "run: An invalid Rabbit node returns a bad rpc message" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["username"], opts))
+ end
+
+ @tag user: @user
+ test "run: An invalid username returns an error", context do
+ assert @command.run(["no_one"], context[:opts]) == {:error, {:no_such_user, "no_one"}}
+ end
+
+ @tag user: @user
+ test "banner", context do
+ s = @command.banner([context[:user]], context[:opts])
+ assert s =~ ~r/Deleting user/
+ assert s =~ ~r/\"#{context[:user]}\"/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/delete_vhost_command_test.exs b/deps/rabbitmq_cli/test/ctl/delete_vhost_command_test.exs
new file mode 100644
index 0000000000..057f0789dc
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/delete_vhost_command_test.exs
@@ -0,0 +1,67 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule DeleteVhostCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.DeleteVhostCommand
+ @vhost "test"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_vhost(context[:vhost])
+ on_exit(context, fn -> delete_vhost(context[:vhost]) end)
+
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: argument count validates" do
+ assert @command.validate(["tst"], %{}) == :ok
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["test", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag vhost: @vhost
+ test "run: A valid name to an active RabbitMQ node is successful", context do
+ assert @command.run([context[:vhost]], context[:opts]) == :ok
+
+ assert list_vhosts() |> Enum.count(fn(record) -> record[:name] == context[:vhost] end) == 0
+ end
+
+ @tag vhost: ""
+ test "run: An empty string to an active RabbitMQ node is successful", context do
+ assert @command.run([context[:vhost]], context[:opts]) == :ok
+
+ assert list_vhosts() |> Enum.count(fn(record) -> record[:name] == context[:vhost] end) == 0
+ end
+
+ test "run: A call to invalid or inactive RabbitMQ node returns a nodedown" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["na"], opts))
+ end
+
+ @tag vhost: @vhost
+ test "run: Deleting the same host twice results in a host not found message", context do
+ @command.run([context[:vhost]], context[:opts])
+ assert @command.run([context[:vhost]], context[:opts]) ==
+ {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag vhost: @vhost
+ test "banner", context do
+ s = @command.banner([context[:vhost]], context[:opts])
+ assert s =~ ~r/Deleting vhost/
+ assert s =~ ~r/\"#{context[:vhost]}\"/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/enable_feature_flag_test.exs b/deps/rabbitmq_cli/test/ctl/enable_feature_flag_test.exs
new file mode 100644
index 0000000000..f8a3e62920
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/enable_feature_flag_test.exs
@@ -0,0 +1,70 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule EnableFeatureFlagCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.EnableFeatureFlagCommand
+ @feature_flag :ff_from_enable_ff_testsuite
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ # Define an arbitrary feature flag for the test.
+ node = get_rabbit_hostname()
+ new_feature_flags = %{
+ @feature_flag =>
+ %{desc: "My feature flag",
+ provided_by: :EnableFeatureFlagCommandTest,
+ stability: :stable}}
+ :ok = :rabbit_misc.rpc_call(
+ node, :rabbit_feature_flags, :initialize_registry, [new_feature_flags])
+
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname()},
+ feature_flag: @feature_flag
+ }
+ end
+
+ test "validate: wrong number of arguments results in arg count errors" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["ff_from_enable_ff_testsuite", "whoops"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: passing an empty string for feature_flag name is an arg error", context do
+ assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([""], context[:opts]))
+ end
+
+ test "run: passing a valid feature_flag name to a running RabbitMQ node succeeds", context do
+ assert @command.run([Atom.to_string(context[:feature_flag])], context[:opts]) == :ok
+ assert list_feature_flags(:enabled) |> Map.has_key?(context[:feature_flag])
+ end
+
+ test "run: attempt to use an unreachable node returns a nodedown" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["na"], opts))
+ end
+
+ test "run: enabling the same feature flag twice is idempotent", context do
+ enable_feature_flag context[:feature_flag]
+ assert @command.run([Atom.to_string(context[:feature_flag])], context[:opts]) == :ok
+ assert list_feature_flags(:enabled) |> Map.has_key?(context[:feature_flag])
+ end
+
+ test "run: enabling all feature flags succeeds", context do
+ enable_feature_flag context[:feature_flag]
+ assert @command.run(["all"], context[:opts]) == :ok
+ assert list_feature_flags(:enabled) |> Map.has_key?(context[:feature_flag])
+ end
+
+ test "banner", context do
+ assert @command.banner([context[:feature_flag]], context[:opts])
+ =~ ~r/Enabling feature flag \"#{context[:feature_flag]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/encode_command_test.exs b/deps/rabbitmq_cli/test/ctl/encode_command_test.exs
new file mode 100644
index 0000000000..550e4b24da
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/encode_command_test.exs
@@ -0,0 +1,92 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule EncodeCommandTest do
+ use ExUnit.Case, async: false
+
+ @command RabbitMQ.CLI.Ctl.Commands.EncodeCommand
+
+ setup _context do
+ {:ok, opts: %{
+ cipher: :rabbit_pbe.default_cipher,
+ hash: :rabbit_pbe.default_hash,
+ iterations: :rabbit_pbe.default_iterations
+ }}
+ end
+
+ test "validate: providing exactly 2 positional arguments passes", context do
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "validate: providing zero or one positional argument fails", context do
+ assert match?({:validation_failure, {:not_enough_args, _}},
+ @command.validate([], context[:opts]))
+ assert match?({:validation_failure, {:not_enough_args, _}},
+ @command.validate(["value"], context[:opts]))
+ end
+
+ test "validate: providing three or more positional argument fails", context do
+ assert match?({:validation_failure, :too_many_args},
+ @command.validate(["value", "secret", "incorrect"], context[:opts]))
+ end
+
+ test "validate: hash and cipher must be supported", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{cipher: :funny_cipher}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{hash: :funny_hash}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{cipher: :funny_cipher, hash: :funny_hash}))
+ )
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "validate: number of iterations must greater than 0", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: 0}))
+ )
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: -1}))
+ )
+ assert :ok == @command.validate(["value", "secret"], context[:opts])
+ end
+
+ test "run: encrypt/decrypt", context do
+ # an Erlang list/bitstring
+ encrypt_decrypt(to_charlist("foobar"), context)
+ # a binary
+ encrypt_decrypt("foobar", context)
+ # a tuple
+ encrypt_decrypt({:password, "secret"}, context)
+ end
+
+ defp encrypt_decrypt(secret, context) do
+ secret_as_erlang_term = format_as_erlang_term(secret)
+ passphrase = "passphrase"
+
+ cipher = context[:opts][:cipher]
+ hash = context[:opts][:hash]
+ iterations = context[:opts][:iterations]
+
+ {:ok, output} = @command.run([secret_as_erlang_term, passphrase], context[:opts])
+ {:encrypted, encrypted} = output
+ # decode plain value
+ assert secret === :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, {:plaintext, secret})
+ # decode {encrypted, ...} tuple form
+ assert secret === :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, {:encrypted, encrypted})
+ end
+
+ defp format_as_erlang_term(value) do
+ :io_lib.format("~p", [value]) |> :lists.flatten() |> to_string()
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/environment_command_test.exs b/deps/rabbitmq_cli/test/ctl/environment_command_test.exs
new file mode 100644
index 0000000000..7f801d54dc
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/environment_command_test.exs
@@ -0,0 +1,45 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule EnvironmentCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.EnvironmentCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: argument count validates" do
+ assert @command.validate([], %{}) == :ok
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag target: get_rabbit_hostname()
+ test "run: environment request on a named, active RMQ node is successful", context do
+ assert @command.run([], context[:opts])[:kernel] != nil
+ assert @command.run([], context[:opts])[:rabbit] != nil
+ end
+
+ test "run: environment request on nonexistent RabbitMQ node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Application environment of node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/eval_command_test.exs b/deps/rabbitmq_cli/test/ctl/eval_command_test.exs
new file mode 100644
index 0000000000..92a2d77667
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/eval_command_test.exs
@@ -0,0 +1,74 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule EvalCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+ import ExUnit.CaptureIO
+
+ @command RabbitMQ.CLI.Ctl.Commands.EvalCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ :ok
+ end
+
+ setup _ do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: providing no arguments succeeds" do
+ # expression is expected to be provided via standard input
+ assert @command.validate([], %{}) == :ok
+ end
+
+ test "validate: empty expression to eval fails validation" do
+ assert @command.validate([""], %{}) == {:validation_failure, "Expression must not be blank"}
+ assert @command.validate(["", "foo"], %{}) == {:validation_failure, "Expression must not be blank"}
+ end
+
+ test "validate: syntax error in expression to eval fails validation" do
+ assert @command.validate(["foo bar"], %{}) == {:validation_failure, "syntax error before: bar"}
+ assert @command.validate(["foo bar", "foo"], %{}) == {:validation_failure, "syntax error before: bar"}
+ end
+
+ test "run: request to a non-existent node returns a badrpc", _context do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["ok."], opts))
+ end
+
+ test "run: evaluates provided Erlang expression", context do
+ assert @command.run(["foo."], context[:opts]) == {:ok, :foo}
+ assert @command.run(["length([1,2,3])."], context[:opts]) == {:ok, 3}
+ assert @command.run(["lists:sum([1,2,3])."], context[:opts]) == {:ok, 6}
+ {:ok, apps} = @command.run(["application:loaded_applications()."], context[:opts])
+ assert is_list(apps)
+ end
+
+ test "run: evaluates provided expression on the target server node", context do
+ {:ok, apps} = @command.run(["application:loaded_applications()."], context[:opts])
+ assert is_list(apps)
+ assert List.keymember?(apps, :rabbit, 0)
+ end
+
+ test "run: returns stdout output", context do
+ assert capture_io(fn ->
+ assert @command.run(["io:format(\"output\")."], context[:opts]) == {:ok, :ok}
+ end) == "output"
+ end
+
+ test "run: passes parameters to the expression as positional/numerical variables", context do
+ assert @command.run(["binary_to_atom(_1, utf8).", "foo"], context[:opts]) == {:ok, :foo}
+ assert @command.run(["{_1, _2}.", "foo", "bar"], context[:opts]) == {:ok, {"foo", "bar"}}
+ end
+
+ test "run: passes globally recognised options as named variables", context do
+ assert @command.run(["{_vhost, _node}."], Map.put(context[:opts], :vhost, "a-node")) ==
+ {:ok, {"a-node", context[:opts][:node]}}
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/eval_file_command_test.exs b/deps/rabbitmq_cli/test/ctl/eval_file_command_test.exs
new file mode 100644
index 0000000000..74cb272f98
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/eval_file_command_test.exs
@@ -0,0 +1,72 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule EvalFileCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.EvalFileCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ :ok
+ end
+
+ setup _ do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: providing no arguments fails validation" do
+ # expression is expected to be provided via standard input
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: empty file path fails validation" do
+ assert @command.validate([""], %{}) == {:validation_failure, "File path must not be blank"}
+ end
+
+ test "validate: path to a non-existent file fails validation" do
+ path = "/tmp/rabbitmq/cli-tests/12937293782368263726.lolz.escript"
+ assert @command.validate([path], %{}) == {:validation_failure, "File #{path} does not exist"}
+ end
+
+ test "run: request to a non-existent node returns a badrpc", _context do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([valid_file_path()], opts))
+ end
+
+ test "run: evaluates expressions in the file on the target server node", context do
+ {:ok, apps} = @command.run([loaded_applications_file_path()], context[:opts])
+ assert is_list(apps)
+ assert List.keymember?(apps, :rabbit, 0)
+ end
+
+ test "run: returns evaluation result", context do
+ assert {:ok, 2} == @command.run([valid_file_path()], context[:opts])
+ end
+
+ test "run: reports invalid syntax errors", context do
+ assert match?({:error, _}, @command.run([invalid_file_path()], context[:opts]))
+ end
+
+ #
+ # Implementation
+ #
+
+ defp valid_file_path() do
+ Path.join([File.cwd!(), "test", "fixtures", "files", "valid_erl_expression.escript"])
+ end
+
+ defp invalid_file_path() do
+ Path.join([File.cwd!(), "test", "fixtures", "files", "invalid_erl_expression.escript"])
+ end
+
+ defp loaded_applications_file_path() do
+ Path.join([File.cwd!(), "test", "fixtures", "files", "loaded_applications.escript"])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/exec_command_test.exs b/deps/rabbitmq_cli/test/ctl/exec_command_test.exs
new file mode 100644
index 0000000000..bb839f5434
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/exec_command_test.exs
@@ -0,0 +1,47 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ExecCommandTest do
+ use ExUnit.Case, async: false
+
+ @command RabbitMQ.CLI.Ctl.Commands.ExecCommand
+
+ setup _ do
+ {:ok, opts: %{}}
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: there should be only one argument" do
+ assert @command.validate(["foo", "bar"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["", "bar"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: empty expression to exec fails validation" do
+ assert @command.validate([""], %{}) == {:validation_failure, "Expression must not be blank"}
+ end
+
+ test "validate: success" do
+ :ok = @command.validate([":ok"], %{})
+ end
+
+ test "run: executes elixir code" do
+ {:ok, :ok} = @command.run([":ok"], %{})
+ node = Node.self()
+ {:ok, ^node} = @command.run(["Node.self()"], %{})
+ {:ok, 3} = @command.run(["1 + 2"], %{})
+ end
+
+ test "run: binds options variable" do
+ opts = %{my: :custom, option: 123}
+ {:ok, ^opts} = @command.run(["options"], opts)
+ {:ok, 123} = @command.run(["options[:option]"], opts)
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/export_definitions_command_test.exs b/deps/rabbitmq_cli/test/ctl/export_definitions_command_test.exs
new file mode 100644
index 0000000000..3506b1ea80
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/export_definitions_command_test.exs
@@ -0,0 +1,138 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ExportDefinitionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ExportDefinitionsCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || 30000,
+ format: context[:format] || "json"
+ }}
+ end
+
+ test "merge_defaults: defaults to JSON for format" do
+ assert @command.merge_defaults([valid_file_path()], %{}) ==
+ {[valid_file_path()], %{format: "json"}}
+ end
+
+ test "merge_defaults: defaults to --silent if target is stdout" do
+ assert @command.merge_defaults(["-"], %{}) == {["-"], %{format: "json", silent: true}}
+ end
+
+ test "merge_defaults: format is case insensitive" do
+ assert @command.merge_defaults([valid_file_path()], %{format: "JSON"}) ==
+ {[valid_file_path()], %{format: "json"}}
+ assert @command.merge_defaults([valid_file_path()], %{format: "Erlang"}) ==
+ {[valid_file_path()], %{format: "erlang"}}
+ end
+
+ test "merge_defaults: format can be overridden" do
+ assert @command.merge_defaults([valid_file_path()], %{format: "erlang"}) ==
+ {[valid_file_path()], %{format: "erlang"}}
+ end
+
+ test "validate: accepts a file path argument", context do
+ assert @command.validate([valid_file_path()], context[:opts]) == :ok
+ end
+
+ test "validate: accepts a dash for stdout", context do
+ assert @command.validate(["-"], context[:opts]) == :ok
+ end
+
+ test "validate: unsupported format fails validation", context do
+ assert match?({:validation_failure, {:bad_argument, _}},
+ @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "yolo"})))
+ end
+
+ test "validate: no positional arguments fails validation", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: more than one positional argument fails validation", context do
+ assert @command.validate([valid_file_path(), "extra-arg"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: supports JSON and Erlang formats", context do
+ assert @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "json"})) == :ok
+ assert @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "erlang"})) == :ok
+ end
+
+ @tag test_timeout: 3000
+ test "run: targeting an unreachable node throws a badrpc", context do
+ result = @command.run([valid_file_path()],
+ %{node: :jake@thedog,
+ timeout: context[:test_timeout],
+ format: "json"})
+ assert match?({:badrpc, _}, result)
+ end
+
+ @tag format: "json"
+ test "run: returns a list of definitions when target is stdout and format is JSON", context do
+ {:ok, map} = @command.run(["-"], context[:opts])
+ assert Map.has_key?(map, :rabbitmq_version)
+ end
+
+ @tag format: "erlang"
+ test "run: returns a list of definitions when target is stdout and format is Erlang Terms", context do
+ {:ok, map} = @command.run(["-"], context[:opts])
+ assert Map.has_key?(map, :rabbitmq_version)
+ end
+
+ @tag format: "json"
+ test "run: writes to a file and returns nil when target is a file and format is JSON", context do
+ File.rm(valid_file_path())
+ {:ok, nil} = @command.run([valid_file_path()], context[:opts])
+
+ {:ok, bin} = File.read(valid_file_path())
+ {:ok, map} = JSON.decode(bin)
+ assert Map.has_key?(map, "rabbitmq_version")
+ end
+
+ @tag format: "json"
+ test "run: correctly formats runtime parameter values", context do
+ File.rm(valid_file_path())
+ imported_file_path = Path.join([File.cwd!(), "test", "fixtures", "files", "definitions.json"])
+ # prepopulate some runtime parameters
+ RabbitMQ.CLI.Ctl.Commands.ImportDefinitionsCommand.run([imported_file_path], context[:opts])
+
+ {:ok, nil} = @command.run([valid_file_path()], context[:opts])
+
+ # clean up the state we've modified
+ clear_parameter("/", "federation-upstream", "up-1")
+
+ {:ok, bin} = File.read(valid_file_path())
+ {:ok, map} = JSON.decode(bin)
+ assert Map.has_key?(map, "rabbitmq_version")
+ params = map["parameters"]
+ assert is_map(hd(params)["value"])
+ end
+
+ @tag format: "erlang"
+ test "run: writes to a file and returns nil when target is a file and format is Erlang Terms", context do
+ File.rm(valid_file_path())
+ {:ok, nil} = @command.run([valid_file_path()], context[:opts])
+
+ {:ok, bin} = File.read(valid_file_path())
+ map = :erlang.binary_to_term(bin)
+ assert Map.has_key?(map, :rabbitmq_version)
+ end
+
+ defp valid_file_path(), do: "#{System.tmp_dir()}/definitions"
+end
diff --git a/deps/rabbitmq_cli/test/ctl/force_boot_command_test.exs b/deps/rabbitmq_cli/test/ctl/force_boot_command_test.exs
new file mode 100644
index 0000000000..a33d7b2e89
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/force_boot_command_test.exs
@@ -0,0 +1,63 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ForceBootCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ForceBootCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup _ do
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: 1000
+ }
+ }
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: the rabbit app running on target node fails validation", context do
+ assert @command.validate_execution_environment([], context[:opts]) ==
+ {:validation_failure, :rabbit_app_is_running}
+ end
+
+ test "run: sets a force boot marker file on target node", context do
+ stop_rabbitmq_app()
+ on_exit(fn -> start_rabbitmq_app() end)
+ assert @command.run([], context[:opts]) == :ok
+ mnesia_dir = :rpc.call(get_rabbit_hostname(), :rabbit_mnesia, :dir, [])
+
+ path = Path.join(mnesia_dir, "force_load")
+ assert File.exists?(path)
+ File.rm(path)
+ end
+
+ test "run: if RABBITMQ_MNESIA_DIR is defined, creates a force boot marker file" do
+ node = :unknown@localhost
+ temp_dir = "#{Mix.Project.config()[:elixirc_paths]}/tmp"
+ File.mkdir_p!(temp_dir)
+ on_exit(fn -> File.rm_rf!(temp_dir) end)
+ System.put_env("RABBITMQ_MNESIA_DIR", temp_dir)
+
+ assert @command.run([], %{node: node}) == :ok
+ assert File.exists?(Path.join(temp_dir, "force_load"))
+
+ System.delete_env("RABBITMQ_MNESIA_DIR")
+ File.rm_rf(temp_dir)
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/force_gc_command_test.exs b/deps/rabbitmq_cli/test/ctl/force_gc_command_test.exs
new file mode 100644
index 0000000000..b9583931d3
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/force_gc_command_test.exs
@@ -0,0 +1,46 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ForceGcCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ForceGcCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ reset_vm_memory_high_watermark()
+
+ on_exit([], fn ->
+ reset_vm_memory_high_watermark()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 200}}
+ end
+
+
+ test "merge_defaults: merge not defaults" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: with extra arguments returns an error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ assert match?({:badrpc, _}, @command.run([], %{node: :jake@thedog, timeout: 200}))
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([], context[:opts]) == :ok
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/force_reset_command_test.exs b/deps/rabbitmq_cli/test/ctl/force_reset_command_test.exs
new file mode 100644
index 0000000000..5b695302f4
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/force_reset_command_test.exs
@@ -0,0 +1,68 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ForceResetCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ForceResetCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: force reset request to an active node with a stopped rabbit app succeeds", context do
+ add_vhost "some_vhost"
+ # ensure the vhost really does exist
+ assert vhost_exists? "some_vhost"
+ stop_rabbitmq_app()
+ assert :ok == @command.run([], context[:opts])
+ start_rabbitmq_app()
+ # check that the created vhost no longer exists
+ assert match?([_], list_vhosts())
+ end
+
+ test "run: reset request to an active node with a running rabbit app fails", context do
+ add_vhost "some_vhost"
+ assert vhost_exists? "some_vhost"
+ assert match?({:error, :mnesia_unexpectedly_running}, @command.run([], context[:opts]))
+ assert vhost_exists? "some_vhost"
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Forcefully resetting node #{get_rabbit_hostname()}/
+ end
+
+ test "output mnesia is running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code,
+ "Mnesia is still running on node " <> _},
+ @command.output({:error, :mnesia_unexpectedly_running}, context[:opts]))
+
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/forget_cluster_node_command_test.exs b/deps/rabbitmq_cli/test/ctl/forget_cluster_node_command_test.exs
new file mode 100644
index 0000000000..0f09e4fee8
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/forget_cluster_node_command_test.exs
@@ -0,0 +1,132 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ForgetClusterNodeCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ForgetClusterNodeCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ node = get_rabbit_hostname()
+
+ start_rabbitmq_app()
+
+ {:ok, plugins_dir} =
+ :rabbit_misc.rpc_call(node, :application, :get_env, [:rabbit, :plugins_dir])
+
+ rabbitmq_home = :rabbit_misc.rpc_call(node, :code, :lib_dir, [:rabbit])
+ mnesia_dir = :rabbit_misc.rpc_call(node, :rabbit_mnesia, :dir, [])
+
+ feature_flags_file =
+ :rabbit_misc.rpc_call(node, :rabbit_feature_flags, :enabled_feature_flags_list_file, [])
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ {:ok,
+ opts: %{
+ rabbitmq_home: rabbitmq_home,
+ plugins_dir: plugins_dir,
+ mnesia_dir: mnesia_dir,
+ feature_flags_file: feature_flags_file,
+ offline: false
+ }}
+ end
+
+ setup context do
+ {:ok, opts: Map.merge(context[:opts], %{node: get_rabbit_hostname()})}
+ end
+
+ test "validate: specifying no target node is reported as an error", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: specifying multiple target nodes is reported as an error", context do
+ assert @command.validate(["a", "b", "c"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate_execution_environment: offline request to a running node fails", context do
+ assert match?(
+ {:validation_failure, :node_running},
+ @command.validate_execution_environment(
+ ["other_node@localhost"],
+ Map.merge(context[:opts], %{offline: true})
+ )
+ )
+ end
+
+ test "validate_execution_environment: offline forget without mnesia dir fails", context do
+ offline_opts =
+ Map.merge(
+ context[:opts],
+ %{offline: true, node: :non_exist@localhost}
+ )
+
+ opts_without_mnesia = Map.delete(offline_opts, :mnesia_dir)
+ Application.put_env(:mnesia, :dir, "/tmp")
+ on_exit(fn -> Application.delete_env(:mnesia, :dir) end)
+
+ assert match?(
+ :ok,
+ @command.validate_execution_environment(
+ ["other_node@localhost"],
+ opts_without_mnesia
+ )
+ )
+
+ Application.delete_env(:mnesia, :dir)
+ System.put_env("RABBITMQ_MNESIA_DIR", "/tmp")
+ on_exit(fn -> System.delete_env("RABBITMQ_MNESIA_DIR") end)
+
+ assert match?(
+ :ok,
+ @command.validate_execution_environment(
+ ["other_node@localhost"],
+ opts_without_mnesia
+ )
+ )
+
+ System.delete_env("RABBITMQ_MNESIA_DIR")
+
+ assert match?(
+ :ok,
+ @command.validate_execution_environment(["other_node@localhost"], offline_opts)
+ )
+ end
+
+ test "validate_execution_environment: online mode does not fail is mnesia is not loaded",
+ context do
+ opts_without_mnesia = Map.delete(context[:opts], :mnesia_dir)
+
+ assert match?(
+ :ok,
+ @command.validate_execution_environment(
+ ["other_node@localhost"],
+ opts_without_mnesia
+ )
+ )
+ end
+
+ test "run: online request to a non-existent node returns a badrpc", context do
+ assert match?(
+ {:badrpc, :nodedown},
+ @command.run(
+ [context[:opts][:node]],
+ Map.merge(context[:opts], %{node: :non_exist@localhost})
+ )
+ )
+ end
+
+ test "banner", context do
+ assert @command.banner(["a"], context[:opts]) =~
+ ~r/Removing node a from the cluster/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/help_command_test.exs b/deps/rabbitmq_cli/test/ctl/help_command_test.exs
new file mode 100644
index 0000000000..d30a4d98c7
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/help_command_test.exs
@@ -0,0 +1,76 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule HelpCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ alias RabbitMQ.CLI.Core.{CommandModules}
+
+ @command RabbitMQ.CLI.Ctl.Commands.HelpCommand
+
+ setup_all do
+ set_scope(:all)
+ :ok
+ end
+
+ test "validate: providing no position arguments passes validation" do
+ assert @command.validate([], %{}) == :ok
+ end
+
+ test "validate: providing one position argument passes validation" do
+ assert @command.validate(["status"], %{}) == :ok
+ end
+
+ test "validate: providing two or more position arguments fails validation" do
+ assert @command.validate(["extra1", "extra2"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: prints basic usage info" do
+ {:ok, lines} = @command.run([], %{})
+ output = Enum.join(lines, "\n")
+ assert output =~ ~r/[-n <node>] [-t <timeout>]/
+ assert output =~ ~r/commands/i
+ end
+
+ test "run: ctl command usage info is printed if command is specified" do
+ ctl_commands = CommandModules.module_map
+ |> Enum.filter(fn({_name, command_mod}) ->
+ to_string(command_mod) =~ ~r/^RabbitMQ\.CLI\.Ctl\.Commands/
+ end)
+ |> Enum.map(fn({name, _}) -> name end)
+
+ IO.inspect(ctl_commands)
+ Enum.each(
+ ctl_commands,
+ fn(command) ->
+ assert @command.run([command], %{}) =~ ~r/#{command}/
+ end)
+ end
+
+ test "run prints command info" do
+ ctl_commands = CommandModules.module_map
+ |> Enum.filter(fn({_name, command_mod}) ->
+ to_string(command_mod) =~ ~r/^RabbitMQ\.CLI\.Ctl\.Commands/
+ end)
+ |> Enum.map(fn({name, _}) -> name end)
+
+ Enum.each(
+ ctl_commands,
+ fn(command) ->
+ {:ok, lines} = @command.run([], %{})
+ output = Enum.join(lines, "\n")
+ assert output =~ ~r/\n\s+#{command}.*\n/
+ end)
+ end
+
+ test "run: exits with the code of OK" do
+ assert @command.output({:ok, "Help string"}, %{}) ==
+ {:ok, "Help string"}
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/import_definitions_command_test.exs b/deps/rabbitmq_cli/test/ctl/import_definitions_command_test.exs
new file mode 100644
index 0000000000..fb7f975ec5
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/import_definitions_command_test.exs
@@ -0,0 +1,88 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ImportDefinitionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ImportDefinitionsCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || 30000,
+ format: context[:format] || "json"
+ }}
+ end
+
+ test "merge_defaults: defaults to JSON for format" do
+ assert @command.merge_defaults([valid_file_path()], %{}) ==
+ {[valid_file_path()], %{format: "json"}}
+ end
+
+ test "merge_defaults: defaults to --silent if target is stdout" do
+ assert @command.merge_defaults(["-"], %{}) == {["-"], %{format: "json", silent: true}}
+ end
+
+ test "merge_defaults: format is case insensitive" do
+ assert @command.merge_defaults([valid_file_path()], %{format: "JSON"}) ==
+ {[valid_file_path()], %{format: "json"}}
+ assert @command.merge_defaults([valid_file_path()], %{format: "Erlang"}) ==
+ {[valid_file_path()], %{format: "erlang"}}
+ end
+
+ test "merge_defaults: format can be overridden" do
+ assert @command.merge_defaults([valid_file_path()], %{format: "erlang"}) ==
+ {[valid_file_path()], %{format: "erlang"}}
+ end
+
+ test "validate: accepts a file path argument", context do
+ assert @command.validate([valid_file_path()], context[:opts]) == :ok
+ end
+
+ test "validate: unsupported format fails validation", context do
+ assert match?({:validation_failure, {:bad_argument, _}},
+ @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "yolo"})))
+ end
+
+ test "validate: more than one positional argument fails validation", context do
+ assert @command.validate([valid_file_path(), "extra-arg"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: supports JSON and Erlang formats", context do
+ assert @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "json"})) == :ok
+ assert @command.validate([valid_file_path()], Map.merge(context[:opts], %{format: "erlang"})) == :ok
+ end
+
+ @tag test_timeout: 3000
+ test "run: targeting an unreachable node throws a badrpc", context do
+ result = @command.run([valid_file_path()],
+ %{node: :jake@thedog,
+ timeout: context[:test_timeout],
+ format: "json"})
+ assert match?({:badrpc, _}, result)
+ end
+
+ @tag format: "json"
+ test "run: imports definitions from a file", context do
+ assert :ok == @command.run([valid_file_path()], context[:opts])
+
+ # clean up the state we've modified
+ clear_parameter("/", "federation-upstream", "up-1")
+ end
+
+ defp valid_file_path() do
+ Path.join([File.cwd!(), "test", "fixtures", "files", "definitions.json"])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/join_cluster_command_test.exs b/deps/rabbitmq_cli/test/ctl/join_cluster_command_test.exs
new file mode 100644
index 0000000000..2a9c7ec861
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/join_cluster_command_test.exs
@@ -0,0 +1,104 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule JoinClusterCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.JoinClusterCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ disc: true,
+ ram: false,
+ }}
+ end
+
+ test "validate: specifying both --disc and --ram is reported as invalid", context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate(["a"], Map.merge(context[:opts], %{disc: true, ram: true}))
+ )
+ end
+ test "validate: specifying no target node is reported as an error", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+ test "validate: specifying multiple target nodes is reported as an error", context do
+ assert @command.validate(["a", "b", "c"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ # TODO
+ #test "run: successful join as a disc node", context do
+ #end
+
+ # TODO
+ #test "run: successful join as a RAM node", context do
+ #end
+
+ test "run: joining self is invalid", context do
+ stop_rabbitmq_app()
+ assert match?(
+ {:error, :cannot_cluster_node_with_itself},
+ @command.run([context[:opts][:node]], context[:opts]))
+ start_rabbitmq_app()
+ end
+
+ # TODO
+ test "run: request to an active node fails", context do
+ assert match?(
+ {:error, :mnesia_unexpectedly_running},
+ @command.run([context[:opts][:node]], context[:opts]))
+ end
+
+ test "run: request to a non-existent node returns a badrpc", context do
+ opts = %{
+ node: :jake@thedog,
+ disc: true,
+ ram: false,
+ timeout: 200
+ }
+ assert match?(
+ {:badrpc, _},
+ @command.run([context[:opts][:node]], opts))
+ end
+
+ test "run: joining a non-existent node returns a badrpc", context do
+ stop_rabbitmq_app()
+ assert match?(
+ {:badrpc_multi, _, [_]},
+ @command.run([:jake@thedog], context[:opts]))
+ start_rabbitmq_app()
+ end
+
+ test "banner", context do
+ assert @command.banner(["a"], context[:opts]) =~
+ ~r/Clustering node #{get_rabbit_hostname()} with a/
+ end
+
+ test "output mnesia is running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code,
+ "Mnesia is still running on node " <> _},
+ @command.output({:error, :mnesia_unexpectedly_running}, context[:opts]))
+
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_bindings_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_bindings_command_test.exs
new file mode 100644
index 0000000000..dae2377322
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_bindings_command_test.exs
@@ -0,0 +1,85 @@
+defmodule ListBindingsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListBindingsCommand
+ @vhost "test1"
+ @user "guest"
+ @default_timeout :infinity
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout,
+ vhost: @vhost
+ }
+ }
+ end
+
+ test "merge_defaults: adds all keys if none specificed", context do
+ default_keys = ~w(source_name source_kind destination_name destination_kind routing_key arguments)
+ declare_queue("test_queue", @vhost)
+ :timer.sleep(100)
+
+ {keys, _} = @command.merge_defaults([], context[:opts])
+ assert default_keys == keys
+ end
+
+ test "merge_defaults: includes table headers by default", _context do
+ {_, opts} = @command.merge_defaults([], %{})
+ assert opts[:table_headers]
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: returns multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "source_name"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["source_name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["source_kind", "oink", "source_name"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["source_name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0}}]
+ end
+
+ test "run: no bindings for no queues", context do
+ [] = run_command_to_list(@command, [["source_name"], context[:opts]])
+ end
+
+ test "run: can filter info keys", context do
+ wanted_keys = ~w(source_name destination_name routing_key)
+ declare_queue("test_queue", @vhost)
+ assert run_command_to_list(@command, [wanted_keys, context[:opts]]) ==
+ [[source_name: "", destination_name: "test_queue", routing_key: "test_queue"]]
+ end
+
+ test "banner" do
+ assert String.starts_with?(@command.banner([], %{vhost: "some_vhost"}), "Listing bindings")
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_channels_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_channels_command_test.exs
new file mode 100644
index 0000000000..6ccf602211
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_channels_command_test.exs
@@ -0,0 +1,118 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ListChannelsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListChannelsCommand
+ @default_timeout :infinity
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ close_all_connections(get_rabbit_hostname())
+
+ on_exit([], fn ->
+ close_all_connections(get_rabbit_hostname())
+ end)
+
+ :ok
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout
+ }
+ }
+ end
+
+ test "merge_defaults: default channel info keys are pid, user, consumer_count, and messages_unacknowledged", context do
+ assert match?({~w(pid user consumer_count messages_unacknowledged), _}, @command.merge_defaults([], context[:opts]))
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: returns multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: returns bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "pid"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["user", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["user", "oink", "pid"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: zero timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["user"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0}}]
+ end
+
+ test "run: multiple channels on multiple connections", context do
+ node_name = get_rabbit_hostname()
+ close_all_connections(node_name)
+ existent_channels = :rabbit_misc.rpc_call(node_name,:rabbit_channel, :list, [])
+ with_channel("/", fn(_channel1) ->
+ with_channel("/", fn(_channel2) ->
+ all_channels = run_command_to_list(@command, [["pid", "user", "connection"], context[:opts]])
+ channels = Enum.filter(all_channels,
+ fn(ch) ->
+ not Enum.member?(existent_channels, ch[:pid])
+ end)
+ chan1 = Enum.at(channels, 0)
+ chan2 = Enum.at(channels, 1)
+ assert Keyword.keys(chan1) == ~w(pid user connection)a
+ assert Keyword.keys(chan2) == ~w(pid user connection)a
+ assert "guest" == chan1[:user]
+ assert "guest" == chan2[:user]
+ assert chan1[:pid] !== chan2[:pid]
+ end)
+ end)
+ end
+
+ test "run: multiple channels on single connection", context do
+ node_name = get_rabbit_hostname()
+ close_all_connections(get_rabbit_hostname())
+ with_connection("/", fn(conn) ->
+ existent_channels = :rabbit_misc.rpc_call(node_name,:rabbit_channel, :list, [])
+ {:ok, _} = AMQP.Channel.open(conn)
+ {:ok, _} = AMQP.Channel.open(conn)
+ all_channels = run_command_to_list(@command, [["pid", "user", "connection"], context[:opts]])
+ channels = Enum.filter(all_channels,
+ fn(ch) ->
+ not Enum.member?(existent_channels, ch[:pid])
+ end)
+
+ chan1 = Enum.at(channels, 0)
+ chan2 = Enum.at(channels, 1)
+ assert Keyword.keys(chan1) == ~w(pid user connection)a
+ assert Keyword.keys(chan2) == ~w(pid user connection)a
+ assert "guest" == chan1[:user]
+ assert "guest" == chan2[:user]
+ assert chan1[:pid] !== chan2[:pid]
+ end)
+ end
+
+ test "run: info keys order is preserved", context do
+ close_all_connections(get_rabbit_hostname())
+ with_channel("/", fn(_channel) ->
+ channels = run_command_to_list(@command, [~w(connection vhost name pid number user), context[:opts]])
+ chan = Enum.at(channels, 0)
+ assert Keyword.keys(chan) == ~w(connection vhost name pid number user)a
+ end)
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_ciphers_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_ciphers_command_test.exs
new file mode 100644
index 0000000000..6f600ba5d8
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_ciphers_command_test.exs
@@ -0,0 +1,29 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ListCiphersCommandTest do
+ use ExUnit.Case
+ @command RabbitMQ.CLI.Ctl.Commands.ListCiphersCommand
+
+ test "merge_defaults: nothing to do" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: treats positional arguments as a failure" do
+ assert @command.validate(["extra-arg"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: treats empty positional arguments and default switches as a success" do
+ assert @command.validate([], %{}) == :ok
+ end
+
+ test "run: lists ciphers", _context do
+ assert match?(
+ {:ok, _},
+ @command.run([], %{})
+ )
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_connections_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_connections_command_test.exs
new file mode 100644
index 0000000000..9cfcb8787f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_connections_command_test.exs
@@ -0,0 +1,90 @@
+defmodule ListConnectionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListConnectionsCommand
+ @user "guest"
+ @default_timeout 15000
+ @default_options %{table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ close_all_connections(get_rabbit_hostname())
+
+ on_exit([], fn ->
+ close_all_connections(get_rabbit_hostname())
+ end)
+
+ :ok
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout
+ }
+ }
+ end
+
+ test "merge_defaults: user, peer_host, peer_port and state by default" do
+ assert @command.merge_defaults([], %{}) == {~w(user peer_host peer_port state), @default_options}
+ end
+
+ test "merge_defaults: includes table headers by default", _context do
+ {_, opts} = @command.merge_defaults([], %{})
+ assert opts[:table_headers]
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "peer_host"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["user", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["user", "oink", "peer_host"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0}}]
+ end
+
+ test "run: filter single key", context do
+ vhost = "/"
+ with_connection(vhost, fn(_conn) ->
+ conns = run_command_to_list(@command, [["name"], context[:opts]])
+ assert (Enum.map(conns, &Keyword.keys/1) |> Enum.uniq) == [[:name]]
+ assert Enum.any?(conns, fn(conn) -> conn[:name] != nil end)
+ end)
+ end
+
+ test "run: show connection vhost", context do
+ vhost = "custom_vhost"
+ add_vhost vhost
+ set_permissions @user, vhost, [".*", ".*", ".*"]
+ on_exit(fn ->
+ delete_vhost vhost
+ end)
+ with_connection(vhost, fn(_conn) ->
+ conns = run_command_to_list(@command, [["vhost"], context[:opts]])
+ assert (Enum.map(conns, &Keyword.keys/1) |> Enum.uniq) == [[:vhost]]
+ assert Enum.any?(conns, fn(conn) -> conn[:vhost] == vhost end)
+ end)
+ end
+
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_consumers_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_consumers_command_test.exs
new file mode 100644
index 0000000000..d49313162a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_consumers_command_test.exs
@@ -0,0 +1,213 @@
+defmodule ListConsumersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListConsumersCommand
+
+ @vhost "test1"
+ @user "guest"
+ @default_timeout :infinity
+ @info_keys ~w(queue_name channel_pid consumer_tag ack_required prefetch_count active arguments)
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout,
+ vhost: @vhost
+ }
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {@info_keys, @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {@info_keys, %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: returns multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "queue_name"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["queue_name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["channel_pid", "oink", "queue_name"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: zero timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["queue_name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0}}]
+ end
+
+ test "run: no consumers for no open connections", context do
+ close_all_connections(get_rabbit_hostname())
+ [] = run_command_to_list(@command, [["queue_name"], context[:opts]])
+ end
+
+ test "run: defaults test", context do
+ queue_name = "test_queue1"
+ consumer_tag = "i_am_consumer"
+ info_keys_s = ~w(queue_name channel_pid consumer_tag ack_required prefetch_count arguments)
+ info_keys_a = Enum.map(info_keys_s, &String.to_atom/1)
+ declare_queue(queue_name, @vhost)
+ with_channel(@vhost, fn(channel) ->
+ {:ok, _} = AMQP.Basic.consume(channel, queue_name, nil, [consumer_tag: consumer_tag])
+ :timer.sleep(100)
+ [[consumer]] = run_command_to_list(@command, [info_keys_s, context[:opts]])
+ assert info_keys_a == Keyword.keys(consumer)
+ assert consumer[:consumer_tag] == consumer_tag
+ assert consumer[:queue_name] == queue_name
+ assert Keyword.delete(consumer, :channel_pid) ==
+ [queue_name: queue_name, consumer_tag: consumer_tag,
+ ack_required: true, prefetch_count: 0, arguments: []]
+
+ end)
+ end
+
+ test "run: consumers are grouped by queues (multiple consumer per queue)", context do
+ queue_name1 = "test_queue1"
+ queue_name2 = "test_queue2"
+ declare_queue("test_queue1", @vhost)
+ declare_queue("test_queue2", @vhost)
+ with_channel(@vhost, fn(channel) ->
+ {:ok, tag1} = AMQP.Basic.consume(channel, queue_name1)
+ {:ok, tag2} = AMQP.Basic.consume(channel, queue_name2)
+ {:ok, tag3} = AMQP.Basic.consume(channel, queue_name2)
+ :timer.sleep(100)
+ try do
+ consumers = run_command_to_list(@command, [["queue_name", "consumer_tag"], context[:opts]])
+ {[[consumer1]], [consumers2]} = Enum.split_with(consumers, fn([_]) -> true; ([_,_]) -> false end)
+ assert [queue_name: queue_name1, consumer_tag: tag1] == consumer1
+ assert Keyword.equal?([{tag2, queue_name2}, {tag3, queue_name2}],
+ for([queue_name: q, consumer_tag: t] <- consumers2, do: {t, q}))
+ after
+ AMQP.Basic.cancel(channel, tag1)
+ AMQP.Basic.cancel(channel, tag2)
+ AMQP.Basic.cancel(channel, tag3)
+ end
+ end)
+ end
+
+ test "run: active and activity status fields are set properly when requested", context do
+ queue_types = ["classic", "quorum"]
+ Enum.each queue_types, fn queue_type ->
+ queue_name = "active-activity-status-fields-" <> queue_type
+ declare_queue(queue_name, @vhost, true, false, [{"x-queue-type", :longstr, queue_type}])
+ :timer.sleep(200)
+ with_channel(@vhost, fn(channel) ->
+ {:ok, tag1} = AMQP.Basic.consume(channel, queue_name)
+ {:ok, tag2} = AMQP.Basic.consume(channel, queue_name)
+ {:ok, tag3} = AMQP.Basic.consume(channel, queue_name)
+ :timer.sleep(100)
+ try do
+ consumers = List.first(run_command_to_list(@command, [["queue_name", "consumer_tag", "active", "activity_status"], context[:opts]]))
+ assert Keyword.equal?([{tag1, queue_name, true, :up},
+ {tag2, queue_name, true, :up}, {tag3, queue_name, true, :up}],
+ for([queue_name: q, consumer_tag: t, active: a, activity_status: as] <- consumers, do: {t, q, a, as}))
+ after
+ AMQP.Basic.cancel(channel, tag1)
+ AMQP.Basic.cancel(channel, tag2)
+ AMQP.Basic.cancel(channel, tag3)
+ :timer.sleep(100)
+ delete_queue(queue_name, @vhost)
+ end
+ end)
+ end
+ end
+
+ test "run: active and activity status fields are set properly when requested and single active consumer is enabled", context do
+ queue_types = ["classic", "quorum"]
+ Enum.each queue_types, fn queue_type ->
+ queue_name = "single-active-consumer-" <> queue_type
+ declare_queue(queue_name, @vhost, true, false,
+ [{"x-single-active-consumer", :bool, true}, {"x-queue-type", :longstr, queue_type}])
+ :timer.sleep(200)
+ with_channel(@vhost, fn(channel) ->
+ {:ok, tag1} = AMQP.Basic.consume(channel, queue_name)
+ {:ok, tag2} = AMQP.Basic.consume(channel, queue_name)
+ {:ok, tag3} = AMQP.Basic.consume(channel, queue_name)
+ :timer.sleep(100)
+ try do
+ consumers = List.first(run_command_to_list(@command, [["queue_name", "consumer_tag", "active", "activity_status"], context[:opts]]))
+ assert Keyword.equal?([{tag1, queue_name, true, :single_active},
+ {tag2, queue_name, false, :waiting}, {tag3, queue_name, false, :waiting}],
+ for([queue_name: q, consumer_tag: t, active: a, activity_status: as] <- consumers, do: {t, q, a, as}))
+ AMQP.Basic.cancel(channel, tag1)
+ :timer.sleep(100)
+ consumers = List.first(run_command_to_list(@command, [["queue_name", "consumer_tag", "active", "activity_status"], context[:opts]]))
+ assert Keyword.equal?([{tag2, queue_name, true, :single_active}, {tag3, queue_name, false, :waiting}],
+ for([queue_name: q, consumer_tag: t, active: a, activity_status: as] <- consumers, do: {t, q, a, as}))
+ after
+ AMQP.Basic.cancel(channel, tag2)
+ AMQP.Basic.cancel(channel, tag3)
+ :timer.sleep(100)
+ delete_queue(queue_name, @vhost)
+ end
+ end)
+ end
+ end
+
+ test "fill_consumer_active_fields: add missing fields if necessary" do
+ consumer38 = [
+ queue_name: {:resource, "/", :queue, "queue1"},
+ channel_pid: "",
+ consumer_tag: "ctag1",
+ ack_required: false,
+ prefetch_count: 0,
+ active: true,
+ activity_status: :up,
+ arguments: []
+ ]
+ assert @command.fill_consumer_active_fields({[
+ consumer38
+ ], {1, :continue}}) == {[consumer38], {1, :continue}}
+
+ assert @command.fill_consumer_active_fields({[
+ [
+ queue_name: {:resource, "/", :queue, "queue2"},
+ channel_pid: "",
+ consumer_tag: "ctag2",
+ ack_required: false,
+ prefetch_count: 0,
+ arguments: []
+ ]
+ ], {1, :continue}}) == {[
+ [
+ queue_name: {:resource, "/", :queue, "queue2"},
+ channel_pid: "",
+ consumer_tag: "ctag2",
+ ack_required: false,
+ prefetch_count: 0,
+ active: true,
+ activity_status: :up,
+ arguments: []
+ ]
+ ], {1, :continue}}
+
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_exchanges_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_exchanges_command_test.exs
new file mode 100644
index 0000000000..fd89cfd066
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_exchanges_command_test.exs
@@ -0,0 +1,160 @@
+defmodule ListExchangesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand
+
+ @vhost "test1"
+ @user "guest"
+ @default_timeout :infinity
+ @default_exchanges [{"amq.direct", :direct},
+ {"amq.fanout", :fanout},
+ {"amq.match", :headers},
+ {"amq.rabbitmq.trace", :topic},
+ {"amq.headers", :headers},
+ {"amq.topic", :topic},
+ {"", :direct}]
+ @default_options %{vhost: "/", table_headers: true}
+
+ defp default_exchange_names() do
+ {names, _types} = Enum.unzip(@default_exchanges)
+ names
+ end
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+ {
+ :ok,
+ opts: %{
+ quiet: true,
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout,
+ vhost: @vhost
+ }
+ }
+ end
+
+ test "merge_defaults: should include name and type when no arguments provided and add default vhost to opts" do
+ assert @command.merge_defaults([], %{})
+ == {["name", "type"], @default_options}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {["name", "type"], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {["name", "type"], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: returns multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "type"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["name", "oink", "type"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: zero timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0}}]
+ end
+
+ test "run: show default exchanges by default", context do
+ assert MapSet.new(run_command_to_list(@command, [["name"], context[:opts]])) ==
+ MapSet.new(for {ex_name, _ex_type} <- @default_exchanges, do: [name: ex_name])
+ end
+
+ test "run: default options test", context do
+ exchange_name = "test_exchange"
+ declare_exchange(exchange_name, @vhost)
+ assert MapSet.new(run_command_to_list(@command, [["name", "type"], context[:opts]])) ==
+ MapSet.new(
+ for({ex_name, ex_type} <- @default_exchanges, do: [name: ex_name, type: ex_type]) ++
+ [[name: exchange_name, type: :direct]])
+ end
+
+ test "run: list multiple exchanges", context do
+ declare_exchange("test_exchange_1", @vhost, :direct)
+ declare_exchange("test_exchange_2", @vhost, :fanout)
+ non_default_exchanges = run_command_to_list(@command, [["name", "type"], context[:opts]])
+ |> without_default_exchanges
+ assert_set_equal(
+ non_default_exchanges,
+ [[name: "test_exchange_1", type: :direct],
+ [name: "test_exchange_2", type: :fanout]])
+ end
+
+ def assert_set_equal(one, two) do
+ assert MapSet.new(one) == MapSet.new(two)
+ end
+
+ test "run: info keys filter single key", context do
+ declare_exchange("test_exchange_1", @vhost)
+ declare_exchange("test_exchange_2", @vhost)
+ non_default_exchanges = run_command_to_list(@command, [["name"], context[:opts]])
+ |> without_default_exchanges
+ assert_set_equal(
+ non_default_exchanges,
+ [[name: "test_exchange_1"],
+ [name: "test_exchange_2"]])
+ end
+
+
+ test "run: info keys add additional keys", context do
+ declare_exchange("durable_exchange", @vhost, :direct, true)
+ declare_exchange("auto_delete_exchange", @vhost, :fanout, false, true)
+ non_default_exchanges = run_command_to_list(@command, [["name", "type", "durable", "auto_delete"], context[:opts]])
+ |> without_default_exchanges
+ assert_set_equal(
+ non_default_exchanges,
+ [[name: "auto_delete_exchange", type: :fanout, durable: false, auto_delete: true],
+ [name: "durable_exchange", type: :direct, durable: true, auto_delete: false]])
+ end
+
+ test "run: specifying a vhost returns the targeted vhost exchanges", context do
+ other_vhost = "other_vhost"
+ add_vhost other_vhost
+ on_exit(fn ->
+ delete_vhost other_vhost
+ end)
+ declare_exchange("test_exchange_1", @vhost)
+ declare_exchange("test_exchange_2", other_vhost)
+ non_default_exchanges1 = run_command_to_list(@command, [["name"], context[:opts]])
+ |> without_default_exchanges
+
+ non_default_exchanges2 = run_command_to_list(@command, [["name"], %{context[:opts] | :vhost => other_vhost}])
+ |> without_default_exchanges
+
+ assert non_default_exchanges1 == [[name: "test_exchange_1"]]
+ assert non_default_exchanges2 == [[name: "test_exchange_2"]]
+ end
+
+ defp without_default_exchanges(xs) do
+ Enum.filter(xs,
+ fn(x) ->
+ not Enum.member?(default_exchange_names(), x[:name])
+ end)
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_feature_flags_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_feature_flags_command_test.exs
new file mode 100644
index 0000000000..b2cf1ad52a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_feature_flags_command_test.exs
@@ -0,0 +1,122 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ListFeatureFlagsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListFeatureFlagsCommand
+
+ @flag1 :ff1_from_list_ff_testsuite
+ @flag2 :ff2_from_list_ff_testsuite
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ # Define an arbitrary feature flag for the test.
+ node = get_rabbit_hostname()
+ new_feature_flags = %{
+ @flag1 =>
+ %{desc: "My feature flag #1",
+ provided_by: :ListFeatureFlagsCommandTest,
+ stability: :stable},
+ @flag2 =>
+ %{desc: "My feature flag #2",
+ provided_by: :ListFeatureFlagsCommandTest,
+ stability: :stable}}
+ :ok = :rabbit_misc.rpc_call(
+ node, :rabbit_feature_flags, :initialize_registry, [new_feature_flags])
+ :ok = :rabbit_misc.rpc_call(
+ node, :rabbit_feature_flags, :enable_all, [])
+
+ name_result = [
+ [{:name, @flag1}],
+ [{:name, @flag2}]
+ ]
+
+ full_result = [
+ [{:name, @flag1}, {:state, :enabled}],
+ [{:name, @flag2}, {:state, :enabled}]
+ ]
+
+ {
+ :ok,
+ name_result: name_result,
+ full_result: full_result
+ }
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), timeout: context[:test_timeout]}
+ }
+ end
+
+ test "merge_defaults with no command, print just use the names" do
+ assert match?({["name", "state"], %{}}, @command.merge_defaults([], %{}))
+ end
+
+ test "validate: return bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "name"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["name", "oink", "state"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ test "run: on a bad RabbitMQ node, return a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["name"], opts))
+ end
+
+ @tag test_timeout: :infinity
+ test "run: with the name tag, print just the names", context do
+ matches_found = @command.run(["name"], context[:opts])
+ assert Enum.all?(context[:name_result], fn(feature_name) ->
+ Enum.find(matches_found, fn(found) -> found == feature_name end)
+ end)
+ end
+
+ @tag test_timeout: :infinity
+ test "run: duplicate args do not produce duplicate entries", context do
+ # checks to ensure that all expected feature flags are in the results
+ matches_found = @command.run(["name", "name"], context[:opts])
+ assert Enum.all?(context[:name_result], fn(feature_name) ->
+ Enum.find(matches_found, fn(found) -> found == feature_name end)
+ end)
+ end
+
+ @tag test_timeout: 30000
+ test "run: sufficiently long timeouts don't interfere with results", context do
+ matches_found = @command.run(["name", "state"], context[:opts])
+ assert Enum.all?(context[:full_result], fn(feature_name) ->
+ Enum.find(matches_found, fn(found) -> found == feature_name end)
+ end)
+ end
+
+ @tag test_timeout: 0, username: "guest"
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run(["name", "state"], context[:opts]) ==
+ {:badrpc, :timeout}
+ end
+
+ @tag test_timeout: :infinity
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Listing feature flags \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_global_parameters_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_global_parameters_command_test.exs
new file mode 100644
index 0000000000..eabd6a3628
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_global_parameters_command_test.exs
@@ -0,0 +1,86 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListGlobalParametersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListGlobalParametersCommand
+
+ @key :mqtt_default_vhosts
+ @value "{\"O=client,CN=dummy\":\"somevhost\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ :ok
+ end
+
+ setup context do
+ on_exit(fn ->
+ clear_global_parameter context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: (context[:timeout] || :infinity),
+ }
+ }
+ end
+
+ test "validate: wrong number of arguments leads to an arg count error" do
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag key: @key, value: @value
+ test "run: a well-formed command returns list of global parameters", context do
+ set_global_parameter(context[:key], @value)
+ @command.run([], context[:opts])
+ |> assert_parameter_list(context)
+ end
+
+ @tag key: @key, value: @value
+ test "run: zero timeout return badrpc", context do
+ set_global_parameter(context[:key], @value)
+ assert @command.run([], Map.put(context[:opts], :timeout, 0)) == {:badrpc, :timeout}
+ end
+
+ test "run: multiple parameters returned in list", context do
+ initial = for param <- @command.run([], context[:opts]), do: Map.new(param)
+ parameters = [
+ %{name: :global_param_1, value: "{\"key1\":\"value1\"}"},
+ %{name: :global_param_2, value: "{\"key2\":\"value2\"}"}
+ ]
+
+
+ Enum.each(parameters, fn(%{name: name, value: value}) ->
+ set_global_parameter(name, value)
+ on_exit(fn ->
+ clear_global_parameter(name)
+ end)
+ end)
+
+ parameters = initial ++ parameters
+ params = for param <- @command.run([], context[:opts]), do: Map.new(param)
+
+ assert MapSet.new(params) == MapSet.new(parameters)
+ end
+
+ @tag key: @key, value: @value
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Listing global runtime parameters \.\.\./
+ end
+
+ # Checks each element of the first parameter against the expected context values
+ defp assert_parameter_list(params, context) do
+ [param | _] = params
+ assert MapSet.new(param) == MapSet.new([name: context[:key],
+ value: context[:value]])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_hashes_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_hashes_command_test.exs
new file mode 100644
index 0000000000..2869479a8a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_hashes_command_test.exs
@@ -0,0 +1,29 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ListHashesCommandTest do
+ use ExUnit.Case
+ @command RabbitMQ.CLI.Ctl.Commands.ListHashesCommand
+
+ test "merge_defaults: nothing to do" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: treats positional arguments as a failure" do
+ assert @command.validate(["extra-arg"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: treats empty positional arguments and default switches as a success" do
+ assert @command.validate([], %{}) == :ok
+ end
+
+ test "run: lists hashes", _context do
+ assert match?(
+ {:ok, _},
+ @command.run([], %{})
+ )
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_operator_policies_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_operator_policies_command_test.exs
new file mode 100644
index 0000000000..6c86fe8441
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_operator_policies_command_test.exs
@@ -0,0 +1,142 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListOperatorPoliciesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListOperatorPoliciesCommand
+
+ @vhost "test1"
+ @root "/"
+ @key "message-expiry"
+ @pattern "^queue\."
+ @value "{\"message-ttl\":10}"
+ @apply_to "all"
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(fn ->
+ clear_operator_policy context[:vhost], context[:key]
+ end)
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: (context[:timeout] || :infinity),
+ vhost: context[:vhost],
+ apply_to: @apply_to,
+ priority: 0
+ }
+ }
+ end
+
+ test "merge_defaults: default vhost is '/'" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns list of policies", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_operator_policy(context[:vhost], context[:key], context[:pattern], @value)
+ @command.run([], vhost_opts)
+ |> assert_operator_policy_list(context)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @root
+ test "run: a well-formed command with no vhost runs against the default one", context do
+
+ set_operator_policy("/", context[:key], context[:pattern], @value)
+ on_exit(fn ->
+ clear_operator_policy("/", context[:key])
+ end)
+
+ @command.run([], context[:opts])
+ |> assert_operator_policy_list(context)
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "run: providing a timeout of 0 returns a badrpc", context do
+ set_operator_policy(context[:vhost], context[:key], context[:pattern], @value)
+ assert @command.run([], Map.put(context[:opts], :timeout, 0)) == {:badrpc, :timeout}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: "bad-vhost"
+ test "run: providing a non-existent vhost returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag vhost: @vhost
+ test "run: when multiple policies exist in the vhost, returns them all", context do
+ policies = [
+ %{vhost: @vhost, name: "some-policy", pattern: "foo", definition: "{\"message-ttl\":10}", 'apply-to': "all", priority: 0},
+ %{vhost: @vhost, name: "other-policy", pattern: "bar", definition: "{\"expires\":20}", 'apply-to': "all", priority: 0}
+ ]
+ policies
+ |> Enum.map(
+ fn(%{name: name, pattern: pattern, definition: value}) ->
+ set_operator_policy(context[:vhost], name, pattern, value)
+ on_exit(fn ->
+ clear_operator_policy(context[:vhost], name)
+ end)
+ end)
+
+ pols = for policy <- @command.run([], context[:opts]), do: Map.new(policy)
+
+ assert MapSet.new(pols) == MapSet.new(policies)
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([], vhost_opts)
+ =~ ~r/Listing operator policy overrides for vhost \"#{context[:vhost]}\" \.\.\./
+ end
+
+ # Checks each element of the first policy against the expected context values
+ defp assert_operator_policy_list(policies, context) do
+ [policy] = policies
+ assert MapSet.new(policy) == MapSet.new([name: context[:key],
+ pattern: context[:pattern],
+ definition: context[:value],
+ vhost: context[:vhost],
+ priority: context[:opts][:priority],
+ "apply-to": context[:opts][:apply_to]])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_parameters_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_parameters_command_test.exs
new file mode 100644
index 0000000000..f42e55353a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_parameters_command_test.exs
@@ -0,0 +1,154 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListParametersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListParametersCommand
+
+ @vhost "test1"
+ @root "/"
+ @component_name "federation-upstream"
+ @key "reconnect-delay"
+ @value "{\"uri\":\"amqp://\"}"
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ node = get_rabbit_hostname()
+
+ {:ok, plugins_file} = :rabbit_misc.rpc_call(node,
+ :application, :get_env,
+ [:rabbit, :enabled_plugins_file])
+ {:ok, plugins_dir} = :rabbit_misc.rpc_call(node,
+ :application, :get_env,
+ [:rabbit, :plugins_dir])
+ rabbitmq_home = :rabbit_misc.rpc_call(node, :code, :lib_dir, [:rabbit])
+
+ {:ok, [enabled_plugins]} = :file.consult(plugins_file)
+
+ opts = %{enabled_plugins_file: plugins_file,
+ plugins_dir: plugins_dir,
+ rabbitmq_home: rabbitmq_home}
+
+ set_enabled_plugins([:rabbitmq_stomp, :rabbitmq_federation], :online, node, opts)
+
+ add_vhost @vhost
+
+ enable_federation_plugin()
+
+ on_exit(fn ->
+ set_enabled_plugins(enabled_plugins, :online, get_rabbit_hostname(), opts)
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(fn ->
+ clear_parameter context[:vhost], context[:component_name], context[:key]
+ end)
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: (context[:timeout] || :infinity),
+ vhost: context[:vhost]
+ }
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: wrong number of arguments leads to an arg count error" do
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns list of parameters", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_parameter(context[:vhost], context[:component_name], context[:key], @value)
+ @command.run([], vhost_opts)
+ |> assert_parameter_list(context)
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @root
+ test "run: a well-formed command with no vhost runs against the default", context do
+
+ set_parameter("/", context[:component_name], context[:key], @value)
+ on_exit(fn ->
+ clear_parameter("/", context[:component_name], context[:key])
+ end)
+
+ @command.run([], context[:opts])
+ |> assert_parameter_list(context)
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "run: zero timeout return badrpc", context do
+ set_parameter(context[:vhost], context[:component_name], context[:key], @value)
+ assert @command.run([], Map.put(context[:opts], :timeout, 0)) == {:badrpc, :timeout}
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: an invalid vhost returns a no-such-vhost error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag vhost: @vhost
+ test "run: multiple parameters returned in list", context do
+ parameters = [
+ %{component: "federation-upstream", name: "my-upstream", value: "{\"uri\":\"amqp://\"}"},
+ %{component: "exchange-delete-in-progress", name: "my-key", value: "{\"foo\":\"bar\"}"}
+ ]
+ parameters
+ |> Enum.map(
+ fn(%{component: component, name: name, value: value}) ->
+ set_parameter(context[:vhost], component, name, value)
+ on_exit(fn ->
+ clear_parameter(context[:vhost], component, name)
+ end)
+ end)
+
+ params = for param <- @command.run([], context[:opts]), do: Map.new(param)
+
+ assert MapSet.new(params) == MapSet.new(parameters)
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([], vhost_opts)
+ =~ ~r/Listing runtime parameters for vhost \"#{context[:vhost]}\" \.\.\./
+ end
+
+ # Checks each element of the first parameter against the expected context values
+ defp assert_parameter_list(params, context) do
+ [param] = params
+ assert MapSet.new(param) == MapSet.new([component: context[:component_name],
+ name: context[:key],
+ value: context[:value]])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_permissions_command_test.exs
new file mode 100644
index 0000000000..eda8f001af
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_permissions_command_test.exs
@@ -0,0 +1,92 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListPermissionsCommand
+
+ @vhost "test1"
+ @user "guest"
+ @root "/"
+ @default_timeout :infinity
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+ set_permissions @user, @vhost, ["^guest-.*", ".*", ".*"]
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout],
+ vhost: "/"
+ }
+ }
+ end
+
+ test "merge_defaults adds default options" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: invalid parameters yield an arg count error" do
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: on a bad RabbitMQ node, return a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag test_timeout: @default_timeout, vhost: @vhost
+ test "run: specifying a vhost returns the targeted vhost permissions", context do
+ assert @command.run(
+ [],
+ Map.merge(context[:opts], %{vhost: @vhost})
+ ) == [[user: "guest", configure: "^guest-.*", write: ".*", read: ".*"]]
+ end
+
+ @tag test_timeout: 30000
+ test "run: sufficiently long timeouts don't interfere with results", context do
+ results = @command.run([], context[:opts])
+ Enum.all?([[user: "guest", configure: ".*", write: ".*", read: ".*"]], fn(perm) ->
+ Enum.find(results, fn(found) -> found == perm end)
+ end)
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run([], context[:opts]) ==
+ {:badrpc, :timeout}
+ end
+
+ @tag vhost: @root
+ test "banner", context do
+ ctx = Map.merge(context[:opts], %{vhost: @vhost})
+ assert @command.banner([], ctx )
+ =~ ~r/Listing permissions for vhost \"#{Regex.escape(ctx[:vhost])}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_policies_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_policies_command_test.exs
new file mode 100644
index 0000000000..49ef6ee856
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_policies_command_test.exs
@@ -0,0 +1,144 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListPoliciesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListPoliciesCommand
+
+ @vhost "test1"
+ @default_vhost "/"
+ @key "federate"
+ @pattern "^fed\."
+ @value "{\"federation-upstream-set\":\"all\"}"
+ @apply_to "all"
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+ enable_federation_plugin()
+
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ on_exit(fn ->
+ clear_policy context[:vhost], context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: (context[:timeout] || :infinity),
+ vhost: context[:vhost],
+ apply_to: @apply_to,
+ priority: 0
+ }
+ }
+ end
+
+ test "merge_defaults: default vhost is '/'" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns list of policies", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ set_policy(context[:vhost], context[:key], context[:pattern], @value)
+ @command.run([], vhost_opts)
+ |> assert_policy_list(context)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @default_vhost
+ test "run: a well-formed command with no vhost runs against the default one", context do
+ set_policy("/", context[:key], context[:pattern], @value)
+ on_exit(fn ->
+ clear_policy("/", context[:key])
+ end)
+
+ @command.run([], context[:opts])
+ |> assert_policy_list(context)
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "run: providing a timeout of 0 returns a badrpc", context do
+ set_policy(context[:vhost], context[:key], context[:pattern], @value)
+ assert @command.run([], Map.put(context[:opts], :timeout, 0)) == {:badrpc, :timeout}
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: "bad-vhost"
+ test "run: providing a non-existent vhost returns an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag vhost: @vhost
+ test "run: when multiple policies exist in the vhost, returns them all", context do
+ policies = [
+ %{vhost: @vhost, name: "some-policy", pattern: "foo", definition: "{\"federation-upstream-set\":\"all\"}", 'apply-to': "all", priority: 0},
+ %{vhost: @vhost, name: "other-policy", pattern: "bar", definition: "{\"ha-mode\":\"all\"}", 'apply-to': "all", priority: 0}
+ ]
+ policies
+ |> Enum.map(
+ fn(%{name: name, pattern: pattern, definition: value}) ->
+ set_policy(context[:vhost], name, pattern, value)
+ on_exit(fn ->
+ clear_policy(context[:vhost], name)
+ end)
+ end)
+
+ pols = for policy <- @command.run([], context[:opts]), do: Map.new(policy)
+
+ assert MapSet.new(pols) == MapSet.new(policies)
+ end
+
+ @tag key: @key, pattern: @pattern, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([], vhost_opts)
+ =~ ~r/Listing policies for vhost \"#{context[:vhost]}\" \.\.\./
+ end
+
+ # Checks each element of the first policy against the expected context values
+ defp assert_policy_list(policies, context) do
+ [policy | _] = policies
+ assert MapSet.new(policy) == MapSet.new([name: context[:key],
+ pattern: context[:pattern],
+ definition: context[:value],
+ vhost: context[:vhost],
+ priority: context[:opts][:priority],
+ "apply-to": context[:opts][:apply_to]])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_queues_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_queues_command_test.exs
new file mode 100644
index 0000000000..a6635c7933
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_queues_command_test.exs
@@ -0,0 +1,145 @@
+defmodule ListQueuesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand
+
+ @vhost "test1"
+ @user "guest"
+ @default_timeout 15000
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ reset_vm_memory_high_watermark()
+ delete_all_queues()
+ close_all_connections(get_rabbit_hostname())
+
+ on_exit([], fn ->
+ delete_all_queues()
+ close_all_connections(get_rabbit_hostname())
+ end)
+
+ :ok
+ end
+
+ setup context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+ {
+ :ok,
+ opts: %{
+ quiet: true,
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout] || @default_timeout,
+ vhost: @vhost,
+ offline: false,
+ online: false,
+ local: false
+ }
+ }
+ end
+
+ test "merge_defaults: no info keys returns names and message count" do
+ assert match?({["name", "messages"], _}, @command.merge_defaults([], %{}))
+ end
+
+ test "validate: returns bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "messages"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["name", "oink", "messages"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return badrpc", context do
+ assert run_command_to_list(@command, [["name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.0, "Some queue(s) are unresponsive, use list_unresponsive_queues command."}}]
+ end
+
+ @tag test_timeout: 1
+ test "run: command timeout (several thousands queues in 1ms) return badrpc with timeout value in seconds", context do
+ # we assume it will take longer than 1 ms to list thousands of queues
+ n = 5000
+ for i <- 1..n do
+ declare_queue("test_queue_" <> Integer.to_string(i), @vhost)
+ end
+ assert run_command_to_list(@command, [["name"], context[:opts]]) ==
+ [{:badrpc, {:timeout, 0.001, "Some queue(s) are unresponsive, use list_unresponsive_queues command."}}]
+ for i <- 1..n do
+ delete_queue("test_queue_" <> Integer.to_string(i), @vhost)
+ end
+ end
+
+ @tag test_timeout: 5000
+ test "run: return multiple queues", context do
+ declare_queue("test_queue_1", @vhost)
+ publish_messages(@vhost, "test_queue_1", 3)
+ declare_queue("test_queue_2", @vhost)
+ publish_messages(@vhost, "test_queue_2", 1)
+ assert Keyword.equal?(run_command_to_list(@command, [["name", "messages"], context[:opts]]),
+ [[name: "test_queue_1", messages: 3],
+ [name: "test_queue_2", messages: 1]])
+ end
+
+ @tag test_timeout: 5000
+ test "run: info keys filter single key", context do
+ declare_queue("test_queue_1", @vhost)
+ declare_queue("test_queue_2", @vhost)
+ assert Keyword.equal?(run_command_to_list(@command, [["name"], context[:opts]]),
+ [[name: "test_queue_1"],
+ [name: "test_queue_2"]])
+ end
+
+ @tag test_timeout: 5000
+ test "run: info keys add additional keys", context do
+ declare_queue("durable_queue", @vhost, true)
+ publish_messages(@vhost, "durable_queue", 3)
+ declare_queue("auto_delete_queue", @vhost, false, true)
+ publish_messages(@vhost, "auto_delete_queue", 1)
+ assert Keyword.equal?(
+ run_command_to_list(@command, [["name", "messages", "durable", "auto_delete"], context[:opts]]),
+ [[name: "durable_queue", messages: 3, durable: true, auto_delete: false],
+ [name: "auto_delete_queue", messages: 1, durable: false, auto_delete: true]])
+ end
+
+ @tag test_timeout: 5000
+ test "run: info keys order is preserved", context do
+ declare_queue("durable_queue", @vhost, true)
+ publish_messages(@vhost, "durable_queue", 3)
+ declare_queue("auto_delete_queue", @vhost, false, true)
+ publish_messages(@vhost, "auto_delete_queue", 1)
+ assert Keyword.equal?(
+ run_command_to_list(@command, [["messages", "durable", "name", "auto_delete"], context[:opts]]),
+ [[messages: 3, durable: true, name: "durable_queue", auto_delete: false],
+ [messages: 1, durable: false, name: "auto_delete_queue", auto_delete: true]])
+ end
+
+ @tag test_timeout: 5000
+ test "run: specifying a vhost returns the targeted vhost queues", context do
+ other_vhost = "other_vhost"
+ add_vhost other_vhost
+ on_exit(fn ->
+ delete_vhost other_vhost
+ end)
+ declare_queue("test_queue_1", @vhost)
+ declare_queue("test_queue_2", other_vhost)
+ assert run_command_to_list(@command, [["name"], context[:opts]]) == [[name: "test_queue_1"]]
+ assert run_command_to_list(@command, [["name"], %{context[:opts] | :vhost => other_vhost}]) == [[name: "test_queue_2"]]
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_topic_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_topic_permissions_command_test.exs
new file mode 100644
index 0000000000..8de1f2536a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_topic_permissions_command_test.exs
@@ -0,0 +1,85 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListTopicPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListTopicPermissionsCommand
+
+ @vhost "test1"
+ @user "user1"
+ @password "password"
+ @root "/"
+ @default_timeout :infinity
+ @default_options %{vhost: "/", table_headers: true}
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost(@vhost)
+ add_user(@user, @password)
+ set_topic_permissions(@user, @vhost, "amq.topic", "^a", "^b")
+ set_topic_permissions(@user, @vhost, "topic1", "^a", "^b")
+
+ on_exit([], fn ->
+ clear_topic_permissions(@user, @vhost)
+ delete_user(@user)
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ timeout: context[:test_timeout],
+ vhost: "/"
+ }
+ }
+ end
+
+ test "merge_defaults adds default vhost" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], @default_options}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default",
+ table_headers: true}}
+ end
+
+ test "validate: does not expect any parameter" do
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag test_timeout: @default_timeout, vhost: @vhost
+ test "run: specifying a vhost returns the topic permissions for the targeted vhost", context do
+ permissions = @command.run([], Map.merge(context[:opts], %{vhost: @vhost}))
+ assert Enum.count(permissions) == 2
+ assert Enum.sort(permissions) == [
+ [user: @user, exchange: "amq.topic", write: "^a", read: "^b"],
+ [user: @user, exchange: "topic1", write: "^a", read: "^b"]
+ ]
+ end
+
+ @tag vhost: @root
+ test "banner", context do
+ ctx = Map.merge(context[:opts], %{vhost: @vhost})
+ assert @command.banner([], ctx )
+ =~ ~r/Listing topic permissions for vhost \"#{Regex.escape(ctx[:vhost])}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_user_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_user_limits_command_test.exs
new file mode 100644
index 0000000000..7b0370f940
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_user_limits_command_test.exs
@@ -0,0 +1,103 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ListUserLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListUserLimitsCommand
+
+ @user "guest"
+ @user1 "test_user1"
+ @password1 "password1"
+ @connection_limit_defn "{\"max-connections\":100}"
+ @channel_limit_defn "{\"max-channels\":1000}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ user = context[:user] || @user
+
+ clear_user_limits(user)
+
+ on_exit(context, fn ->
+ clear_user_limits(user)
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ global: true
+ },
+ user: user
+ }
+ end
+
+ test "merge_defaults: does not change defined user" do
+ assert match?({[], %{user: "test_user"}}, @command.merge_defaults([], %{user: "test_user"}))
+ end
+
+ test "validate: providing arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: a well-formed command returns an empty list if there are no limits", context do
+ assert @command.run([], context[:opts]) == []
+ end
+
+ test "run: a well-formed user specific command returns an empty json object if there are no limits" do
+ assert @command.run([], %{node: get_rabbit_hostname(),
+ user: @user}) == "{}"
+ end
+
+ test "run: list limits for all users", context do
+ add_user(@user1, @password1)
+ on_exit(fn() ->
+ delete_user(@user1)
+ end)
+ set_user_limits(@user, @connection_limit_defn)
+ set_user_limits(@user1, @channel_limit_defn)
+
+ assert Enum.sort(@command.run([], context[:opts])) ==
+ Enum.sort([[user: @user, limits: @connection_limit_defn],
+ [user: @user1, limits: @channel_limit_defn]])
+ end
+
+ test "run: list limits for a single user", context do
+ user_opts = Map.put(context[:opts], :user, @user)
+ set_user_limits(@user, @connection_limit_defn)
+
+ assert @command.run([], user_opts) ==
+ [[user: @user, limits: @connection_limit_defn]]
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, user: "guest", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag user: "user"
+ test "run: providing a non-existent user reports an error", _context do
+ s = "non-existent-user"
+
+ assert @command.run([], %{node: get_rabbit_hostname(),
+ user: s}) == {:error, {:no_such_user, s}}
+ end
+
+ test "banner", context do
+ assert @command.banner([], %{user: context[:user]})
+ == "Listing limits for user \"#{context[:user]}\" ..."
+ assert @command.banner([], %{global: true})
+ == "Listing limits for all users ..."
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_user_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_user_permissions_command_test.exs
new file mode 100644
index 0000000000..ddd44c0e01
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_user_permissions_command_test.exs
@@ -0,0 +1,91 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListUserPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListUserPermissionsCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ default_result = [
+ [
+ {:vhost,<<"/">>},
+ {:configure,<<".*">>},
+ {:write,<<".*">>},
+ {:read,<<".*">>}
+ ]
+ ]
+
+ no_such_user_result = {:error, {:no_such_user, context[:username]}}
+
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), timeout: context[:test_timeout]},
+ result: default_result,
+ no_such_user: no_such_user_result,
+ timeout: {:badrpc, :timeout}
+ }
+ end
+
+## -------------------------------- Usage -------------------------------------
+
+ test "validate: wrong number of arguments results in an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["guest", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+## ------------------------------- Username -----------------------------------
+
+ @tag test_timeout: :infinity, username: "guest"
+ test "run: valid user returns a list of permissions", context do
+ results = @command.run([context[:username]], context[:opts])
+ assert Enum.all?(context[:result], fn(perm) ->
+ Enum.find(results, fn(found) -> found == perm end)
+ end)
+ end
+
+ @tag test_timeout: :infinity, username: "interloper"
+ test "run: invalid user returns a no-such-user error", context do
+ assert @command.run(
+ [context[:username]], context[:opts]) == context[:no_such_user]
+ end
+
+## --------------------------------- Flags ------------------------------------
+
+ test "run: unreachable RabbitMQ node returns a badrpc" do
+ assert match?({:badrpc, _}, @command.run(["guest"], %{node: :jake@thedog, timeout: 200}))
+ end
+
+ @tag test_timeout: 30000, username: "guest"
+ test "run: long user-defined timeout doesn't interfere with operation", context do
+ results = @command.run([context[:username]], context[:opts])
+ Enum.all?(context[:result], fn(perm) ->
+ Enum.find(results, fn(found) -> found == perm end)
+ end)
+ end
+
+ @tag test_timeout: 0, username: "guest"
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run(
+ [context[:username]],
+ context[:opts]
+ ) == context[:timeout]
+ end
+
+ @tag test_timeout: :infinity
+ test "banner", context do
+ assert @command.banner( [context[:username]], context[:opts])
+ =~ ~r/Listing permissions for user \"#{context[:username]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_user_topic_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_user_topic_permissions_command_test.exs
new file mode 100644
index 0000000000..edf935de77
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_user_topic_permissions_command_test.exs
@@ -0,0 +1,72 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListUserTopicPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListUserTopicPermissionsCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ set_topic_permissions("guest", "/", "amq.topic", "^a", "^b")
+ set_topic_permissions("guest", "/", "topic1", "^a", "^b")
+
+ on_exit([], fn ->
+ clear_topic_permissions("guest", "/")
+ end)
+
+ :ok
+ end
+
+ setup context do
+ no_such_user_result = {:error, {:no_such_user, context[:username]}}
+
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), timeout: context[:test_timeout]},
+ no_such_user: no_such_user_result,
+ timeout: {:badrpc, :timeout}
+ }
+ end
+
+## -------------------------------- Usage -------------------------------------
+
+ test "validate: expect username argument" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["guest", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+## ------------------------------- Username -----------------------------------
+
+ @tag test_timeout: :infinity, username: "guest"
+ test "run: valid user returns a list of topic permissions", context do
+ results = @command.run([context[:username]], context[:opts])
+ assert Enum.count(results) == 2
+ end
+
+ @tag test_timeout: :infinity, username: "interloper"
+ test "run: invalid user returns a no-such-user error", context do
+ assert @command.run(
+ [context[:username]], context[:opts]) == context[:no_such_user]
+ end
+
+## --------------------------------- Flags ------------------------------------
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["guest"], opts))
+ end
+
+ @tag test_timeout: :infinity
+ test "banner", context do
+ assert @command.banner( [context[:username]], context[:opts])
+ =~ ~r/Listing topic permissions for user \"#{context[:username]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_users_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_users_command_test.exs
new file mode 100644
index 0000000000..bcfdb84b2b
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_users_command_test.exs
@@ -0,0 +1,74 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListUsersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListUsersCommand
+
+ @user "user1"
+ @password "password"
+ @guest "guest"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ std_result = [
+ [{:user,@guest},{:tags,[:administrator]}],
+ [{:user,@user},{:tags,[]}]
+ ]
+
+ {:ok, std_result: std_result}
+ end
+
+ setup context do
+ add_user @user, @password
+ on_exit([], fn -> delete_user @user end)
+
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: context[:test_timeout]}}
+ end
+
+ test "validate: On incorrect number of commands, return an arg count error" do
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag test_timeout: 15000
+ test "run: On a successful query, return an array of lists of tuples", context do
+ matches_found = @command.run([], context[:opts])
+
+ assert Enum.all?(context[:std_result], fn(user) ->
+ Enum.find(matches_found, fn(found) -> found == user end)
+ end)
+ end
+
+ test "run: On an invalid rabbitmq node, return a bad rpc" do
+ assert match?({:badrpc, _}, @command.run([], %{node: :jake@thedog, timeout: 200}))
+ end
+
+ @tag test_timeout: 30000
+ test "run: sufficiently long timeouts don't interfere with results", context do
+ # checks to ensure that all expected users are in the results
+ matches_found = @command.run([], context[:opts])
+
+ assert Enum.all?(context[:std_result], fn(user) ->
+ Enum.find(matches_found, fn(found) -> found == user end)
+ end)
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run([], context[:opts]) ==
+ {:badrpc, :timeout}
+ end
+
+ @tag test_timeout: :infinity
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Listing users \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_vhost_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_vhost_limits_command_test.exs
new file mode 100644
index 0000000000..f07d40672a
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_vhost_limits_command_test.exs
@@ -0,0 +1,111 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListVhostLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListVhostLimitsCommand
+
+ @vhost "test_vhost"
+ @vhost1 "test_vhost1"
+ @connection_limit_defn "{\"max-connections\":100}"
+ @queue_limit_defn "{\"max-queues\":1000}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+ vhost = context[:vhost] || @vhost
+
+ clear_vhost_limits(vhost)
+
+ on_exit(context, fn ->
+ clear_vhost_limits(vhost)
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ global: true
+ },
+ vhost: vhost
+ }
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert match?({[], %{vhost: "test_vhost"}}, @command.merge_defaults([], %{vhost: "test_vhost"}))
+ end
+
+ test "validate: providing arguments fails validation" do
+ assert @command.validate(["many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: a well-formed command returns an empty list if there are no limits", context do
+ assert @command.run([], context[:opts]) == []
+ end
+
+ test "run: a well-formed vhost specific command returns an empty list if there are no limits", context do
+ vhost_opts = Map.put(context[:opts], :vhost, @vhost)
+ assert @command.run([], vhost_opts) == []
+ end
+
+ test "run: list limits for all vhosts", context do
+ add_vhost(@vhost1)
+ on_exit(fn() ->
+ delete_vhost(@vhost1)
+ end)
+ set_vhost_limits(@vhost, @connection_limit_defn)
+ set_vhost_limits(@vhost1, @queue_limit_defn)
+
+ assert Enum.sort(@command.run([], context[:opts])) ==
+ Enum.sort([[vhost: @vhost, limits: @connection_limit_defn],
+ [vhost: @vhost1, limits: @queue_limit_defn]])
+ end
+
+ test "run: list limits for a single vhost", context do
+ vhost_opts = Map.put(context[:opts], :vhost, @vhost)
+ set_vhost_limits(@vhost, @connection_limit_defn)
+
+ assert @command.run([], vhost_opts) ==
+ [[vhost: @vhost, limits: @connection_limit_defn]]
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag vhost: "bad-vhost"
+ test "run: providing a non-existent vhost reports an error", _context do
+ s = "non-existent-vhost-a9sd89"
+
+ assert @command.run([], %{node: get_rabbit_hostname(),
+ vhost: s}) == {:error, {:no_such_vhost, s}}
+ end
+
+ test "banner", context do
+ assert @command.banner([], %{vhost: context[:vhost]})
+ == "Listing limits for vhost \"#{context[:vhost]}\" ..."
+ assert @command.banner([], %{global: true})
+ == "Listing limits for all vhosts ..."
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/list_vhosts_command_test.exs b/deps/rabbitmq_cli/test/ctl/list_vhosts_command_test.exs
new file mode 100644
index 0000000000..76f46af422
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/list_vhosts_command_test.exs
@@ -0,0 +1,160 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ListVhostsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand
+
+ @vhost1 "test1"
+ @vhost2 "test2"
+ @root "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost1
+ add_vhost @vhost2
+ trace_off @root
+
+ on_exit([], fn ->
+ delete_vhost @vhost1
+ delete_vhost @vhost2
+ end)
+
+ name_result = [
+ [{:name, @vhost1}],
+ [{:name, @vhost2}],
+ [{:name, @root}]
+ ]
+
+ tracing_result = [
+ [{:tracing, false}],
+ [{:tracing, false}],
+ [{:tracing, false}]
+ ]
+
+ full_result = [
+ [{:name, @vhost1}, {:tracing, false}],
+ [{:name, @vhost2}, {:tracing, false}],
+ [{:name, @root}, {:tracing, false}]
+ ]
+
+ transposed_result = [
+ [{:tracing, false}, {:name, @vhost1}],
+ [{:tracing, false}, {:name, @vhost2}],
+ [{:tracing, false}, {:name, @root}]
+ ]
+
+ {
+ :ok,
+ name_result: name_result,
+ tracing_result: tracing_result,
+ full_result: full_result,
+ transposed_result: transposed_result
+ }
+ end
+
+ setup context do
+ {
+ :ok,
+ opts: %{node: get_rabbit_hostname(), timeout: context[:test_timeout]}
+ }
+ end
+
+ test "merge_defaults with no command, print just use the names" do
+ assert match?({["name"], %{}}, @command.merge_defaults([], %{}))
+ end
+
+ test "validate: return bad_info_key on a single bad arg", context do
+ assert @command.validate(["quack"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ end
+
+ test "validate: multiple bad args return a list of bad info key values", context do
+ assert @command.validate(["quack", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink, :quack]}}
+ end
+
+ test "validate: return bad_info_key on mix of good and bad args", context do
+ assert @command.validate(["quack", "tracing"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:quack]}}
+ assert @command.validate(["name", "oink"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ assert @command.validate(["name", "oink", "tracing"], context[:opts]) ==
+ {:validation_failure, {:bad_info_key, [:oink]}}
+ end
+
+ test "run: on a bad RabbitMQ node, return a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["name"], opts))
+ end
+
+ @tag test_timeout: :infinity
+ test "run: with the name tag, print just the names", context do
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["name"], context[:opts])
+ assert Enum.all?(context[:name_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+ end
+
+ @tag test_timeout: :infinity
+ test "run: with the tracing tag, print just say if tracing is on", context do
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["tracing"], context[:opts])
+ assert Enum.all?(context[:tracing_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+ end
+
+ @tag test_timeout: :infinity
+ test "run: with name and tracing keys, print both", context do
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["name", "tracing"], context[:opts])
+ assert Enum.all?(context[:full_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["tracing", "name"], context[:opts])
+ assert Enum.all?(context[:transposed_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+ end
+
+ @tag test_timeout: :infinity
+ test "run: duplicate args do not produce duplicate entries", context do
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["name", "name"], context[:opts])
+ assert Enum.all?(context[:name_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+ end
+
+ @tag test_timeout: 30000
+ test "run: sufficiently long timeouts don't interfere with results", context do
+ # checks to ensure that all expected vhosts are in the results
+ matches_found = @command.run(["name", "tracing"], context[:opts])
+ assert Enum.all?(context[:full_result], fn(vhost) ->
+ Enum.find(matches_found, fn(found) -> found == vhost end)
+ end)
+ end
+
+ @tag test_timeout: 0, username: "guest"
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run(["name", "tracing"], context[:opts]) ==
+ {:badrpc, :timeout}
+ end
+
+ @tag test_timeout: :infinity
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Listing vhosts \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/node_health_check_command_test.exs b/deps/rabbitmq_cli/test/ctl/node_health_check_command_test.exs
new file mode 100644
index 0000000000..12ff786bfb
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/node_health_check_command_test.exs
@@ -0,0 +1,65 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule NodeHealthCheckCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.NodeHealthCheckCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ reset_vm_memory_high_watermark()
+
+ on_exit([], fn ->
+ reset_vm_memory_high_watermark()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 20000}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: with no arguments succeeds", _context do
+ assert @command.validate([], []) == :ok
+ end
+
+ test "validate: with a named, active node argument succeeds", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([], context[:opts])
+ end
+
+ test "run: request to a named, active node with an alarm in effect fails", context do
+ set_vm_memory_high_watermark(0.0000000000001)
+ # give VM memory monitor check some time to kick in
+ :timer.sleep(1500)
+ {:healthcheck_failed, _message} = @command.run([], context[:opts])
+
+ reset_vm_memory_high_watermark()
+ :timer.sleep(1500)
+ assert @command.run([], context[:opts]) == :ok
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ assert match?({:badrpc, _}, @command.run([], %{node: :jake@thedog, timeout: 200}))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) |> Enum.join("\n") =~ ~r/Checking health/
+ assert @command.banner([], context[:opts]) |> Enum.join("\n") =~ ~r/#{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/ping_command_test.exs b/deps/rabbitmq_cli/test/ctl/ping_command_test.exs
new file mode 100644
index 0000000000..347013a4a8
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/ping_command_test.exs
@@ -0,0 +1,56 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule PingCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.PingCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ reset_vm_memory_high_watermark()
+
+ on_exit([], fn ->
+ reset_vm_memory_high_watermark()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 200}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: with no arguments succeeds", _context do
+ assert @command.validate([], []) == :ok
+ end
+
+ test "validate: with a named, active node argument succeeds", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([], context[:opts])
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ assert match?({:error, _}, @command.run([], %{node: :jake@thedog, timeout: 200}))
+ end
+
+ test "banner", context do
+ banner = @command.banner([], context[:opts])
+
+ assert banner =~ ~r/Will ping/
+ assert banner =~ ~r/#{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/purge_queue_command_test.exs b/deps/rabbitmq_cli/test/ctl/purge_queue_command_test.exs
new file mode 100644
index 0000000000..9891175f15
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/purge_queue_command_test.exs
@@ -0,0 +1,88 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule PurgeQueueCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.PurgeQueueCommand
+ @user "guest"
+ @vhost "purge-queue-vhost"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost,
+ timeout: context[:test_timeout]
+ }}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ @tag test_timeout: 30000
+ test "request to an existent queue on active node succeeds", context do
+ add_vhost @vhost
+ set_permissions @user, @vhost, [".*", ".*", ".*"]
+ on_exit(context, fn -> delete_vhost(@vhost) end)
+
+ q = "foo"
+ n = 20
+
+ declare_queue(q, @vhost)
+ assert message_count(@vhost, q) == 0
+
+ publish_messages(@vhost, q, n)
+ assert message_count(@vhost, q) == n
+
+ assert @command.run([q], context[:opts]) == :ok
+ assert message_count(@vhost, q) == 0
+ end
+
+ @tag test_timeout: 30000
+ test "request to a non-existent queue on active node returns not found", context do
+ assert @command.run(["non-existent"], context[:opts]) == {:error, :not_found}
+ end
+
+ @tag test_timeout: 0
+ test "run: timeout causes command to return a bad RPC", context do
+ assert @command.run(["foo"], context[:opts]) == {:badrpc, :timeout}
+ end
+
+ test "shows up in help" do
+ s = @command.usage()
+ assert s =~ ~r/purge_queue/
+ end
+
+ test "defaults to vhost /" do
+ assert @command.merge_defaults(["foo"], %{bar: "baz"}) == {["foo"], %{bar: "baz", vhost: "/"}}
+ end
+
+ test "validate: with extra arguments returns an arg count error" do
+ assert @command.validate(["queue-name", "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: with no arguments returns an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: with correct args returns ok" do
+ assert @command.validate(["q"], %{}) == :ok
+ end
+
+ test "banner informs that vhost's queue is purged" do
+ assert @command.banner(["my-q"], %{vhost: "/foo"}) == "Purging queue 'my-q' in vhost '/foo' ..."
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/rename_cluster_node_command_test.exs b/deps/rabbitmq_cli/test/ctl/rename_cluster_node_command_test.exs
new file mode 100644
index 0000000000..02bf2ad795
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/rename_cluster_node_command_test.exs
@@ -0,0 +1,102 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule RenameClusterNodeCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ node = get_rabbit_hostname()
+
+ start_rabbitmq_app()
+
+ {:ok, plugins_dir} =
+ :rabbit_misc.rpc_call(node, :application, :get_env, [:rabbit, :plugins_dir])
+
+ rabbitmq_home = :rabbit_misc.rpc_call(node, :code, :lib_dir, [:rabbit])
+ mnesia_dir = :rabbit_misc.rpc_call(node, :rabbit_mnesia, :dir, [])
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ {:ok, opts: %{rabbitmq_home: rabbitmq_home, plugins_dir: plugins_dir, mnesia_dir: mnesia_dir}}
+ end
+
+ setup context do
+ {:ok,
+ opts:
+ Map.merge(
+ context[:opts],
+ %{node: :not_running@localhost}
+ )}
+ end
+
+ test "validate: specifying no nodes fails validation", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: specifying one node only fails validation", context do
+ assert @command.validate(["a"], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate_execution_environment: specifying an uneven number of arguments fails validation",
+ context do
+ assert match?(
+ {:validation_failure, {:bad_argument, _}},
+ @command.validate_execution_environment(["a", "b", "c"], context[:opts])
+ )
+ end
+
+ test "validate_execution_environment: request to a running node fails", _context do
+ node = get_rabbit_hostname()
+
+ assert match?(
+ {:validation_failure, :node_running},
+ @command.validate_execution_environment([to_string(node), "other_node@localhost"], %{
+ node: node
+ })
+ )
+ end
+
+ test "validate_execution_environment: not providing node mnesia dir fails validation",
+ context do
+ opts_without_mnesia = Map.delete(context[:opts], :mnesia_dir)
+ Application.put_env(:mnesia, :dir, "/tmp")
+ on_exit(fn -> Application.delete_env(:mnesia, :dir) end)
+
+ assert :ok ==
+ @command.validate(
+ ["some_node@localhost", "other_node@localhost"],
+ opts_without_mnesia
+ )
+
+ Application.delete_env(:mnesia, :dir)
+ System.put_env("RABBITMQ_MNESIA_DIR", "/tmp")
+ on_exit(fn -> System.delete_env("RABBITMQ_MNESIA_DIR") end)
+
+ assert :ok ==
+ @command.validate(
+ ["some_node@localhost", "other_node@localhost"],
+ opts_without_mnesia
+ )
+
+ System.delete_env("RABBITMQ_MNESIA_DIR")
+
+ assert :ok ==
+ @command.validate(["some_node@localhost", "other_node@localhost"], context[:opts])
+ end
+
+ test "banner", context do
+ assert @command.banner(["a", "b"], context[:opts]) =~
+ ~r/Renaming cluster nodes: \n a -> b/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/report_command_test.exs b/deps/rabbitmq_cli/test/ctl/report_command_test.exs
new file mode 100644
index 0000000000..f207ab8c2b
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/report_command_test.exs
@@ -0,0 +1,44 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ReportTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ReportCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: :infinity}}
+ end
+
+ test "validate: with extra arguments, status returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: report request to a reachable node succeeds", context do
+ output = @command.run([], context[:opts]) |> Enum.to_list
+
+ assert_stream_without_errors(output)
+ end
+
+ test "run: report request on nonexistent RabbitMQ node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Reporting server status of node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/reset_command_test.exs b/deps/rabbitmq_cli/test/ctl/reset_command_test.exs
new file mode 100644
index 0000000000..8bded47377
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/reset_command_test.exs
@@ -0,0 +1,68 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ResetCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ResetCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: reset request to an active node with a stopped rabbit app succeeds", context do
+ add_vhost "some_vhost"
+ #ensure the vhost really does exist
+ assert vhost_exists? "some_vhost"
+ stop_rabbitmq_app()
+ assert :ok == @command.run([], context[:opts])
+ start_rabbitmq_app()
+ #check that the created vhost no longer exists
+ assert match?([_], list_vhosts())
+ end
+
+ test "run: reset request to an active node with a running rabbit app fails", context do
+ add_vhost "some_vhost"
+ assert vhost_exists? "some_vhost"
+ assert match?({:error, :mnesia_unexpectedly_running}, @command.run([], context[:opts]))
+ assert vhost_exists? "some_vhost"
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Resetting node #{get_rabbit_hostname()}/
+ end
+
+ test "output mnesia is running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code,
+ "Mnesia is still running on node " <> _},
+ @command.output({:error, :mnesia_unexpectedly_running}, context[:opts]))
+
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/restart_vhost_command_test.exs b/deps/rabbitmq_cli/test/ctl/restart_vhost_command_test.exs
new file mode 100644
index 0000000000..c8d2fe7c48
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/restart_vhost_command_test.exs
@@ -0,0 +1,95 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule RestartVhostCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.RestartVhostCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ :ok
+ end
+
+ @vhost "vhost_to_restart"
+ @timeout 10000
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost,
+ timeout: @timeout
+ }}
+ end
+
+ test "validate: specifying arguments is reported as an error", context do
+ assert @command.validate(["a"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ assert @command.validate(["a", "b"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ assert @command.validate(["a", "b", "c"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a non-existent node returns a badrpc", _context do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: @timeout}
+ assert match?(
+ {:badrpc, _},
+ @command.run([], opts))
+ end
+
+ test "banner", context do
+ expected = "Trying to restart vhost '#{@vhost}' on node '#{get_rabbit_hostname()}' ..."
+ ^expected = @command.banner([], context[:opts])
+ end
+
+ test "run: restarting an existing vhost returns already_started", context do
+ setup_vhosts()
+ {:error, {:already_started, _}} = @command.run([], context[:opts])
+ end
+
+ test "run: restarting an failed vhost returns ok", context do
+ setup_vhosts()
+ vhost = context[:opts][:vhost]
+ node_name = context[:opts][:node]
+ force_vhost_failure(node_name, vhost)
+ {:ok, _} = @command.run([], context[:opts])
+ {:ok, _} = :rpc.call(node_name, :rabbit_vhost_sup_sup, :get_vhost_sup, [vhost])
+ end
+
+ #
+ # Implementation
+ #
+
+ defp setup_vhosts do
+ add_vhost @vhost
+ # give the vhost a chance to fully start and initialise
+ :timer.sleep(1000)
+ on_exit(fn ->
+ delete_vhost @vhost
+ end)
+ end
+
+ defp force_vhost_failure(node_name, vhost) do
+ case :rpc.call(node_name, :rabbit_vhost_sup_sup, :get_vhost_sup, [vhost]) do
+ {:ok, sup} ->
+ case :lists.keyfind(:msg_store_persistent, 1, :supervisor.which_children(sup)) do
+ {_, pid, _, _} ->
+ Process.exit(pid, :foo)
+ :timer.sleep(5000)
+ force_vhost_failure(node_name, vhost);
+ false ->
+ Process.exit(sup, :foo)
+ :timer.sleep(5000)
+ force_vhost_failure(node_name, vhost)
+ end;
+ {:error, {:vhost_supervisor_not_running, _}} ->
+ :ok
+ end
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/resume_listeners_command_test.exs b/deps/rabbitmq_cli/test/ctl/resume_listeners_command_test.exs
new file mode 100644
index 0000000000..3aad0b355b
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/resume_listeners_command_test.exs
@@ -0,0 +1,67 @@
+## The contents of this file are subject to the Mozilla Public License
+## Version 1.1 (the "License"); you may not use this file except in
+## compliance with the License. You may obtain a copy of the License
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule ResumeListenersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ResumeListenersCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ resume_all_client_listeners()
+
+ node_name = get_rabbit_hostname()
+ on_exit(fn ->
+ resume_all_client_listeners()
+ close_all_connections(node_name)
+ end)
+
+ {:ok, opts: %{node: node_name, timeout: 30_000}}
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "merge_defaults: merges no defaults" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: accepts no arguments", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "run: resumes all client TCP listeners so new client connects are accepted", context do
+ suspend_all_client_listeners()
+ expect_client_connection_failure()
+
+ assert @command.run([], Map.merge(context[:opts], %{timeout: 5_000})) == :ok
+
+ # implies a successful connection
+ with_channel("/", fn _ -> :ok end)
+ close_all_connections(get_rabbit_hostname())
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/rotate_logs_command_test.exs b/deps/rabbitmq_cli/test/ctl/rotate_logs_command_test.exs
new file mode 100644
index 0000000000..13eed87d43
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/rotate_logs_command_test.exs
@@ -0,0 +1,40 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule RotateLogsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.RotateLogsCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([], context[:opts]) == :ok
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Rotating logs for node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_cluster_name_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_cluster_name_command_test.exs
new file mode 100644
index 0000000000..a0852522e4
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_cluster_name_command_test.exs
@@ -0,0 +1,63 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetClusterNameCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetClusterNameCommand
+
+ setup_all do
+ :net_kernel.start([:rabbitmqctl, :shortnames])
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "shows up in help" do
+ s = @command.usage()
+ assert s =~ ~r/set_cluster_name/
+ end
+
+ test "has no defaults" do
+ assert @command.merge_defaults(["foo"], %{bar: "baz"}) == {["foo"], %{bar: "baz"}}
+ end
+
+ test "validate: with insufficient number of arguments, return arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: with too many arguments, return arg count error" do
+ assert @command.validate(["foo", "bar"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: with correct number of arguments, return ok" do
+ assert @command.validate(["mynewname"], %{}) == :ok
+ end
+
+ test "run: valid name returns ok", context do
+ s = get_cluster_name()
+ assert @command.run(["agoodname"], context[:opts]) == :ok
+ # restore original name
+ @command.run([s], context[:opts])
+ end
+
+ test "run: An invalid Rabbit node returns a bad rpc message" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(["clustername"], opts))
+ end
+
+ test "banner shows that the name is being set" do
+ s = @command.banner(["annoyyou"], %{})
+ assert s == "Setting cluster name to annoyyou ..."
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_disk_free_limit_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_disk_free_limit_command_test.exs
new file mode 100644
index 0000000000..80f0e1511f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_disk_free_limit_command_test.exs
@@ -0,0 +1,173 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetDiskFreeLimitCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand
+
+ @default_limit 1048576
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ set_disk_free_limit(@default_limit)
+
+ on_exit([], fn ->
+ set_disk_free_limit(@default_limit)
+ end)
+
+ end
+
+ setup context do
+ context[:tag] # silences warnings
+ on_exit([], fn -> set_disk_free_limit(@default_limit) end)
+
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: an invalid number of arguments results in arg count errors" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag limit: "2097152bytes"
+ test "run: an invalid string input returns a bad arg and does not change the limit", context do
+ assert @command.validate([context[:limit]], context[:opts]) ==
+ {:validation_failure, :bad_argument}
+ end
+
+ test "validate: valid fractional inputs return an ok", context do
+ assert @command.validate(
+ ["mem_relative", "0.0"],
+ context[:opts]
+ ) == :ok
+
+ assert @command.validate(
+ ["mem_relative", "0.5"],
+ context[:opts]
+ ) == :ok
+
+ assert @command.validate(
+ ["mem_relative", "1.8"],
+ context[:opts]
+ ) == :ok
+ end
+
+ test "validate: a value outside the accepted range returns an error", context do
+ assert @command.validate(
+ ["mem_relative", "-1.0"],
+ context[:opts]
+ ) == {:validation_failure, :bad_argument}
+ end
+
+ @tag fraction: "1.3"
+ test "validate: a valid float string input returns ok", context do
+ assert @command.validate(
+ ["mem_relative", context[:fraction]],
+ context[:opts]
+ ) == :ok
+ end
+
+ @tag fraction: "1.3salt"
+ test "validate: an invalid string input returns a bad argument", context do
+ assert @command.validate(
+ ["mem_relative", context[:fraction]],
+ context[:opts]
+ ) == {:validation_failure, :bad_argument}
+ end
+
+## ------------------------ validate mem_relative command -------------------------------------------
+
+ test "validate: an invalid number of mem_relative arguments results in an arg count error" do
+ assert @command.validate(["mem_relative"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["mem_relative", 1.3, "extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+
+## ------------------------ run absolute command -------------------------------------------
+
+ @tag test_timeout: 3000
+ test "run: an invalid node returns a bad rpc" do
+ args = [@default_limit]
+ opts = %{node: :jake@thedog}
+
+ assert match?({:badrpc, _}, @command.run(args, opts))
+ end
+
+ @tag limit: 2097152
+ test "run: a valid integer input returns an ok and sets the disk free limit", context do
+ assert @command.run([context[:limit]], context[:opts]) == :ok
+ assert status()[:disk_free_limit] === context[:limit]
+ end
+
+ @tag limit: 2097152.0
+ test "run: a valid non-fractional float input returns an ok and sets the disk free limit", context do
+ assert @command.run([context[:limit]], context[:opts]) == :ok
+ assert status()[:disk_free_limit] === round(context[:limit])
+ end
+
+ @tag limit: 2097152.9
+ test "run: a valid fractional float input returns an ok and sets the disk free limit", context do
+ assert @command.run([context[:limit]], context[:opts]) == :ok
+ assert status()[:disk_free_limit] === context[:limit] |> Float.floor |> round
+ end
+
+ @tag limit: "2097152"
+ test "run: an integer string input returns an ok and sets the disk free limit", context do
+ assert @command.run([context[:limit]], context[:opts]) == :ok
+ assert status()[:disk_free_limit] === String.to_integer(context[:limit])
+ end
+
+ @tag limit: "2MB"
+ test "run: an valid unit string input returns an ok and changes the limit", context do
+ assert @command.run([context[:limit]], context[:opts]) == :ok
+ assert status()[:disk_free_limit] === 2000000
+ end
+
+## ------------------------ run relative command -------------------------------------------
+
+ @tag fraction: 1
+ test "run: an integer input returns ok", context do
+ assert @command.run(
+ ["mem_relative", context[:fraction]],
+ context[:opts]
+ ) == :ok
+ end
+
+ @tag fraction: 1.1
+ test "run: a factional input returns ok", context do
+ assert @command.run(
+ ["mem_relative", context[:fraction]],
+ context[:opts]
+ ) == :ok
+ end
+
+
+ test "banner: returns absolute message", context do
+ assert @command.banner(["10"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to 10 bytes .../
+
+ assert @command.banner(["-10"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to -10 bytes .../
+
+ assert @command.banner(["sandwich"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to sandwich bytes .../
+ end
+
+ test "banner: returns memory-relative message", context do
+ assert @command.banner(["mem_relative", "1.3"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to 1\.3 times the total RAM \.\.\./
+
+ assert @command.banner(["mem_relative", "-1.3"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to -1\.3 times the total RAM \.\.\./
+
+ assert @command.banner(["mem_relative", "sandwich"], context[:opts])
+ =~ ~r/Setting disk free limit on #{get_rabbit_hostname()} to sandwich times the total RAM \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_global_parameter_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_global_parameter_command_test.exs
new file mode 100644
index 0000000000..848f29a0b8
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_global_parameter_command_test.exs
@@ -0,0 +1,82 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetGlobalParameterCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetGlobalParameterCommand
+
+ @key :mqtt_default_vhosts
+ @value "{\"O=client,CN=dummy\":\"somevhost\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_global_parameter context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ }
+ }
+ end
+
+ test "validate: expects a key and a value" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag key: @key, value: @value
+ test "run: expects a key and a value", context do
+ assert @command.run(
+ [context[:key], context[:value]],
+ context[:opts]
+ ) == :ok
+
+ assert_parameter_fields(context)
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@key, @value], opts))
+ end
+
+ @tag key: @key, value: "bad-value"
+ test "run: a value that fails to parse as JSON returns a decoding error", context do
+ initial = list_global_parameters()
+ assert match?({:error_string, _},
+ @command.run([context[:key], context[:value]],
+ context[:opts]))
+
+ assert list_global_parameters() == initial
+ end
+
+ @tag key: @key, value: @value
+ test "banner", context do
+ assert @command.banner([context[:key], context[:value]], context[:opts])
+ =~ ~r/Setting global runtime parameter \"#{context[:key]}\" to \"#{context[:value]}\" \.\.\./
+ end
+
+ # Checks each element of the first parameter against the expected context values
+ defp assert_parameter_fields(context) do
+ result_param = list_global_parameters() |> List.first
+
+ assert result_param[:value] == context[:value]
+ assert result_param[:name] == context[:key]
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_log_level_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_log_level_command_test.exs
new file mode 100644
index 0000000000..b4108219ba
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_log_level_command_test.exs
@@ -0,0 +1,44 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule SetLogLevelCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetLogLevelCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ {:ok,
+ log_level: "debug",
+ opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with a single known level succeeds", context do
+ assert @command.validate([context[:log_level]], context[:opts]) == :ok
+ end
+
+ test "validate: with a single unsupported level fails", context do
+ assert match?({:error, _}, @command.validate(["lolwut"], context[:opts]))
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate([context[:log_level], "whoops"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([context[:log_level]], context[:opts]) == :ok
+ end
+
+ test "run: request to a non-existent node returns a badrpc", context do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([context[:log_level]], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([context[:log_level]], context[:opts]) == "Setting log level to \"debug\" ..."
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_operator_policy_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_operator_policy_command_test.exs
new file mode 100644
index 0000000000..5911132a32
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_operator_policy_command_test.exs
@@ -0,0 +1,153 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetOperatorPolicyCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetOperatorPolicyCommand
+
+ @vhost "test1"
+ @root "/"
+ @key "message-expiry"
+ @pattern "^queue\."
+ @value "{\"message-ttl\":10}"
+ @apply_to "all"
+ @priority 0
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ on_exit(context, fn ->
+ clear_operator_policy(context[:vhost], context[:key])
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: "/",
+ apply_to: @apply_to,
+ priority: @priority
+ }
+ }
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @root
+ test "merge_defaults: a well-formed command with no vhost runs against the default" do
+ assert match?({_, %{vhost: "/"}}, @command.merge_defaults([], %{}))
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert match?({[], %{vhost: "test_vhost"}}, @command.merge_defaults([], %{vhost: "test_vhost"}))
+ end
+
+ test "merge_defaults: default apply_to is \"all\"" do
+ assert match?({_, %{apply_to: "all"}}, @command.merge_defaults([], %{}))
+ assert match?({_, %{apply_to: "custom"}}, @command.merge_defaults([], %{apply_to: "custom"}))
+ end
+
+ test "merge_defaults: default priority is 0" do
+ assert match?({_, %{priority: 0}}, @command.merge_defaults([], %{}))
+ assert match?({_, %{priority: 3}}, @command.merge_defaults([], %{priority: 3}))
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns okay", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ vhost_opts
+ ) == :ok
+
+ assert_operator_policy_fields(context)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", priority: 0, apply_to: "all", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@key, @pattern, @value], opts))
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: providing a non-existent vhost reports an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag pattern: @pattern, key: @key, value: "bad-value", vhost: @root
+ test "run: an invalid value returns a JSON decoding error", context do
+ assert match?({:error_string, _},
+ @command.run([context[:key], context[:pattern], context[:value]],
+ context[:opts]))
+
+ assert list_operator_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: "{\"foo\":\"bar\"}", vhost: @root
+ test "run: invalid policy returns an error", context do
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\n[{<<"foo">>,<<"bar">>}] are not recognised policy settings\n'}
+
+ assert list_operator_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: "{}", vhost: @root
+ test "run: an empty JSON object value returns an error", context do
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\nno policy provided\n'}
+
+ assert list_operator_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:key], context[:pattern], context[:value]], vhost_opts)
+ == "Setting operator policy override \"#{context[:key]}\" for pattern \"#{context[:pattern]}\" to \"#{context[:value]}\" with priority \"#{context[:opts][:priority]}\" for vhost \"#{context[:vhost]}\" \.\.\."
+ end
+
+ # Checks each element of the first policy against the expected context values
+ defp assert_operator_policy_fields(context) do
+ result_policy = context[:vhost] |> list_operator_policies |> List.first
+ assert result_policy[:definition] == context[:value]
+ assert result_policy[:vhost] == context[:vhost]
+ assert result_policy[:pattern] == context[:pattern]
+ assert result_policy[:name] == context[:key]
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_parameter_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_parameter_command_test.exs
new file mode 100644
index 0000000000..50a2543dee
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_parameter_command_test.exs
@@ -0,0 +1,136 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetParameterCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetParameterCommand
+
+ @vhost "test1"
+ @root "/"
+ @component_name "federation-upstream"
+ @key "reconnect-delay"
+ @value "{\"uri\":\"amqp://127.0.0.1:5672\"}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ enable_federation_plugin()
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ # featured in a definitions file imported by other tests
+ clear_parameter("/", "federation-upstream", "up-1")
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn ->
+ clear_parameter context[:vhost], context[:component_name], context[:key]
+ end)
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: context[:vhost]
+ }
+ }
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @root
+ test "merge_defaults: a well-formed command with no vhost runs against the default" do
+ assert match?({_, %{vhost: "/"}}, @command.merge_defaults([], %{}))
+ assert match?({_, %{vhost: "non_default"}}, @command.merge_defaults([], %{vhost: "non_default"}))
+ end
+
+ test "validate: wrong number of arguments leads to an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns okay", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:component_name], context[:key], context[:value]],
+ vhost_opts
+ ) == :ok
+
+ assert_parameter_fields(context)
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@component_name, @key, @value], opts))
+ end
+
+ @tag component_name: "bad-component-name", key: @key, value: @value, vhost: @root
+ test "run: an invalid component_name returns a validation failed error", context do
+ assert @command.run(
+ [context[:component_name], context[:key], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\ncomponent #{context[:component_name]} not found\n'}
+
+ assert list_parameters(context[:vhost]) == []
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: an invalid vhost returns a no-such-vhost error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:component_name], context[:key], context[:value]],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag component_name: @component_name, key: @key, value: "bad-value", vhost: @root
+ test "run: an invalid value returns a JSON decoding error", context do
+ assert match?({:error_string, _},
+ @command.run([context[:component_name], context[:key], context[:value]],
+ context[:opts]))
+
+ assert list_parameters(context[:vhost]) == []
+ end
+
+ @tag component_name: @component_name, key: @key, value: "{}", vhost: @root
+ test "run: an empty JSON object value returns a key \"uri\" not found error", context do
+ assert @command.run(
+ [context[:component_name], context[:key], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\nKey "uri" not found in reconnect-delay\n'}
+
+ assert list_parameters(context[:vhost]) == []
+ end
+
+ @tag component_name: @component_name, key: @key, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:component_name], context[:key], context[:value]], vhost_opts)
+ =~ ~r/Setting runtime parameter \"#{context[:key]}\" for component \"#{context[:component_name]}\" to \"#{context[:value]}\" in vhost \"#{context[:vhost]}\" \.\.\./
+ end
+
+ # Checks each element of the first parameter against the expected context values
+ defp assert_parameter_fields(context) do
+ result_param = context[:vhost] |> list_parameters |> List.first
+
+ assert result_param[:value] == context[:value]
+ assert result_param[:component] == context[:component_name]
+ assert result_param[:name] == context[:key]
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs
new file mode 100644
index 0000000000..c2628f2728
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs
@@ -0,0 +1,114 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetPermissionsCommand
+
+ @vhost "test1"
+ @user "guest"
+ @root "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ on_exit(context, fn ->
+ set_permissions context[:user], context[:vhost], [".*", ".*", ".*"]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: context[:vhost]
+ }
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: wrong number of arguments leads to an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "quite", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this", "is", "way", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag user: @user, vhost: @vhost
+ test "run: a well-formed, host-specific command returns okay", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:user], "^#{context[:user]}-.*", ".*", ".*"],
+ vhost_opts
+ ) == :ok
+
+ u = Enum.find(list_permissions(context[:vhost]), fn(x) -> x[:user] == context[:user] end)
+ assert u[:configure] == "^#{context[:user]}-.*"
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@user, ".*", ".*", ".*"], opts))
+ end
+
+ @tag user: "interloper", vhost: @root
+ test "run: an invalid user returns a no-such-user error", context do
+ assert @command.run(
+ [context[:user], "^#{context[:user]}-.*", ".*", ".*"],
+ context[:opts]
+ ) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ @tag user: @user, vhost: "wintermute"
+ test "run: an invalid vhost returns a no-such-vhost error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:user], "^#{context[:user]}-.*", ".*", ".*"],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag user: @user, vhost: @root
+ test "run: invalid regex patterns returns an error", context do
+ assert @command.run(
+ [context[:user], "^#{context[:user]}-.*", ".*", "*"],
+ context[:opts]
+ ) == {:error, {:invalid_regexp, '*', {'nothing to repeat', 0}}}
+
+ # asserts that the failed command didn't change anything
+ u = Enum.find(list_permissions(context[:vhost]), fn(x) -> x[:user] == context[:user] end)
+ assert u == [user: context[:user], configure: ".*", write: ".*", read: ".*"]
+ end
+
+ @tag user: @user, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:user], "^#{context[:user]}-.*", ".*", ".*"], vhost_opts)
+ =~ ~r/Setting permissions for user \"#{context[:user]}\" in vhost \"#{context[:vhost]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_policy_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_policy_command_test.exs
new file mode 100644
index 0000000000..0422933ecb
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_policy_command_test.exs
@@ -0,0 +1,217 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetPolicyCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetPolicyCommand
+
+ @vhost "test1"
+ @root "/"
+ @key "federate"
+ @pattern "^fed\."
+ @value "{\"federation-upstream-set\":\"all\"}"
+ @apply_to "all"
+ @priority 0
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ enable_federation_plugin()
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ on_exit(context, fn ->
+ clear_policy context[:vhost], context[:key]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: "/",
+ apply_to: @apply_to,
+ priority: @priority
+ }
+ }
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @root
+ test "merge_defaults: a well-formed command with no vhost runs against the default" do
+ assert match?({_, %{vhost: "/"}}, @command.merge_defaults([], %{}))
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert match?({[], %{vhost: "test_vhost"}}, @command.merge_defaults([], %{vhost: "test_vhost"}))
+ end
+
+ test "merge_defaults: default apply_to is \"all\"" do
+ assert match?({_, %{apply_to: "all"}}, @command.merge_defaults([], %{}))
+ assert match?({_, %{apply_to: "custom"}}, @command.merge_defaults([], %{apply_to: "custom"}))
+ end
+
+ test "merge_defaults: default priority is 0" do
+ assert match?({_, %{priority: 0}}, @command.merge_defaults([], %{}))
+ assert match?({_, %{priority: 3}}, @command.merge_defaults([], %{priority: 3}))
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @vhost
+ test "run: a well-formed, host-specific command returns okay", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ vhost_opts
+ ) == :ok
+
+ assert_policy_fields(context)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", priority: 0, apply_to: "all", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@key, @pattern, @value], opts))
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: "bad-vhost"
+ test "run: providing a non-existent vhost reports an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ @tag pattern: @pattern, key: @key, value: "bad-value", vhost: @root
+ test "run: an invalid value returns a JSON decoding error", context do
+ assert match?({:error_string, _},
+ @command.run([context[:key], context[:pattern], context[:value]],
+ context[:opts]))
+
+ assert list_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: "{\"foo\":\"bar\"}", vhost: @root
+ test "run: invalid policy returns an error", context do
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\n[{<<"foo">>,<<"bar">>}] are not recognised policy settings\n'}
+
+ assert list_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: "{}", vhost: @root
+ test "run: an empty JSON object value returns an error", context do
+ assert @command.run(
+ [context[:key], context[:pattern], context[:value]],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\nno policy provided\n'}
+
+ assert list_policies(context[:vhost]) == []
+ end
+
+ @tag pattern: @pattern, key: @key, value: @value, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:key], context[:pattern], context[:value]], vhost_opts)
+ == "Setting policy \"#{context[:key]}\" for pattern \"#{context[:pattern]}\" to \"#{context[:value]}\" with priority \"#{context[:opts][:priority]}\" for vhost \"#{context[:vhost]}\" \.\.\."
+ end
+
+ @tag pattern: "ha_", key: "ha_policy_test", vhost: @vhost
+ test "ha policy validation", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ context = Map.put(context, :opts, vhost_opts)
+ pass_validation(context, "{\"ha-mode\":\"all\"}")
+ fail_validation(context, "{\"ha-mode\":\"made_up\"}")
+
+ fail_validation(context, "{\"ha-mode\":\"nodes\"}")
+ fail_validation(context, "{\"ha-mode\":\"nodes\",\"ha-params\":2}")
+ fail_validation(context, "{\"ha-mode\":\"nodes\",\"ha-params\":[\"a\",2]}")
+ pass_validation(context, "{\"ha-mode\":\"nodes\",\"ha-params\":[\"a\",\"b\"]}")
+ fail_validation(context, "{\"ha-params\":[\"a\",\"b\"]}")
+
+ fail_validation(context, "{\"ha-mode\":\"exactly\"}")
+ fail_validation(context, "{\"ha-mode\":\"exactly\",\"ha-params\":[\"a\",\"b\"]}")
+ pass_validation(context, "{\"ha-mode\":\"exactly\",\"ha-params\":2}")
+ fail_validation(context, "{\"ha-params\":2}")
+
+ pass_validation(context, "{\"ha-mode\":\"all\",\"ha-sync-mode\":\"manual\"}")
+ pass_validation(context, "{\"ha-mode\":\"all\",\"ha-sync-mode\":\"automatic\"}")
+ fail_validation(context, "{\"ha-mode\":\"all\",\"ha-sync-mode\":\"made_up\"}")
+ fail_validation(context, "{\"ha-sync-mode\":\"manual\"}")
+ fail_validation(context, "{\"ha-sync-mode\":\"automatic\"}")
+ end
+
+ @tag pattern: "ha_", key: "ha_policy_test", vhost: @vhost
+ test "queue master locator policy validation", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ context = Map.put(context, :opts, vhost_opts)
+ pass_validation(context, "{\"queue-master-locator\":\"min-masters\"}")
+ pass_validation(context, "{\"queue-master-locator\":\"client-local\"}")
+ pass_validation(context, "{\"queue-master-locator\":\"random\"}")
+ fail_validation(context, "{\"queue-master-locator\":\"made_up\"}")
+ end
+
+ @tag pattern: "ha_", key: "ha_policy_test", vhost: @vhost
+ test "queue modes policy validation", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+ context = Map.put(context, :opts, vhost_opts)
+ pass_validation(context, "{\"queue-mode\":\"lazy\"}")
+ pass_validation(context, "{\"queue-mode\":\"default\"}")
+ fail_validation(context, "{\"queue-mode\":\"wrong\"}")
+ end
+
+ def pass_validation(context, value) do
+ assert @command.run(
+ [context[:key], context[:pattern], value],
+ context[:opts]
+ ) == :ok
+ assert_policy_fields(Map.merge(context, %{value: value}))
+ end
+
+ def fail_validation(context, value) do
+ result = @command.run(
+ [context[:key], context[:pattern], value],
+ context[:opts]
+ )
+ assert {:error_string, _} = result
+ {:error_string, msg} = result
+ assert "Validation failed"<>_ = to_string(msg)
+ end
+
+ # Checks each element of the first policy against the expected context values
+ defp assert_policy_fields(context) do
+ result_policy = context[:vhost] |> list_policies |> List.first
+ assert result_policy[:definition] == context[:value]
+ assert result_policy[:vhost] == context[:vhost]
+ assert result_policy[:pattern] == context[:pattern]
+ assert result_policy[:name] == context[:key]
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_topic_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_topic_permissions_command_test.exs
new file mode 100644
index 0000000000..f117f5a789
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_topic_permissions_command_test.exs
@@ -0,0 +1,114 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetTopicPermissionsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetTopicPermissionsCommand
+
+ @vhost "test1"
+ @user "guest"
+ @root "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ on_exit(context, fn ->
+ clear_topic_permissions context[:user], context[:vhost]
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: context[:vhost]
+ }
+ }
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: expects username, exchange, and pattern arguments" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["insufficient"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["still", "not", "enough"], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["this", "is", "way", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ @tag user: @user, vhost: @vhost
+ test "run: a well-formed, host-specific command returns okay", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:user], "amq.topic", "^a", "^b"],
+ vhost_opts
+ ) == :ok
+
+ assert List.first(list_user_topic_permissions(context[:user]))[:write] == "^a"
+ assert List.first(list_user_topic_permissions(context[:user]))[:read] == "^b"
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@user, "amq.topic", "^a", "^b"], opts))
+ end
+
+ @tag user: "interloper", vhost: @root
+ test "run: an invalid user returns a no-such-user error", context do
+ assert @command.run(
+ [context[:user], "amq.topic", "^a", "^b"],
+ context[:opts]
+ ) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ @tag user: @user, vhost: "wintermute"
+ test "run: an invalid vhost returns a no-such-vhost error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:user], "amq.topic", "^a", "^b"],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+
+ assert Enum.count(list_user_topic_permissions(context[:user])) == 0
+ end
+
+ @tag user: @user, vhost: @root
+ test "run: invalid regex patterns return error", context do
+ n = Enum.count(list_user_topic_permissions(context[:user]))
+ {:error, {:invalid_regexp, _, _}} = @command.run(
+ [context[:user], "amq.topic", "[", "^b"],
+ context[:opts]
+ )
+ assert Enum.count(list_user_topic_permissions(context[:user])) == n
+ end
+
+ @tag user: @user, vhost: @vhost
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:user], "amq.topic", "^a", "^b"], vhost_opts)
+ =~ ~r/Setting topic permissions on \"amq.topic\" for user \"#{context[:user]}\" in vhost \"#{context[:vhost]}\" \.\.\./
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_user_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_user_limits_command_test.exs
new file mode 100644
index 0000000000..6179267396
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_user_limits_command_test.exs
@@ -0,0 +1,137 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule SetUserLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetUserLimitsCommand
+
+ @user "someone"
+ @password "password"
+ @conn_definition "{\"max-connections\":100}"
+ @channel_definition "{\"max-channels\":200}"
+ @definition "{\"max-connections\":50, \"max-channels\":500}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_user @user, @password
+
+ on_exit([], fn ->
+ delete_user @user
+ end)
+
+ :ok
+ end
+
+ setup context do
+ user = context[:user] || @user
+
+ clear_user_limits(user)
+
+ on_exit(context, fn ->
+ clear_user_limits(user)
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname()
+ },
+ user: user
+ }
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["not-enough"], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: a well-formed, host-specific command returns okay", context do
+ assert @command.run(
+ [context[:user],
+ @conn_definition],
+ context[:opts]
+ ) == :ok
+
+ assert_limits(context, @conn_definition)
+ clear_user_limits(context[:user])
+
+ assert @command.run(
+ [context[:user],
+ @channel_definition],
+ context[:opts]
+ ) == :ok
+
+ assert_limits(context, @channel_definition)
+ end
+
+ test "run: a well-formed command to set both max-connections and max-channels returns okay", context do
+ assert @command.run(
+ [context[:user],
+ @definition],
+ context[:opts]
+ ) == :ok
+
+ assert_limits(context, @definition)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@user, @conn_definition], opts))
+ end
+
+ @tag user: "non-existent-user"
+ test "run: providing a non-existent user reports an error", context do
+
+ assert @command.run(
+ [context[:user],
+ @conn_definition],
+ context[:opts]
+ ) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ test "run: an invalid definition returns a JSON decoding error", context do
+ assert match?({:error_string, _},
+ @command.run(
+ [context[:user],
+ ["this_is_not_json"]],
+ context[:opts]))
+
+ assert get_user_limits(context[:user]) == %{}
+ end
+
+ test "run: invalid limit returns an error", context do
+ assert @command.run(
+ [context[:user],
+ "{\"foo\":\"bar\"}"],
+ context[:opts]
+ ) == {:error_string, 'Unrecognised terms [{<<"foo">>,<<"bar">>}] in user-limits'}
+
+ assert get_user_limits(context[:user]) == %{}
+ end
+
+ test "banner", context do
+ assert @command.banner([context[:user], context[:conn_definition]], context[:opts])
+ == "Setting user limits to \"#{context[:conn_definition]}\" for user \"#{context[:user]}\" ..."
+ end
+
+ #
+ # Implementation
+ #
+
+ defp assert_limits(context, definition) do
+ limits = get_user_limits(context[:user])
+ assert {:ok, limits} == JSON.decode(definition)
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_user_tags_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_user_tags_command_test.exs
new file mode 100644
index 0000000000..cdc51e673f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_user_tags_command_test.exs
@@ -0,0 +1,144 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetUserTagsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetUserTagsCommand
+
+ @user "user1"
+ @password "password"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_user @user, @password
+
+ on_exit([], fn ->
+ delete_user(@user)
+ end)
+
+ :ok
+ end
+
+ setup context do
+ context[:user] # silences warnings
+ on_exit([], fn -> set_user_tags(context[:user], []) end)
+
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: on an incorrect number of arguments, return an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@user, :imperator], opts))
+ end
+
+ @tag user: @user, tags: [:imperator]
+ test "run: on a single optional argument, add a flag to the user", context do
+ @command.run(
+ [context[:user] | context[:tags]],
+ context[:opts]
+ )
+
+ result = Enum.find(
+ list_users(),
+ fn(record) -> record[:user] == context[:user] end
+ )
+
+ assert result[:tags] == context[:tags]
+ end
+
+ @tag user: "interloper", tags: [:imperator]
+ test "run: on an invalid user, get a no such user error", context do
+ assert @command.run(
+ [context[:user] | context[:tags]],
+ context[:opts]
+ ) == {:error, {:no_such_user, context[:user]}}
+ end
+
+ @tag user: @user, tags: [:imperator, :generalissimo]
+ test "run: on multiple optional arguments, add all flags to the user", context do
+ @command.run(
+ [context[:user] | context[:tags]],
+ context[:opts]
+ )
+
+ result = Enum.find(
+ list_users(),
+ fn(record) -> record[:user] == context[:user] end
+ )
+
+ assert result[:tags] == context[:tags]
+ end
+
+ @tag user: @user, tags: [:imperator]
+ test "run: with no optional arguments, clear user tags", context do
+
+ set_user_tags(context[:user], context[:tags])
+
+ @command.run([context[:user]], context[:opts])
+
+ result = Enum.find(
+ list_users(),
+ fn(record) -> record[:user] == context[:user] end
+ )
+
+ assert result[:tags] == []
+ end
+
+ @tag user: @user, tags: [:imperator]
+ test "run: identical calls are idempotent", context do
+
+ set_user_tags(context[:user], context[:tags])
+
+ assert @command.run(
+ [context[:user] | context[:tags]],
+ context[:opts]
+ ) == :ok
+
+ result = Enum.find(
+ list_users(),
+ fn(record) -> record[:user] == context[:user] end
+ )
+
+ assert result[:tags] == context[:tags]
+ end
+
+ @tag user: @user, old_tags: [:imperator], new_tags: [:generalissimo]
+ test "run: if different tags exist, overwrite them", context do
+
+ set_user_tags(context[:user], context[:old_tags])
+
+ assert @command.run(
+ [context[:user] | context[:new_tags]],
+ context[:opts]
+ ) == :ok
+
+ result = Enum.find(
+ list_users(),
+ fn(record) -> record[:user] == context[:user] end
+ )
+
+ assert result[:tags] == context[:new_tags]
+ end
+
+ @tag user: @user, tags: ["imperator"]
+ test "banner", context do
+ assert @command.banner(
+ [context[:user] | context[:tags]],
+ context[:opts]
+ )
+ =~ ~r/Setting tags for user \"#{context[:user]}\" to \[#{context[:tags]}\] \.\.\./
+ end
+
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_vhost_limits_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_vhost_limits_command_test.exs
new file mode 100644
index 0000000000..b5c679b02f
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_vhost_limits_command_test.exs
@@ -0,0 +1,137 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule SetVhostLimitsCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetVhostLimitsCommand
+
+ @vhost "test1"
+ @definition "{\"max-connections\":100}"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost @vhost
+
+ on_exit([], fn ->
+ delete_vhost @vhost
+ end)
+
+ :ok
+ end
+
+ setup context do
+
+ vhost = context[:vhost] || @vhost
+
+ clear_vhost_limits(vhost)
+
+ on_exit(context, fn ->
+ clear_vhost_limits(vhost)
+ end)
+
+ {
+ :ok,
+ opts: %{
+ node: get_rabbit_hostname(),
+ vhost: vhost
+ },
+ definition: context[:definition] || @definition,
+ vhost: vhost
+ }
+ end
+
+ test "merge_defaults: a well-formed command with no vhost runs against the default" do
+ assert match?({_, %{vhost: "/"}}, @command.merge_defaults([], %{}))
+ end
+
+ test "merge_defaults: does not change defined vhost" do
+ assert match?({[], %{vhost: "test_vhost"}}, @command.merge_defaults([], %{vhost: "test_vhost"}))
+ end
+
+ test "validate: providing too few arguments fails validation" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation" do
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ assert @command.validate(["this", "is", "too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: a well-formed, host-specific command returns okay", context do
+ assert @command.run(
+ [context[:definition]],
+ context[:opts]
+ ) == :ok
+
+ assert_limits(context)
+ end
+
+ test "run: an unreachable node throws a badrpc" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([@definition], opts))
+ end
+
+ @tag vhost: "bad-vhost"
+ test "run: providing a non-existent vhost reports an error", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.run(
+ [context[:definition]],
+ vhost_opts
+ ) == {:error, {:no_such_vhost, context[:vhost]}}
+ end
+
+ test "run: an invalid definition returns a JSON decoding error", context do
+ assert match?({:error_string, _},
+ @command.run(["bad_value"], context[:opts]))
+
+ assert get_vhost_limits(context[:vhost]) == %{}
+ end
+
+ test "run: invalid limit returns an error", context do
+ assert @command.run(
+ ["{\"foo\":\"bar\"}"],
+ context[:opts]
+ ) == {:error_string, 'Validation failed\n\nUnrecognised terms [{<<"foo">>,<<"bar">>}] in limits\n'}
+
+ assert get_vhost_limits(context[:vhost]) == %{}
+ end
+
+ test "run: an empty JSON object definition unsets all limits for vhost", context do
+
+ assert @command.run(
+ [@definition],
+ context[:opts]
+ ) == :ok
+
+ assert_limits(context)
+
+ assert @command.run(
+ ["{}"],
+ context[:opts]
+ ) == :ok
+
+ assert get_vhost_limits(context[:vhost]) == %{}
+ end
+
+ test "banner", context do
+ vhost_opts = Map.merge(context[:opts], %{vhost: context[:vhost]})
+
+ assert @command.banner([context[:definition]], vhost_opts)
+ == "Setting vhost limits to \"#{context[:definition]}\" for vhost \"#{context[:vhost]}\" ..."
+ end
+
+ defp assert_limits(context) do
+ limits = get_vhost_limits(context[:vhost])
+ assert {:ok, limits} == JSON.decode(context[:definition])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/set_vm_memory_high_watermark_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_vm_memory_high_watermark_command_test.exs
new file mode 100644
index 0000000000..bd9719ab40
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/set_vm_memory_high_watermark_command_test.exs
@@ -0,0 +1,162 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule SetVmMemoryHighWatermarkCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+ import RabbitMQ.CLI.Core.{Alarms, Memory}
+
+ @command RabbitMQ.CLI.Ctl.Commands.SetVmMemoryHighWatermarkCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ start_rabbitmq_app()
+ reset_vm_memory_high_watermark()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ reset_vm_memory_high_watermark()
+ end)
+
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: a string returns an error", context do
+ assert @command.validate(["sandwich"], context[:opts]) == {:validation_failure, :bad_argument}
+ assert @command.validate(["0.4sandwich"], context[:opts]) == {:validation_failure, :bad_argument}
+ end
+
+ test "validate: valid numerical value returns valid", context do
+ assert @command.validate(["0.7"], context[:opts]) == :ok
+ assert @command.validate(["1"], context[:opts]) == :ok
+ end
+
+ test "run: valid numerical value returns valid", context do
+ assert @command.run([0.7], context[:opts]) == :ok
+ assert status()[:vm_memory_high_watermark] == 0.7
+
+ assert @command.run([1], context[:opts]) == :ok
+ assert status()[:vm_memory_high_watermark] == 1
+ end
+
+ test "validate: validate a valid numerical string value returns valid", context do
+ assert @command.validate(["0.7"], context[:opts]) == :ok
+ assert @command.validate(["1"], context[:opts]) == :ok
+ end
+
+ test "validate: the wrong number of arguments returns an arg count error" do
+ assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
+ assert @command.validate(["too", "many"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: a negative number returns a bad argument", context do
+ assert @command.validate(["-0.1"], context[:opts]) == {:validation_failure, {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}}
+ end
+
+ test "validate: a percentage returns a bad argument", context do
+ assert @command.validate(["40"], context[:opts]) == {:validation_failure, {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}}
+ end
+
+ test "validate: a value greater than 1.0 returns a bad argument", context do
+ assert @command.validate(["1.1"], context[:opts]) == {:validation_failure, {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}}
+ end
+
+ @tag test_timeout: 3000
+ test "run: on an invalid node, return a bad rpc" do
+ args = [0.7]
+ opts = %{node: :jake@thedog, timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run(args, opts))
+ end
+
+## ---------------------------- Absolute tests --------------------------------
+
+ test "validate: an absolute call without an argument returns not enough args" do
+ assert @command.validate(["absolute"], %{}) == {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: an absolute call with too many arguments returns too many args" do
+ assert @command.validate(["absolute", "too", "many"], %{}) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: a single absolute integer return valid", context do
+ assert @command.validate(["absolute","10"], context[:opts]) == :ok
+ end
+ test "run: a single absolute integer return ok", context do
+ assert @command.run(["absolute","10"], context[:opts]) == :ok
+ assert status()[:vm_memory_high_watermark] == {:absolute, memory_unit_absolute(10, "")}
+ end
+
+ test "validate: a single absolute integer with an invalid memory unit fails ", context do
+ assert @command.validate(["absolute","10bytes"], context[:opts]) == {:validation_failure, {:bad_argument, "Invalid units."}}
+ end
+
+ test "validate: a single absolute float with a valid memory unit fails ", context do
+ assert @command.validate(["absolute","10.0MB"], context[:opts]) == {:validation_failure, {:bad_argument, "The threshold should be an integer."}}
+ end
+
+ test "validate: a single absolute float with an invalid memory unit fails ", context do
+ assert @command.validate(["absolute","10.0bytes"], context[:opts]) == {:validation_failure, {:bad_argument, "The threshold should be an integer."}}
+ end
+
+ test "validate: a single absolute string fails ", context do
+ assert @command.validate(["absolute","large"], context[:opts]) == {:validation_failure, :bad_argument}
+ end
+
+ test "validate: a single absolute string with a valid unit fails ", context do
+ assert @command.validate(["absolute","manyGB"], context[:opts]) == {:validation_failure, :bad_argument}
+ end
+
+ test "run: a single absolute integer with memory units return ok", context do
+ memory_units()
+ |> Enum.each(fn mu ->
+ arg = "10#{mu}"
+ assert @command.run(["absolute",arg], context[:opts]) == :ok
+ assert status()[:vm_memory_high_watermark] == {:absolute, memory_unit_absolute(10, mu)}
+ end)
+ end
+
+ test "run: low watermark sets alarm", context do
+ old_watermark = status()[:vm_memory_high_watermark]
+ on_exit(fn() ->
+ args = case old_watermark do
+ {:absolute, val} -> ["absolute", to_string(val)];
+ other -> [to_string(other)]
+ end
+ @command.run(args, context[:opts])
+ end)
+ ## this will trigger an alarm
+ @command.run(["absolute", "2000"], context[:opts])
+
+ assert [:memory] == alarm_types(status()[:alarms])
+ end
+
+ test "banner: absolute memory request prints info message", context do
+ assert @command.banner(["absolute", "10"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to 10 bytes .../
+
+ assert @command.banner(["absolute", "-10"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to -10 bytes .../
+
+ assert @command.banner(["absolute", "sandwich"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to sandwich bytes .../
+ end
+
+ test "banner, relative memory", context do
+ assert @command.banner(["0.7"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to 0.7 .../
+
+ assert @command.banner(["-0.7"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to -0.7 .../
+
+ assert @command.banner(["sandwich"], context[:opts])
+ =~ ~r/Setting memory threshold on #{get_rabbit_hostname()} to sandwich .../
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/shutdown_command_test.exs b/deps/rabbitmq_cli/test/ctl/shutdown_command_test.exs
new file mode 100644
index 0000000000..153c136c4b
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/shutdown_command_test.exs
@@ -0,0 +1,53 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule ShutdownCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.ShutdownCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 15}}
+ end
+
+ test "validate: accepts no arguments", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: in wait mode, checks if local and target node hostnames match" do
+ assert match?({:validation_failure, {:unsupported_target, _}},
+ @command.validate([], %{wait: true, node: :'rabbit@some.remote.hostname'}))
+ end
+
+ test "validate: in wait mode, always assumes @localhost nodes are local" do
+ assert @command.validate([], %{wait: true, node: :rabbit@localhost}) == :ok
+ end
+
+ test "validate: in no wait mode, passes unconditionally", context do
+ assert @command.validate([], Map.merge(%{wait: false}, context[:opts])) == :ok
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, wait: false, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "empty banner", context do
+ nil = @command.banner([], context[:opts])
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/start_app_command_test.exs b/deps/rabbitmq_cli/test/ctl/start_app_command_test.exs
new file mode 100644
index 0000000000..bdd8632842
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/start_app_command_test.exs
@@ -0,0 +1,50 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule StartAppCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.StartAppCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to an active node succeeds", context do
+ node = RabbitMQ.CLI.Core.Helpers.normalise_node(context[:node], :shortnames)
+ stop_rabbitmq_app()
+ refute :rabbit_misc.rpc_call(node, :rabbit, :is_running, [])
+ assert @command.run([], context[:opts])
+ assert :rabbit_misc.rpc_call(node, :rabbit, :is_running, [])
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Starting node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/status_command_test.exs b/deps/rabbitmq_cli/test/ctl/status_command_test.exs
new file mode 100644
index 0000000000..03ab6cb8fc
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/status_command_test.exs
@@ -0,0 +1,40 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule StatusCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.StatusCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(), timeout: 60_000}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a named, active node succeeds", context do
+ assert @command.run([], context[:opts])[:pid] != nil
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Status of node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/stop_app_command_test.exs b/deps/rabbitmq_cli/test/ctl/stop_app_command_test.exs
new file mode 100644
index 0000000000..60551b2189
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/stop_app_command_test.exs
@@ -0,0 +1,49 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule StopAppCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.StopAppCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to an active node succeeds", context do
+ node = RabbitMQ.CLI.Core.Helpers.normalise_node(context[:node], :shortnames)
+ assert :rabbit_misc.rpc_call(node, :rabbit, :is_running, [])
+ assert @command.run([], context[:opts])
+ refute :rabbit_misc.rpc_call(node, :rabbit, :is_running, [])
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Stopping rabbit application on node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/stop_command_test.exs b/deps/rabbitmq_cli/test/ctl/stop_command_test.exs
new file mode 100644
index 0000000000..2f1dca2eae
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/stop_command_test.exs
@@ -0,0 +1,52 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule StopCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.StopCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname(),
+ idempotent: false}}
+ end
+
+ test "validate accepts no arguments", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "validate accepts a PID file path", context do
+ assert @command.validate(["/path/to/pidfile.pid"], context[:opts]) == :ok
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["/path/to/pidfile.pid", "extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ # NB: as this commands shuts down the Erlang vm it isn't really practical to test it here
+
+ test "run: request to a non-existent node with --idempotent=false returns a badrpc" do
+ opts = %{node: :jake@thedog, idempotent: false, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "run: request to a non-existent node with --idempotent returns ok" do
+ opts = %{node: :jake@thedog, idempotent: true, timeout: 200}
+ assert match?({:ok, _}, @command.run([], opts))
+ end
+
+ test "banner", context do
+ assert @command.banner([], context[:opts]) =~ ~r/Stopping and halting node #{get_rabbit_hostname()}/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/suspend_listeners_command_test.exs b/deps/rabbitmq_cli/test/ctl/suspend_listeners_command_test.exs
new file mode 100644
index 0000000000..602cdf9f8b
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/suspend_listeners_command_test.exs
@@ -0,0 +1,67 @@
+## The contents of this file are subject to the Mozilla Public License
+## Version 1.1 (the "License"); you may not use this file except in
+## compliance with the License. You may obtain a copy of the License
+## at https://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule SuspendListenersCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SuspendListenersCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ resume_all_client_listeners()
+
+ node_name = get_rabbit_hostname()
+ on_exit(fn ->
+ resume_all_client_listeners()
+ close_all_connections(node_name)
+ end)
+
+ {:ok, opts: %{node: node_name, timeout: 30_000}}
+ end
+
+ setup do
+ {:ok, opts: %{node: get_rabbit_hostname()}}
+ end
+
+ test "merge_defaults: merges no defaults" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: accepts no arguments", context do
+ assert @command.validate([], context[:opts]) == :ok
+ end
+
+ test "validate: with extra arguments returns an arg count error", context do
+ assert @command.validate(["extra"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: request to a non-existent node returns a badrpc" do
+ opts = %{node: :jake@thedog, timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ test "run: suspends all client TCP listeners so no new client connects are accepted", context do
+ assert @command.run([], Map.merge(context[:opts], %{timeout: 5_000})) == :ok
+
+ expect_client_connection_failure()
+ resume_all_client_listeners()
+
+ # implies a successful connection
+ with_channel("/", fn _ -> :ok end)
+ close_all_connections(get_rabbit_hostname())
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/sync_queue_command_test.exs b/deps/rabbitmq_cli/test/ctl/sync_queue_command_test.exs
new file mode 100644
index 0000000000..3d3f866dd0
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/sync_queue_command_test.exs
@@ -0,0 +1,64 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+defmodule SyncQueueCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.SyncQueueCommand
+
+ @vhost "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname(),
+ vhost: @vhost
+ }}
+ end
+
+ test "validate: specifying no queue name is reported as an error", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: specifying two queue names is reported as an error", context do
+ assert @command.validate(["q1", "q2"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: specifying three queue names is reported as an error", context do
+ assert @command.validate(["q1", "q2", "q3"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "validate: specifying one queue name succeeds", context do
+ assert @command.validate(["q1"], context[:opts]) == :ok
+ end
+
+ test "run: request to a non-existent RabbitMQ node returns a nodedown" do
+ opts = %{node: :jake@thedog, vhost: @vhost, timeout: 200}
+ assert match?({:badrpc, _}, @command.run(["q1"], opts))
+ end
+
+ test "banner", context do
+ s = @command.banner(["q1"], context[:opts])
+
+ assert s =~ ~r/Synchronising queue/
+ assert s =~ ~r/q1/
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/trace_off_command_test.exs b/deps/rabbitmq_cli/test/ctl/trace_off_command_test.exs
new file mode 100644
index 0000000000..0ea53774cb
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/trace_off_command_test.exs
@@ -0,0 +1,78 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule TraceOffCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.TraceOffCommand
+
+ @test_vhost "test"
+ @default_vhost "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost(@test_vhost)
+
+ on_exit([], fn ->
+ delete_vhost(@test_vhost)
+ end)
+
+ :ok
+ end
+
+ setup context do
+ trace_on(context[:vhost])
+ on_exit(context, fn -> trace_off(context[:vhost]) end)
+ {:ok, opts: %{node: get_rabbit_hostname(), vhost: context[:vhost]}}
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: wrong number of arguments triggers arg count error" do
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: on an active node, trace_off command works on default" do
+ opts = %{node: get_rabbit_hostname()}
+ opts_with_vhost = %{node: get_rabbit_hostname(), vhost: "/"}
+ trace_on(@default_vhost)
+
+ assert @command.merge_defaults([], opts) == {[], opts_with_vhost}
+ end
+
+ test "run: on an invalid RabbitMQ node, return a nodedown" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag target: get_rabbit_hostname(), vhost: @default_vhost
+ test "run: calls to trace_off are idempotent", context do
+ @command.run([], context[:opts])
+ assert @command.run([], context[:opts]) == {:ok, "Trace disabled for vhost #{@default_vhost}"}
+ end
+
+ @tag vhost: @test_vhost
+ test "run: on an active node, trace_off command works on named vhost", context do
+ assert @command.run([], context[:opts]) == {:ok, "Trace disabled for vhost #{@test_vhost}"}
+ end
+
+ @tag vhost: "toast"
+ test "run: Turning tracing off on invalid host returns successfully", context do
+ assert @command.run([], context[:opts]) == {:ok, "Trace disabled for vhost toast"}
+ end
+
+ @tag vhost: @default_vhost
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Stopping tracing for vhost "#{context[:vhost]}" .../
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/trace_on_command_test.exs b/deps/rabbitmq_cli/test/ctl/trace_on_command_test.exs
new file mode 100644
index 0000000000..4db58772a1
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/trace_on_command_test.exs
@@ -0,0 +1,79 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule TraceOnCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.TraceOnCommand
+
+ @test_vhost "test"
+ @default_vhost "/"
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ add_vhost(@test_vhost)
+
+ on_exit([], fn ->
+ delete_vhost(@test_vhost)
+ end)
+
+ :ok
+ end
+
+ setup context do
+ on_exit(context, fn -> trace_off(context[:vhost]) end)
+ {:ok, opts: %{node: get_rabbit_hostname(), vhost: context[:vhost]}}
+ end
+
+ test "merge_defaults: on an active node, trace_on command works on default" do
+ opts = %{node: get_rabbit_hostname()}
+ opts_with_vhost = %{node: get_rabbit_hostname(), vhost: "/"}
+
+ assert @command.merge_defaults([], opts) == {[], opts_with_vhost}
+
+ trace_off(@default_vhost)
+ end
+
+ test "merge_defaults: defaults can be overridden" do
+ assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
+ assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
+ end
+
+ test "validate: wrong number of arguments triggers arg count error" do
+ assert @command.validate(["extra"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: on an invalid RabbitMQ node, return a nodedown" do
+ opts = %{node: :jake@thedog, vhost: "/", timeout: 200}
+
+ assert match?({:badrpc, _}, @command.run([], opts))
+ end
+
+ @tag vhost: @default_vhost
+ test "run: calls to trace_on are idempotent", context do
+ @command.run([], context[:opts])
+ assert @command.run([], context[:opts]) == {:ok, "Trace enabled for vhost #{@default_vhost}"}
+ end
+
+ @tag vhost: @test_vhost
+ test "run: on an active node, trace_on command works on named vhost", context do
+ assert @command.run([], context[:opts]) == {:ok, "Trace enabled for vhost #{@test_vhost}"}
+ end
+
+ @tag vhost: "toast"
+ test "run: Turning tracing on on invalid host returns successfully", context do
+ assert @command.run([], context[:opts]) == {:ok, "Trace enabled for vhost toast"}
+ end
+
+ @tag vhost: @default_vhost
+ test "banner", context do
+ assert @command.banner([], context[:opts])
+ =~ ~r/Starting tracing for vhost "#{context[:vhost]}" .../
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/update_cluster_nodes_command_test.exs b/deps/rabbitmq_cli/test/ctl/update_cluster_nodes_command_test.exs
new file mode 100644
index 0000000000..b94c21f1be
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/update_cluster_nodes_command_test.exs
@@ -0,0 +1,80 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2016-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule UpdateClusterNodesCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.UpdateClusterNodesCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ :ok
+ end
+
+ setup do
+ {:ok, opts: %{
+ node: get_rabbit_hostname()
+ }}
+ end
+
+ test "validate: providing too few arguments fails validation", context do
+ assert @command.validate([], context[:opts]) ==
+ {:validation_failure, :not_enough_args}
+ end
+
+ test "validate: providing too many arguments fails validation", context do
+ assert @command.validate(["a", "b", "c"], context[:opts]) ==
+ {:validation_failure, :too_many_args}
+ end
+
+ test "run: specifying self as seed node fails validation", context do
+ stop_rabbitmq_app()
+ assert match?(
+ {:error, :cannot_cluster_node_with_itself},
+ @command.run([context[:opts][:node]], context[:opts]))
+ start_rabbitmq_app()
+ end
+
+ test "run: request to an unreachable node returns a badrpc", context do
+ opts = %{
+ node: :jake@thedog,
+ timeout: 200
+ }
+ assert match?(
+ {:badrpc, :nodedown},
+ @command.run([context[:opts][:node]], opts))
+ end
+
+ test "run: specifying an unreachable node as seed returns a badrpc", context do
+ stop_rabbitmq_app()
+ assert match?(
+ {:badrpc_multi, _, [_]},
+ @command.run([:jake@thedog], context[:opts]))
+ start_rabbitmq_app()
+ end
+
+ test "banner", context do
+ assert @command.banner(["a"], context[:opts]) =~
+ ~r/Will seed #{get_rabbit_hostname()} from a on next start/
+ end
+
+ test "output mnesia is running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code,
+ "Mnesia is still running on node " <> _},
+ @command.output({:error, :mnesia_unexpectedly_running}, context[:opts]))
+
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/version_command_test.exs b/deps/rabbitmq_cli/test/ctl/version_command_test.exs
new file mode 100644
index 0000000000..76216b6cf0
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/version_command_test.exs
@@ -0,0 +1,24 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule VersionCommandTest do
+ use ExUnit.Case
+
+ @command RabbitMQ.CLI.Ctl.Commands.VersionCommand
+
+ test "merge_defaults: merges no defaults" do
+ assert @command.merge_defaults([], %{}) == {[], %{}}
+ end
+
+ test "validate: treats positional arguments as a failure" do
+ assert @command.validate(["extra-arg"], %{}) == {:validation_failure, :too_many_args}
+ end
+
+ test "validate: treats empty positional arguments and default switches as a success" do
+ assert @command.validate([], %{}) == :ok
+ end
+end
diff --git a/deps/rabbitmq_cli/test/ctl/wait_command_test.exs b/deps/rabbitmq_cli/test/ctl/wait_command_test.exs
new file mode 100644
index 0000000000..c1fd604245
--- /dev/null
+++ b/deps/rabbitmq_cli/test/ctl/wait_command_test.exs
@@ -0,0 +1,114 @@
+## This Source Code Form is subject to the terms of the Mozilla Public
+## License, v. 2.0. If a copy of the MPL was not distributed with this
+## file, You can obtain one at https://mozilla.org/MPL/2.0/.
+##
+## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+
+
+defmodule WaitCommandTest do
+ use ExUnit.Case, async: false
+ import TestHelper
+
+ @command RabbitMQ.CLI.Ctl.Commands.WaitCommand
+
+ setup_all do
+ RabbitMQ.CLI.Core.Distribution.start()
+ start_rabbitmq_app()
+
+ on_exit([], fn ->
+ start_rabbitmq_app()
+ end)
+
+ RabbitMQ.CLI.Core.Distribution.start()
+ rabbitmq_home = :rabbit_misc.rpc_call(get_rabbit_hostname(), :code, :lib_dir, [:rabbit])
+
+ {:ok, opts: %{node: get_rabbit_hostname(),
+ rabbitmq_home: rabbitmq_home,
+ timeout: 500}}
+ end
+
+
+ test "validate: cannot have both pid and pidfile", context do
+ {:validation_failure, "Cannot specify both pid and pidfile"} =
+ @command.validate(["pid_file"], Map.merge(context[:opts], %{pid: 123}))
+ end
+
+ test "validate: should have either pid or pidfile", context do
+ {:validation_failure, "No pid or pidfile specified"} =
+ @command.validate([], context[:opts])
+ end
+
+ test "validate: with more than one argument returns an arg count error", context do
+ assert @command.validate(["pid_file", "extra"], context[:opts]) == {:validation_failure, :too_many_args}
+ end
+
+ test "run: times out waiting for non-existent pid file", context do
+ {:error, {:timeout, _}} = @command.run(["pid_file"], context[:opts]) |> Enum.to_list |> List.last
+ end
+
+ test "run: fails if pid process does not exist", context do
+ non_existent_pid = get_non_existent_os_pid()
+ {:error, :process_not_running} =
+ @command.run([], Map.merge(context[:opts], %{pid: non_existent_pid}))
+ |> Enum.to_list
+ |> List.last
+ end
+
+ test "run: times out if unable to communicate with the node", context do
+ pid = String.to_integer(System.get_pid())
+ {:error, {:timeout, _}} =
+ @command.run([], Map.merge(context[:opts], %{pid: pid, node: :nonode@nohost}))
+ |> Enum.to_list
+ |> List.last
+ end
+
+ test "run: happy path", context do
+ pid = :erlang.list_to_integer(:rpc.call(context[:opts][:node], :os, :getpid, []))
+ output = @command.run([], Map.merge(context[:opts], %{pid: pid}))
+ assert_stream_without_errors(output)
+ end
+
+ test "run: happy path in quiet mode", context do
+ pid = :erlang.list_to_integer(:rpc.call(context[:opts][:node], :os, :getpid, []))
+ output = @command.run([], Map.merge(context[:opts], %{pid: pid, quiet: true}))
+ [] = Enum.to_list(output)
+ end
+
+ test "no banner", context do
+ nil = @command.banner([], context[:opts])
+ end
+
+ test "output: process not running error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code, "Error: process is not running."},
+ @command.output({:error, :process_not_running}, context[:opts]))
+ end
+
+ test "output: garbage in pid file error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code, "Error: garbage in pid file."},
+ @command.output({:error, {:garbage_in_pid_file, "somefile"}}, context[:opts]))
+ end
+
+ test "output: could not read pid error", context do
+ exit_code = RabbitMQ.CLI.Core.ExitCodes.exit_software
+ assert match?({:error, ^exit_code, "Error: could not read pid. Detail: something wrong"},
+ @command.output({:error, {:could_not_read_pid, "something wrong"}}, context[:opts]))
+ end
+
+ test "output: default output is fine", context do
+ assert match?({:error, "message"}, @command.output({:error, "message"}, context[:opts]))
+ assert match?({:error, :message}, @command.output({:error, :message}, context[:opts]))
+ assert match?({:error, :message}, @command.output(:message, context[:opts]))
+ assert match?({:ok, "ok"}, @command.output({:ok, "ok"}, context[:opts]))
+ assert match?(:ok, @command.output(:ok, context[:opts]))
+ assert match?({:ok, "ok"}, @command.output("ok", context[:opts]))
+ end
+
+ def get_non_existent_os_pid(pid \\ 2) do
+ case :rabbit_misc.is_os_process_alive(to_charlist(pid)) do
+ true -> get_non_existent_os_pid(pid + 1)
+ false -> pid
+ end
+ end
+end