diff options
Diffstat (limited to 'test/pleroma')
-rw-r--r-- | test/pleroma/application/config_dependent_deps_test.exs | 149 | ||||
-rw-r--r-- | test/pleroma/application/environment_test.exs | 248 | ||||
-rw-r--r-- | test/pleroma/application/requirements_test.exs (renamed from test/pleroma/application_requirements_test.exs) | 55 | ||||
-rw-r--r-- | test/pleroma/config/converter_test.exs | 432 | ||||
-rw-r--r-- | test/pleroma/config/loader_test.exs | 40 | ||||
-rw-r--r-- | test/pleroma/config/transfer_task_test.exs | 120 | ||||
-rw-r--r-- | test/pleroma/config/versioning_test.exs | 414 | ||||
-rw-r--r-- | test/pleroma/config_db_test.exs | 538 | ||||
-rw-r--r-- | test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs | 28 | ||||
-rw-r--r-- | test/pleroma/web/admin_api/controllers/config_controller_test.exs | 643 |
10 files changed, 1878 insertions, 789 deletions
diff --git a/test/pleroma/application/config_dependent_deps_test.exs b/test/pleroma/application/config_dependent_deps_test.exs new file mode 100644 index 000000000..620da16d9 --- /dev/null +++ b/test/pleroma/application/config_dependent_deps_test.exs @@ -0,0 +1,149 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Application.ConfigDependentDepsTest do + use ExUnit.Case + + alias Pleroma.Application.ConfigDependentDeps + + setup do + {:ok, _} = + DynamicSupervisor.start_link( + strategy: :one_for_one, + name: Pleroma.Application.DynamicSupervisorTest + ) + + {:ok, pid} = + Pleroma.Application.ConfigDependentDeps.start_link( + dynamic_supervisor: Pleroma.Application.DynamicSupervisorTest, + name: Pleroma.Application.ConfigDependentDepsTesting, + relations: [ + {{:pleroma, :dummy_module1}, Pleroma.DummyModule1}, + {{:pleroma, :dummy_module2}, Pleroma.DummyModule2}, + {:dummy_group1, :dummy_group1}, + {:ex_aws, :ex_aws}, + {:not_started_app, :not_started_app} + ] + ) + + [pid: pid] + end + + test "start_dependency/2", %{pid: pid} do + {:ok, pid} = ConfigDependentDeps.start_dependency(Pleroma.DummyModule1, pid) + assert Process.alive?(pid) + end + + describe "need_reboot?/1" do + test "apps and paths", %{pid: pid} do + changes = [ + %Pleroma.ConfigDB{group: :dummy_group1}, + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module1} + ] + + assert ConfigDependentDeps.save_config_paths_for_restart(changes, pid) == [ + {:pleroma, :dummy_module1}, + :dummy_group1 + ] + + assert ConfigDependentDeps.need_reboot?(pid) + end + + test "app and path are not duplicated", %{pid: pid} do + changes = [ + %Pleroma.ConfigDB{group: :dummy_group1}, + %Pleroma.ConfigDB{group: :dummy_group1}, + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module1}, + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module1} + ] + + assert ConfigDependentDeps.save_config_paths_for_restart(changes, pid) == [ + {:pleroma, :dummy_module1}, + :dummy_group1 + ] + + assert ConfigDependentDeps.need_reboot?(pid) + end + end + + describe "restart_dependencies/1" do + test "started dependency", %{pid: pid} do + {:ok, dummy_pid} = ConfigDependentDeps.start_dependency(Pleroma.DummyModule1, pid) + + changes = [ + %Pleroma.ConfigDB{group: :ex_aws}, + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module1} + ] + + assert ConfigDependentDeps.save_config_paths_for_restart(changes, pid) == [ + {:pleroma, :dummy_module1}, + :ex_aws + ] + + assert :ok == ConfigDependentDeps.restart_dependencies(pid) + + restarted = Process.whereis(Pleroma.DummyModule1) + + refute dummy_pid == restarted + end + + test "not started process and app", %{pid: pid} do + changes = [ + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module1}, + %Pleroma.ConfigDB{group: :not_started_app} + ] + + assert ConfigDependentDeps.save_config_paths_for_restart(changes, pid) == [ + :not_started_app, + {:pleroma, :dummy_module1} + ] + + assert :ok == ConfigDependentDeps.restart_dependencies(pid) + + started = Process.whereis(Pleroma.DummyModule1) + + assert Process.alive?(started) + end + + test "ignored dependency", %{pid: pid} do + changes = [ + %Pleroma.ConfigDB{group: :pleroma, key: :dummy_module2} + ] + + assert ConfigDependentDeps.save_config_paths_for_restart(changes, pid) == [ + {:pleroma, :dummy_module2} + ] + + assert :ok == ConfigDependentDeps.restart_dependencies(pid) + + refute Process.whereis(Pleroma.DummyModule2) + end + end + + test "process goes down", %{pid: pid} do + {:ok, dummy_pid} = ConfigDependentDeps.start_dependency(Pleroma.DummyModule1, pid) + + Process.exit(dummy_pid, :kill) + + Process.sleep(10) + restarted = Process.whereis(Pleroma.DummyModule1) + refute restarted == dummy_pid + end +end + +defmodule Pleroma.DummyModule1 do + use Agent + + def start_link(_) do + Agent.start_link(fn -> nil end, name: __MODULE__) + end +end + +defmodule Pleroma.DummyModule2 do + use Agent + + def start_link(_) do + :ignore + end +end diff --git a/test/pleroma/application/environment_test.exs b/test/pleroma/application/environment_test.exs new file mode 100644 index 000000000..2ad27ebd8 --- /dev/null +++ b/test/pleroma/application/environment_test.exs @@ -0,0 +1,248 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Application.EnvironmentTest do + use Pleroma.DataCase + + import Pleroma.Factory + + alias Pleroma.Application.Environment + + setup do: clear_config(:configurable_from_database, true) + + describe "load_from_db_and_update/0" do + test "transfer config values from db to env" do + refute Application.get_env(:pleroma, :test_key) + refute Application.get_env(:idna, :test_key) + refute Application.get_env(:quack, :test_key) + refute Application.get_env(:postgrex, :test_key) + initial = Application.get_env(:logger, :level) + + insert(:config, key: :test_key, value: [live: 2, com: 3]) + insert(:config, group: :idna, key: :test_key, value: [live: 15, com: 35]) + + insert(:config, + group: :quack, + key: nil, + value: [test_key: [key1: :test_value1, key2: :test_value2]] + ) + + insert(:config, group: :logger, key: nil, value: [level: :debug]) + + Environment.load_from_db_and_update() + + assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] + assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] + assert Application.get_env(:quack, :test_key) == [key1: :test_value1, key2: :test_value2] + assert Application.get_env(:logger, :level) == :debug + + on_exit(fn -> + Application.delete_env(:pleroma, :test_key) + Application.delete_env(:idna, :test_key) + Application.delete_env(:quack, :test_key) + Application.delete_env(:postgrex, :test_key) + Application.put_env(:logger, :level, initial) + end) + end + + test "transfer config values for 1 group and some keys" do + quack_env = Application.get_all_env(:quack) + + insert(:config, group: :quack, key: nil, value: [level: :info, meta: [:none]]) + + Environment.load_from_db_and_update() + + assert Application.get_env(:quack, :level) == :info + assert Application.get_env(:quack, :meta) == [:none] + default = Pleroma.Config.Holder.default_config(:quack, :webhook_url) + assert Application.get_env(:quack, :webhook_url) == default + + on_exit(fn -> + Application.put_all_env(quack: quack_env) + end) + end + + test "transfer config values with full subkey update" do + clear_config(:emoji) + clear_config(:assets) + + insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]]) + insert(:config, key: :assets, value: [mascots: [a: 1, b: 2]]) + + Environment.load_from_db_and_update() + + emoji_env = Application.get_env(:pleroma, :emoji) + assert emoji_env[:groups] == [a: 1, b: 2] + assets_env = Application.get_env(:pleroma, :assets) + assert assets_env[:mascots] == [a: 1, b: 2] + end + end + + describe "update/2 :ex_syslogger" do + setup do + initial = Application.get_env(:logger, :ex_syslogger) + + config = + insert(:config, + group: :logger, + key: nil, + value: [ + ex_syslogger: [ + level: :warn, + ident: "pleroma", + format: "$metadata[$level] $message", + metadata: [:request_id, :key] + ] + ] + ) + + on_exit(fn -> Application.put_env(:logger, :ex_syslogger, initial) end) + [config: config, initial: initial] + end + + test "changing", %{config: config} do + assert Environment.update([config]) == :ok + + env = Application.get_env(:logger, :ex_syslogger) + assert env[:level] == :warn + assert env[:metadata] == [:request_id, :key] + end + + test "deletion", %{config: config, initial: initial} do + assert Environment.update([config]) == :ok + + {:ok, config} = Pleroma.ConfigDB.delete(config) + assert Environment.update([config]) == :ok + + env = Application.get_env(:logger, :ex_syslogger) + + assert env == initial + end + end + + describe "update/2 :console" do + setup do + initial = Application.get_env(:logger, :console) + + config = + insert(:config, + group: :logger, + key: nil, + value: [ + console: [ + level: :info, + format: "$time $metadata[$level]", + metadata: [:request_id, :key] + ] + ] + ) + + on_exit(fn -> Application.put_env(:logger, :console, initial) end) + [config: config, initial: initial] + end + + test "change", %{config: config} do + assert Environment.update([config]) == :ok + env = Application.get_env(:logger, :console) + assert env[:level] == :info + assert env[:format] == "$time $metadata[$level]" + assert env[:metadata] == [:request_id, :key] + end + + test "deletion", %{config: config, initial: initial} do + assert Environment.update([config]) == :ok + {:ok, config} = Pleroma.ConfigDB.delete(config) + assert Environment.update([config]) == :ok + + env = Application.get_env(:logger, :console) + assert env == initial + end + end + + describe "update/2 :backends" do + setup do + initial = Application.get_all_env(:logger) + + config = + insert(:config, group: :logger, key: nil, value: [backends: [:console, :ex_syslogger]]) + + on_exit(fn -> Application.put_all_env(logger: initial) end) + + [config: config, initial: initial] + end + + test "change", %{config: config} do + assert Environment.update([config]) == :ok + env = Application.get_all_env(:logger) + assert env[:backends] == [:console, :ex_syslogger] + end + + test "deletion", %{config: config, initial: initial} do + assert Environment.update([config]) == :ok + {:ok, config} = Pleroma.ConfigDB.delete(config) + assert Environment.update([config]) + + env = Application.get_all_env(:logger) + assert env == initial + end + end + + describe "update/2 logger settings" do + setup do + initial = Application.get_all_env(:logger) + + config = + insert(:config, + group: :logger, + key: nil, + value: [ + console: [ + level: :info, + format: "$time $metadata[$level]", + metadata: [:request_id, :key] + ], + ex_syslogger: [ + level: :warn, + ident: "pleroma", + format: "$metadata[$level] $message", + metadata: [:request_id, :key] + ], + backends: [:console, :ex_syslogger] + ] + ) + + on_exit(fn -> Application.put_all_env(logger: initial) end) + [config: config] + end + + test "change", %{config: config} do + assert Environment.update([config]) == :ok + + env = + :logger + |> Application.get_all_env() + |> Keyword.take([:backends, :console, :ex_syslogger]) + + assert env[:console] == config.value[:console] + assert env[:ex_syslogger] == config.value[:ex_syslogger] + assert env[:backends] == config.value[:backends] + end + end + + test "update/2 for change without key :cors_plug" do + config = + insert(:config, + group: :cors_plug, + key: nil, + value: [max_age: 300, methods: ["GET"]] + ) + + assert Environment.update([config]) == :ok + + env = Application.get_all_env(:cors_plug) + + assert env[:max_age] == 300 + assert env[:methods] == ["GET"] + end +end diff --git a/test/pleroma/application_requirements_test.exs b/test/pleroma/application/requirements_test.exs index a54c37968..c4ce045cc 100644 --- a/test/pleroma/application_requirements_test.exs +++ b/test/pleroma/application/requirements_test.exs @@ -2,24 +2,24 @@ # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ApplicationRequirementsTest do +defmodule Pleroma.Application.RequirementsTest do use Pleroma.DataCase import ExUnit.CaptureLog import Mock - alias Pleroma.ApplicationRequirements - alias Pleroma.Repo + alias Pleroma.Application.Requirements + alias Pleroma.Emails.Mailer describe "check_repo_pool_size!/1" do test "raises if the pool size is unexpected" do clear_config([Pleroma.Repo, :pool_size], 11) clear_config([:dangerzone, :override_repo_pool_size], false) - assert_raise Pleroma.ApplicationRequirements.VerifyError, + assert_raise Requirements.VerifyError, "Repo.pool_size different than recommended value.", fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) + capture_log(&Requirements.verify!/0) end end @@ -27,27 +27,27 @@ defmodule Pleroma.ApplicationRequirementsTest do clear_config([Pleroma.Repo, :pool_size], 11) clear_config([:dangerzone, :override_repo_pool_size], true) - assert Pleroma.ApplicationRequirements.verify!() == :ok + assert Requirements.verify!() == :ok end end describe "check_welcome_message_config!/1" do setup do: clear_config([:welcome]) - setup do: clear_config([Pleroma.Emails.Mailer]) + setup do: clear_config([Mailer]) test "warns if welcome email enabled but mail disabled" do clear_config([:welcome, :email, :enabled], true) - clear_config([Pleroma.Emails.Mailer, :enabled], false) + clear_config([Mailer, :enabled], false) assert capture_log(fn -> - assert Pleroma.ApplicationRequirements.verify!() == :ok + assert Requirements.verify!() == :ok end) =~ "Welcome emails will NOT be sent" end end describe "check_confirmation_accounts!" do setup_with_mocks([ - {Pleroma.ApplicationRequirements, [:passthrough], + {Requirements, [:passthrough], [ check_migrations_applied!: fn _ -> :ok end ]} @@ -59,30 +59,29 @@ defmodule Pleroma.ApplicationRequirementsTest do test "warns if account confirmation is required but mailer isn't enabled" do clear_config([:instance, :account_activation_required], true) - clear_config([Pleroma.Emails.Mailer, :enabled], false) + clear_config([Mailer, :enabled], false) assert capture_log(fn -> - assert Pleroma.ApplicationRequirements.verify!() == :ok + assert Requirements.verify!() == :ok end) =~ "Users will NOT be able to confirm their accounts" end test "doesn't do anything if account confirmation is disabled" do clear_config([:instance, :account_activation_required], false) - clear_config([Pleroma.Emails.Mailer, :enabled], false) - assert Pleroma.ApplicationRequirements.verify!() == :ok + clear_config([Mailer, :enabled], false) + assert Requirements.verify!() == :ok end test "doesn't do anything if account confirmation is required and mailer is enabled" do clear_config([:instance, :account_activation_required], true) - clear_config([Pleroma.Emails.Mailer, :enabled], true) - assert Pleroma.ApplicationRequirements.verify!() == :ok + clear_config([Mailer, :enabled], true) + assert Requirements.verify!() == :ok end end describe "check_rum!" do setup_with_mocks([ - {Pleroma.ApplicationRequirements, [:passthrough], - [check_migrations_applied!: fn _ -> :ok end]} + {Requirements, [:passthrough], [check_migrations_applied!: fn _ -> :ok end]} ]) do :ok end @@ -93,10 +92,10 @@ defmodule Pleroma.ApplicationRequirementsTest do clear_config([:database, :rum_enabled], true) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do - assert_raise ApplicationRequirements.VerifyError, + assert_raise Requirements.VerifyError, "Unapplied RUM Migrations detected", fn -> - capture_log(&ApplicationRequirements.verify!/0) + capture_log(&Requirements.verify!/0) end end end @@ -105,10 +104,10 @@ defmodule Pleroma.ApplicationRequirementsTest do clear_config([:database, :rum_enabled], false) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do - assert_raise ApplicationRequirements.VerifyError, + assert_raise Requirements.VerifyError, "RUM Migrations detected", fn -> - capture_log(&ApplicationRequirements.verify!/0) + capture_log(&Requirements.verify!/0) end end end @@ -117,7 +116,7 @@ defmodule Pleroma.ApplicationRequirementsTest do clear_config([:database, :rum_enabled], true) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do - assert ApplicationRequirements.verify!() == :ok + assert Requirements.verify!() == :ok end end @@ -125,12 +124,12 @@ defmodule Pleroma.ApplicationRequirementsTest do clear_config([:database, :rum_enabled], false) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do - assert ApplicationRequirements.verify!() == :ok + assert Requirements.verify!() == :ok end end end - describe "check_migrations_applied!" do + describe "check_migrations_applied" do setup_with_mocks([ {Ecto.Migrator, [], [ @@ -150,17 +149,17 @@ defmodule Pleroma.ApplicationRequirementsTest do setup do: clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check]) test "raises if it detects unapplied migrations" do - assert_raise ApplicationRequirements.VerifyError, + assert_raise Requirements.VerifyError, "Unapplied Migrations detected", fn -> - capture_log(&ApplicationRequirements.verify!/0) + capture_log(&Requirements.verify!/0) end end test "doesn't do anything if disabled" do clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true) - assert :ok == ApplicationRequirements.verify!() + assert :ok == Requirements.verify!() end end end diff --git a/test/pleroma/config/converter_test.exs b/test/pleroma/config/converter_test.exs new file mode 100644 index 000000000..a1ffab5be --- /dev/null +++ b/test/pleroma/config/converter_test.exs @@ -0,0 +1,432 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Config.ConverterTest do + use ExUnit.Case, async: true + + alias Pleroma.Config.Converter + + describe "to_elixir_types/1" do + test "string" do + assert Converter.to_elixir_types("value as string") == "value as string" + end + + test "boolean" do + assert Converter.to_elixir_types(false) == false + end + + test "nil" do + assert Converter.to_elixir_types(nil) == nil + end + + test "integer" do + assert Converter.to_elixir_types(150) == 150 + end + + test "atom" do + assert Converter.to_elixir_types(":atom") == :atom + end + + test "ssl options" do + assert Converter.to_elixir_types([":tlsv1", ":tlsv1.1", ":tlsv1.2"]) == [ + :tlsv1, + :"tlsv1.1", + :"tlsv1.2" + ] + end + + test "pleroma module" do + assert Converter.to_elixir_types("Pleroma.Bookmark") == Pleroma.Bookmark + end + + test "pleroma string" do + assert Converter.to_elixir_types("Pleroma") == "Pleroma" + end + + test "phoenix module" do + assert Converter.to_elixir_types("Phoenix.Socket.V1.JSONSerializer") == + Phoenix.Socket.V1.JSONSerializer + end + + test "tesla module" do + assert Converter.to_elixir_types("Tesla.Adapter.Hackney") == Tesla.Adapter.Hackney + end + + test "ExSyslogger module" do + assert Converter.to_elixir_types("ExSyslogger") == ExSyslogger + end + + test "Quack.Logger module" do + assert Converter.to_elixir_types("Quack.Logger") == Quack.Logger + end + + test "Swoosh.Adapters modules" do + assert Converter.to_elixir_types("Swoosh.Adapters.SMTP") == Swoosh.Adapters.SMTP + assert Converter.to_elixir_types("Swoosh.Adapters.AmazonSES") == Swoosh.Adapters.AmazonSES + end + + test "sigil" do + assert Converter.to_elixir_types("~r[comp[lL][aA][iI][nN]er]") == ~r/comp[lL][aA][iI][nN]er/ + end + + test "link sigil" do + assert Converter.to_elixir_types("~r/https:\/\/example.com/") == ~r/https:\/\/example.com/ + end + + test "link sigil with um modifiers" do + assert Converter.to_elixir_types("~r/https:\/\/example.com/um") == + ~r/https:\/\/example.com/um + end + + test "link sigil with i modifier" do + assert Converter.to_elixir_types("~r/https:\/\/example.com/i") == ~r/https:\/\/example.com/i + end + + test "link sigil with s modifier" do + assert Converter.to_elixir_types("~r/https:\/\/example.com/s") == ~r/https:\/\/example.com/s + end + + test "raise if valid delimiter not found" do + assert_raise ArgumentError, "valid delimiter for Regex expression not found", fn -> + Converter.to_elixir_types("~r/https://[]{}<>\"'()|example.com/s") + end + end + + test "2 child tuple" do + assert Converter.to_elixir_types(%{"tuple" => ["v1", ":v2"]}) == {"v1", :v2} + end + + test "proxy tuple with localhost" do + assert Converter.to_elixir_types(%{ + "tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}] + }) == {:proxy_url, {:socks5, :localhost, 1234}} + end + + test "proxy tuple with domain" do + assert Converter.to_elixir_types(%{ + "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}] + }) == {:proxy_url, {:socks5, 'domain.com', 1234}} + end + + test "proxy tuple with ip" do + assert Converter.to_elixir_types(%{ + "tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}] + }) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}} + end + + test "tuple with n childs" do + assert Converter.to_elixir_types(%{ + "tuple" => [ + "v1", + ":v2", + "Pleroma.Bookmark", + 150, + false, + "Phoenix.Socket.V1.JSONSerializer" + ] + }) == {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} + end + + test "map with string key" do + assert Converter.to_elixir_types(%{"key" => "value"}) == %{"key" => "value"} + end + + test "map with atom key" do + assert Converter.to_elixir_types(%{":key" => "value"}) == %{key: "value"} + end + + test "list of strings" do + assert Converter.to_elixir_types(["v1", "v2", "v3"]) == ["v1", "v2", "v3"] + end + + test "list of modules" do + assert Converter.to_elixir_types(["Pleroma.Repo", "Pleroma.Activity"]) == [ + Pleroma.Repo, + Pleroma.Activity + ] + end + + test "list of atoms" do + assert Converter.to_elixir_types([":v1", ":v2", ":v3"]) == [:v1, :v2, :v3] + end + + test "list of mixed values" do + assert Converter.to_elixir_types([ + "v1", + ":v2", + "Pleroma.Repo", + "Phoenix.Socket.V1.JSONSerializer", + 15, + false + ]) == [ + "v1", + :v2, + Pleroma.Repo, + Phoenix.Socket.V1.JSONSerializer, + 15, + false + ] + end + + test "simple keyword" do + assert Converter.to_elixir_types([%{"tuple" => [":key", "value"]}]) == [key: "value"] + end + + test "keyword" do + assert Converter.to_elixir_types([ + %{"tuple" => [":types", "Pleroma.PostgresTypes"]}, + %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]}, + %{"tuple" => [":migration_lock", nil]}, + %{"tuple" => [":key1", 150]}, + %{"tuple" => [":key2", "string"]} + ]) == [ + types: Pleroma.PostgresTypes, + telemetry_event: [Pleroma.Repo.Instrumenter], + migration_lock: nil, + key1: 150, + key2: "string" + ] + end + + test "trandformed keyword" do + assert Converter.to_elixir_types(a: 1, b: 2, c: "string") == [a: 1, b: 2, c: "string"] + end + + test "complex keyword with nested mixed childs" do + assert Converter.to_elixir_types([ + %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]}, + %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]}, + %{"tuple" => [":link_name", true]}, + %{"tuple" => [":proxy_remote", false]}, + %{"tuple" => [":common_map", %{":key" => "value"}]}, + %{ + "tuple" => [ + ":proxy_opts", + [ + %{"tuple" => [":redirect_on_failure", false]}, + %{"tuple" => [":max_body_length", 1_048_576]}, + %{ + "tuple" => [ + ":http", + [ + %{"tuple" => [":follow_redirect", true]}, + %{"tuple" => [":pool", ":upload"]} + ] + ] + } + ] + ] + } + ]) == [ + uploader: Pleroma.Uploaders.Local, + filters: [Pleroma.Upload.Filter.Dedupe], + link_name: true, + proxy_remote: false, + common_map: %{key: "value"}, + proxy_opts: [ + redirect_on_failure: false, + max_body_length: 1_048_576, + http: [ + follow_redirect: true, + pool: :upload + ] + ] + ] + end + + test "common keyword" do + assert Converter.to_elixir_types([ + %{"tuple" => [":level", ":warn"]}, + %{"tuple" => [":meta", [":all"]]}, + %{"tuple" => [":path", ""]}, + %{"tuple" => [":val", nil]}, + %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]} + ]) == [ + level: :warn, + meta: [:all], + path: "", + val: nil, + webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" + ] + end + + test "complex keyword with sigil" do + assert Converter.to_elixir_types([ + %{"tuple" => [":federated_timeline_removal", []]}, + %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]}, + %{"tuple" => [":replace", []]} + ]) == [ + federated_timeline_removal: [], + reject: [~r/comp[lL][aA][iI][nN]er/], + replace: [] + ] + end + + test "complex keyword with tuples with more than 2 values" do + assert Converter.to_elixir_types([ + %{ + "tuple" => [ + ":http", + [ + %{ + "tuple" => [ + ":key1", + [ + %{ + "tuple" => [ + ":_", + [ + %{ + "tuple" => [ + "/api/v1/streaming", + "Pleroma.Web.MastodonAPI.WebsocketHandler", + [] + ] + }, + %{ + "tuple" => [ + "/websocket", + "Phoenix.Endpoint.CowboyWebSocket", + %{ + "tuple" => [ + "Phoenix.Transports.WebSocket", + %{ + "tuple" => [ + "Pleroma.Web.Endpoint", + "Pleroma.Web.UserSocket", + [] + ] + } + ] + } + ] + }, + %{ + "tuple" => [ + ":_", + "Phoenix.Endpoint.Cowboy2Handler", + %{"tuple" => ["Pleroma.Web.Endpoint", []]} + ] + } + ] + ] + } + ] + ] + } + ] + ] + } + ]) == [ + http: [ + key1: [ + {:_, + [ + {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, + {"/websocket", Phoenix.Endpoint.CowboyWebSocket, + {Phoenix.Transports.WebSocket, + {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}}, + {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + ]} + ] + ] + ] + end + end + + describe "to_json_types" do + test "list" do + assert Converter.to_json_types(["0", 1, true, :atom, Pleroma.Upload]) == [ + "0", + 1, + true, + ":atom", + "Pleroma.Upload" + ] + end + + test "regex" do + assert Converter.to_json_types(~r/regex/i) == "~r/regex/i" + end + + test "map" do + assert Converter.to_json_types(%{"a" => "b", "c" => 1, "d" => true, "e" => :atom}) == %{ + "a" => "b", + "c" => 1, + "d" => true, + "e" => ":atom" + } + end + + test ":args list" do + assert Converter.to_json_types({:args, [{1, "a"}, "string"]}) == %{ + "tuple" => [":args", ["{1, \"a\"}", "string"]] + } + end + + test ":proxy_url tuple with localhost" do + assert Converter.to_json_types({:proxy_url, {:socks, :localhost, 1234}}) == %{ + "tuple" => [":proxy_url", %{"tuple" => [":socks", "localhost", 1234]}] + } + end + + test ":proxy_url tuple" do + assert Converter.to_json_types({:proxy_url, {:socks, {127, 0, 0, 1}, 1234}}) == %{ + "tuple" => [":proxy_url", %{"tuple" => [":socks", "127.0.0.1", 1234]}] + } + end + + test ":proxy_url tuple domain" do + assert Converter.to_json_types({:proxy_url, {:socks5, "domain.com", 1234}}) == %{ + "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}] + } + end + + test "tuple" do + assert Converter.to_json_types({1, "a"}) == %{"tuple" => [1, "a"]} + end + + test "string" do + assert Converter.to_json_types("string") == "string" + end + + test "boolean" do + assert Converter.to_json_types(true) == true + end + + test "integer" do + assert Converter.to_json_types(123) == 123 + end + + test "nil" do + assert Converter.to_json_types(nil) == nil + end + + test "ssl type" do + assert Converter.to_json_types(:"tlsv1.1") == ":tlsv1.1" + end + + test "atom" do + assert Converter.to_json_types(:atom) == ":atom" + end + end + + describe "string_to_elixir_types!/1" do + test "atom" do + assert Converter.string_to_elixir_types!(":localhost") == :localhost + end + + test "module" do + assert Converter.string_to_elixir_types!("Pleroma.Upload") == Pleroma.Upload + end + + test "regex" do + assert Converter.string_to_elixir_types!("~r/regex/i") == ~r/regex/i + end + + test "string" do + assert Converter.string_to_elixir_types!("string") == "string" + end + end +end diff --git a/test/pleroma/config/loader_test.exs b/test/pleroma/config/loader_test.exs index b34fd70da..5eb29946d 100644 --- a/test/pleroma/config/loader_test.exs +++ b/test/pleroma/config/loader_test.exs @@ -8,22 +8,38 @@ defmodule Pleroma.Config.LoaderTest do alias Pleroma.Config.Loader test "read/1" do - config = Loader.read("test/fixtures/config/temp.secret.exs") + config = Loader.read!("test/fixtures/config/temp.secret.exs") assert config[:pleroma][:first_setting][:key] == "value" assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo] assert config[:quack][:level] == :info end - test "filter_group/2" do - assert Loader.filter_group(:pleroma, - pleroma: [ - {Pleroma.Repo, [a: 1, b: 2]}, - {Pleroma.Upload, [a: 1, b: 2]}, - {Pleroma.Web.Endpoint, []}, - env: :test, - configurable_from_database: true, - database: [] - ] - ) == [{Pleroma.Upload, [a: 1, b: 2]}] + test "filter/1" do + config = Loader.read!("test/fixtures/config/temp.secret.exs") + + filtered_config = Loader.filter(config) + + refute filtered_config[:postgrex] + refute filtered_config[:tesla] + refute filtered_config[:phoenix] + refute filtered_config[:tz_data] + refute filtered_config[:http_signatures] + refute filtered_config[:web_push_encryption] + refute filtered_config[:floki] + + refute filtered_config[:pleroma][Pleroma.Repo] + refute filtered_config[:pleroma][Pleroma.Web.Endpoint] + refute filtered_config[:pleroma][:env] + refute filtered_config[:pleroma][:configurable_from_database] + refute filtered_config[:pleroma][:database] + refute filtered_config[:pleroma][:ecto_repos] + refute filtered_config[:pleroma][Pleroma.Gun] + refute filtered_config[:pleroma][Pleroma.ReverseProxy.Client] + + assert config[:pleroma][:first_setting][:key] == "value" + assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo] + assert config[:quack][:level] == :info + assert config[:pleroma][:second_setting][:key] == "value2" + assert config[:pleroma][:second_setting][:key2] == ["Activity"] end end diff --git a/test/pleroma/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs deleted file mode 100644 index 8ae5d3b81..000000000 --- a/test/pleroma/config/transfer_task_test.exs +++ /dev/null @@ -1,120 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Config.TransferTaskTest do - use Pleroma.DataCase - - import ExUnit.CaptureLog - import Pleroma.Factory - - alias Pleroma.Config.TransferTask - - setup do: clear_config(:configurable_from_database, true) - - test "transfer config values from db to env" do - refute Application.get_env(:pleroma, :test_key) - refute Application.get_env(:idna, :test_key) - refute Application.get_env(:quack, :test_key) - refute Application.get_env(:postgrex, :test_key) - initial = Application.get_env(:logger, :level) - - insert(:config, key: :test_key, value: [live: 2, com: 3]) - insert(:config, group: :idna, key: :test_key, value: [live: 15, com: 35]) - insert(:config, group: :quack, key: :test_key, value: [:test_value1, :test_value2]) - insert(:config, group: :postgrex, key: :test_key, value: :value) - insert(:config, group: :logger, key: :level, value: :debug) - - TransferTask.start_link([]) - - assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] - assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] - assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2] - assert Application.get_env(:logger, :level) == :debug - assert Application.get_env(:postgrex, :test_key) == :value - - on_exit(fn -> - Application.delete_env(:pleroma, :test_key) - Application.delete_env(:idna, :test_key) - Application.delete_env(:quack, :test_key) - Application.delete_env(:postgrex, :test_key) - Application.put_env(:logger, :level, initial) - end) - end - - test "transfer config values for 1 group and some keys" do - level = Application.get_env(:quack, :level) - meta = Application.get_env(:quack, :meta) - - insert(:config, group: :quack, key: :level, value: :info) - insert(:config, group: :quack, key: :meta, value: [:none]) - - TransferTask.start_link([]) - - assert Application.get_env(:quack, :level) == :info - assert Application.get_env(:quack, :meta) == [:none] - default = Pleroma.Config.Holder.default_config(:quack, :webhook_url) - assert Application.get_env(:quack, :webhook_url) == default - - on_exit(fn -> - Application.put_env(:quack, :level, level) - Application.put_env(:quack, :meta, meta) - end) - end - - test "transfer config values with full subkey update" do - clear_config(:emoji) - clear_config(:assets) - - insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]]) - insert(:config, key: :assets, value: [mascots: [a: 1, b: 2]]) - - TransferTask.start_link([]) - - emoji_env = Application.get_env(:pleroma, :emoji) - assert emoji_env[:groups] == [a: 1, b: 2] - assets_env = Application.get_env(:pleroma, :assets) - assert assets_env[:mascots] == [a: 1, b: 2] - end - - describe "pleroma restart" do - setup do - on_exit(fn -> Restarter.Pleroma.refresh() end) - end - - test "don't restart if no reboot time settings were changed" do - clear_config(:emoji) - insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]]) - - refute String.contains?( - capture_log(fn -> TransferTask.start_link([]) end), - "pleroma restarted" - ) - end - - test "on reboot time key" do - clear_config(:chat) - insert(:config, key: :chat, value: [enabled: false]) - assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" - end - - test "on reboot time subkey" do - clear_config(Pleroma.Captcha) - insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) - assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" - end - - test "don't restart pleroma on reboot time key and subkey if there is false flag" do - clear_config(:chat) - clear_config(Pleroma.Captcha) - - insert(:config, key: :chat, value: [enabled: false]) - insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) - - refute String.contains?( - capture_log(fn -> TransferTask.load_and_update_env([], false) end), - "pleroma restarted" - ) - end - end -end diff --git a/test/pleroma/config/versioning_test.exs b/test/pleroma/config/versioning_test.exs new file mode 100644 index 000000000..783952e98 --- /dev/null +++ b/test/pleroma/config/versioning_test.exs @@ -0,0 +1,414 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Config.VersioningTest do + use Pleroma.DataCase, async: true + + import Pleroma.Factory + + alias Pleroma.Config.Version + alias Pleroma.Config.Versioning + alias Pleroma.ConfigDB + alias Pleroma.Repo + + @with_key %{ + group: :pleroma, + key: :instance, + value: [name: "Instance name"] + } + + @without_key %{ + group: :quack, + key: nil, + value: [ + level: :warn, + meta: [:all], + webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" + ] + } + + @value_not_keyword %{ + group: :pleroma, + key: Pleroma.Web.Auth.Authenticator, + value: Pleroma.Web.Auth.PleromaAuthenticator + } + + describe "new_version/1" do + test "creates version" do + changes = [@with_key, @without_key, @value_not_keyword] + + {:ok, + %{ + :insert_version => version, + :update_all_versions => {0, nil}, + {:insert_or_update, :pleroma, :instance} => _, + {:insert_or_update, :quack, nil} => _ + }} = Versioning.new_version(changes) + + assert version.current + assert backup_length(version) == 2 + + assert version.backup[:quack] == @without_key[:value] + + assert version.backup[:pleroma][:instance] == @with_key[:value] + + assert version.backup[:pleroma][Pleroma.Web.Auth.Authenticator] == + @value_not_keyword[:value] + + assert Repo.aggregate(ConfigDB, :count) == 3 + assert Repo.aggregate(Version, :count) == 1 + end + + test "creates several versions" do + change1 = [@with_key] + + {:ok, + %{ + :insert_version => version1, + :update_all_versions => {0, nil}, + {:insert_or_update, :pleroma, :instance} => _ + }} = Versioning.new_version(change1) + + change2 = [@without_key] + + {:ok, + %{ + :insert_version => version2, + :update_all_versions => {1, nil}, + {:insert_or_update, :quack, nil} => _ + }} = Versioning.new_version(change2) + + version1 = refresh_record(version1) + refute version1.current + + assert backup_length(version1) == 1 + + version2 = refresh_record(version2) + assert version2.current + + assert backup_length(version2) == 2 + end + + test "error on empty list" do + assert Versioning.new_version([]) == {:error, :empty_changes} + end + + test "error on bad format" do + assert Versioning.new_version(nil) == {:error, :bad_format} + end + + test "process changes as single map" do + {:ok, + %{ + :insert_version => _, + :update_all_versions => {0, nil}, + {:insert_or_update, :pleroma, :instance} => _ + }} = Versioning.new_version(@with_key) + + assert Repo.aggregate(ConfigDB, :count) == 1 + end + + test "error if value is not keyword" do + assert Versioning.new_version([ + %{group: :pleroma, key: :key, value: %{}} + ]) == + {:error, {:error, :pleroma, :key}, + {:value_must_be_keyword, %{group: :pleroma, key: :key, value: %{}}}, %{}} + end + + test "error if value is list" do + assert Versioning.new_version([ + %{group: :pleroma, key: :key, value: [1]} + ]) == + {:error, {:error, :pleroma, :key}, + {:value_must_be_keyword, %{group: :pleroma, key: :key, value: [1]}}, %{}} + end + end + + describe "rollback/1" do + test "bad steps format" do + assert Versioning.rollback(nil) == {:error, :steps_format} + end + + test "no versions" do + assert Versioning.rollback() == {:error, :no_current_version} + end + + test "rollback not possible, because there is only one version" do + {:ok, _} = Versioning.new_version(@with_key) + + assert Versioning.rollback() == {:error, :rollback_not_possible} + end + + test "rollbacks to previous version" do + {:ok, _} = Versioning.new_version(@with_key) + + {:ok, _} = Versioning.new_version(@value_not_keyword) + + {:ok, _} = Versioning.new_version(@without_key) + + {:ok, _} = Versioning.rollback() + + configs = ConfigDB.all() + + Enum.each(configs, fn + %{key: :instance} = config -> + config.value == @with_key[:value] + + %{key: Pleroma.Web.Auth.Authenticator} = config -> + config.value == @value_not_keyword[:value] + end) + + assert Repo.aggregate(Version, :count) == 2 + + version = Repo.get_by(Version, current: true) + + assert version.backup[:pleroma][:instance] == @with_key[:value] + + assert version.backup[:pleroma][Pleroma.Web.Auth.Authenticator] == + @value_not_keyword[:value] + end + + test "rollbacks with 2 steps" do + {:ok, _} = Versioning.new_version(@with_key) + + {:ok, _} = Versioning.new_version(@without_key) + + {:ok, _} = + Versioning.new_version(%{ + group: :pleroma, + key: :instance, + value: [name: "New name"] + }) + + assert Repo.aggregate(ConfigDB, :count) == 2 + assert Repo.aggregate(Version, :count) == 3 + {:ok, _} = Versioning.rollback(2) + + assert Repo.aggregate(Version, :count) == 1 + + [with_key] = ConfigDB.all() + + assert with_key.value == @with_key[:value] + end + + test "rollbacks with 2 steps and creates new version for new change" do + {:ok, _} = Versioning.new_version(@with_key) + + {:ok, _} = Versioning.new_version(@without_key) + + {:ok, _} = + Versioning.new_version(%{ + group: :pleroma, + key: :instance, + value: [name: "New name"] + }) + + {:ok, _} = Versioning.rollback(2) + + {:ok, _} = + Versioning.new_version(%{ + group: :pleroma, + key: :instance, + value: [name: "Last name"] + }) + + [with_key] = ConfigDB.all() + assert with_key.value == [name: "Last name"] + end + + test "properly rollbacks with settings without keys" do + {:ok, _} = Versioning.new_version(@with_key) + + {:ok, _} = Versioning.new_version(@without_key) + + {:ok, _} = + Versioning.new_version(%{ + group: :pleroma, + key: :instance, + value: [name: "New name"] + }) + + {:ok, _} = Versioning.rollback() + + config = ConfigDB.get_by_params(%{group: :quack}) + assert config.value == @without_key[:value] + end + + test "properly rollbacks with logger settings" do + {:ok, _} = Versioning.new_version(@with_key) + + {:ok, _} = + Versioning.new_version([ + %{ + group: :logger, + value: [ + console: [ + level: :debug, + format: "\n$time $metadata[$level] $message\n", + metadata: [:request_id] + ], + backends: [:console] + ] + } + ]) + + {:ok, _} = Versioning.new_version(@without_key) + + {:ok, _} = Versioning.rollback() + + logger = ConfigDB.get_by_params(%{group: :logger}) + + assert logger.value == [ + console: [ + level: :debug, + format: "\n$time $metadata[$level] $message\n", + metadata: [:request_id] + ], + backends: [:console] + ] + end + end + + describe "migrate/1" do + test "migrates settings from config file" do + {:ok, _} = Versioning.migrate("test/fixtures/config/temp.secret.exs") + + assert Repo.aggregate(ConfigDB, :count) == 3 + + config1 = ConfigDB.get_by_params(%{group: :pleroma, key: :first_setting}) + config2 = ConfigDB.get_by_params(%{group: :pleroma, key: :second_setting}) + config3 = ConfigDB.get_by_params(%{group: :quack}) + + assert config1.value == [key: "value", key2: [Repo]] + assert config2.value == [key: "value2", key2: ["Activity"]] + assert config3.value == [level: :info] + + [version] = Repo.all(Version) + + assert version.backup == [ + pleroma: [ + second_setting: [key: "value2", key2: ["Activity"]], + first_setting: [key: "value", key2: [Repo]] + ], + quack: [level: :info] + ] + end + + test "truncates table on migration" do + insert_list(4, :config) + + assert Repo.aggregate(ConfigDB, :count) == 4 + + {:ok, _} = Versioning.migrate("test/fixtures/config/temp.secret.exs") + + assert Repo.aggregate(ConfigDB, :count) == 3 + end + end + + describe "migrate_namespace/2" do + test "common namespace rename" do + value_before_migration = [name: "Name"] + + {:ok, %{:insert_version => version1}} = + Versioning.new_version(%{ + group: :pleroma, + key: :key1, + value: value_before_migration + }) + + {:ok, %{:insert_version => version2}} = + Versioning.new_version(%{ + group: :pleroma, + key: :key2, + value: [name: "Name"] + }) + + {:ok, %{:insert_version => version3}} = + Versioning.new_version(%{ + group: :pleroma, + key: :key3, + value: [name: "Name"] + }) + + {:ok, _} = Versioning.migrate_namespace({:pleroma, :key1}, {:ex_aws, :new_key}) + + version1 = refresh_record(version1) + assert version1.backup == [ex_aws: [new_key: [name: "Name"]]] + version2 = refresh_record(version2) + + assert version2.backup == [ + ex_aws: [new_key: [name: "Name"]], + pleroma: [key2: [name: "Name"]] + ] + + version3 = refresh_record(version3) + + assert version3.backup == [ + ex_aws: [new_key: [name: "Name"]], + pleroma: [key2: [name: "Name"], key3: [name: "Name"]] + ] + + assert Repo.aggregate(from(c in ConfigDB, where: c.group == ^:pleroma), :count, :id) == 2 + config = ConfigDB.get_by_params(%{group: :ex_aws, key: :new_key}) + assert config.value == value_before_migration + + {:ok, _} = Versioning.migrate_namespace({:pleroma, :key2}, {:pleroma, :new_key}) + + version1 = refresh_record(version1) + assert version1.backup == [ex_aws: [new_key: [name: "Name"]]] + version2 = refresh_record(version2) + + assert version2.backup == [ + pleroma: [new_key: [name: "Name"]], + ex_aws: [new_key: [name: "Name"]] + ] + + version3 = refresh_record(version3) + + assert version3.backup == [ + ex_aws: [new_key: [name: "Name"]], + pleroma: [new_key: [name: "Name"], key3: [name: "Name"]] + ] + end + + test "old namespace exists in old backups" do + {:ok, %{:insert_version => version1}} = + Versioning.new_version(%{ + group: :pleroma, + key: :key1, + value: [name: "Name"] + }) + + {:ok, %{:insert_version => version2}} = + Versioning.new_version([ + %{ + group: :pleroma, + key: :key2, + value: [name: "Name"] + }, + %{group: :pleroma, key: :key1, delete: true} + ]) + + {:ok, _} = Versioning.migrate_namespace({:pleroma, :key1}, {:ex_aws, :new_key}) + + version1 = refresh_record(version1) + assert version1.backup == [ex_aws: [new_key: [name: "Name"]]] + version2 = refresh_record(version2) + + assert version2.backup == [ + pleroma: [key2: [name: "Name"]] + ] + + assert Repo.aggregate(from(c in ConfigDB, where: c.group == ^:pleroma), :count, :id) == 1 + refute ConfigDB.get_by_params(%{group: :ex_aws, key: :new_key}) + end + end + + defp backup_length(%{backup: backup}) do + backup + |> Keyword.keys() + |> length() + end +end diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index d42123fb4..26704169a 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -14,7 +14,7 @@ defmodule Pleroma.ConfigDBTest do assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key}) end - test "get_all_as_keyword/0" do + test "all_as_keyword/0" do saved = insert(:config) insert(:config, group: ":quack", key: ":level", value: :info) insert(:config, group: ":quack", key: ":meta", value: [:none]) @@ -25,7 +25,7 @@ defmodule Pleroma.ConfigDBTest do value: "https://hooks.slack.com/services/KEY/some_val" ) - config = ConfigDB.get_all_as_keyword() + config = ConfigDB.all_as_keyword() assert config[:pleroma] == [ {saved.key, saved.value} @@ -38,12 +38,12 @@ defmodule Pleroma.ConfigDBTest do describe "update_or_create/1" do test "common" do - config = insert(:config) + config1 = insert(:config, value: []) key2 = :another_key params = [ - %{group: :pleroma, key: key2, value: "another_value"}, - %{group: :pleroma, key: config.key, value: [a: 1, b: 2, c: "new_value"]} + %{group: :pleroma, key: config1.key, value: [a: 1, b: 2, c: "new_value"]}, + %{group: :pleroma, key: key2, value: [new_val: "another_value"]} ] assert Repo.all(ConfigDB) |> length() == 1 @@ -52,11 +52,11 @@ defmodule Pleroma.ConfigDBTest do assert Repo.all(ConfigDB) |> length() == 2 - config1 = ConfigDB.get_by_params(%{group: config.group, key: config.key}) + config1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key}) config2 = ConfigDB.get_by_params(%{group: :pleroma, key: key2}) assert config1.value == [a: 1, b: 2, c: "new_value"] - assert config2.value == "another_value" + assert config2.value == [new_val: "another_value"] end test "partial update" do @@ -95,50 +95,18 @@ defmodule Pleroma.ConfigDBTest do assert updated.value[:key3] == :val3 end - test "only full update for some keys" do - config1 = insert(:config, key: :ecto_repos, value: [repo: Pleroma.Repo]) - - config2 = insert(:config, group: :cors_plug, key: :max_age, value: 18) - - {:ok, _config} = - ConfigDB.update_or_create(%{ - group: config1.group, - key: config1.key, - value: [another_repo: [Pleroma.Repo]] - }) - - {:ok, _config} = - ConfigDB.update_or_create(%{ - group: config2.group, - key: config2.key, - value: 777 - }) - - updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key}) - updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key}) - - assert updated1.value == [another_repo: [Pleroma.Repo]] - assert updated2.value == 777 - end - - test "full update if value is not keyword" do - config = - insert(:config, - group: ":tesla", - key: ":adapter", - value: Tesla.Adapter.Hackney - ) + test "only full update for groups without keys" do + config = insert(:config, group: :cors_plug, key: nil, value: [max_age: 18]) {:ok, _config} = ConfigDB.update_or_create(%{ group: config.group, - key: config.key, - value: Tesla.Adapter.Httpc + key: nil, + value: [max_age: 25, credentials: true] }) updated = ConfigDB.get_by_params(%{group: config.group, key: config.key}) - - assert updated.value == Tesla.Adapter.Httpc + assert updated.value == [max_age: 25, credentials: true] end test "only full update for some subkeys" do @@ -176,15 +144,14 @@ defmodule Pleroma.ConfigDBTest do end end - describe "delete/1" do + describe "delete_or_update/1" do test "error on deleting non existing setting" do - {:error, error} = ConfigDB.delete(%{group: ":pleroma", key: ":key"}) - assert error =~ "Config with params %{group: \":pleroma\", key: \":key\"} not found" + assert {:ok, nil} == ConfigDB.delete_or_update(%{group: :pleroma, key: :key}) end test "full delete" do config = insert(:config) - {:ok, deleted} = ConfigDB.delete(%{group: config.group, key: config.key}) + {:ok, deleted} = ConfigDB.delete_or_update(%{group: config.group, key: config.key}) assert Ecto.get_meta(deleted, :state) == :deleted refute ConfigDB.get_by_params(%{group: config.group, key: config.key}) end @@ -193,7 +160,7 @@ defmodule Pleroma.ConfigDBTest do config = insert(:config, value: [groups: [a: 1, b: 2], key: [a: 1]]) {:ok, deleted} = - ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]}) + ConfigDB.delete_or_update(%{group: config.group, key: config.key, subkeys: [:groups]}) assert Ecto.get_meta(deleted, :state) == :loaded @@ -208,339 +175,246 @@ defmodule Pleroma.ConfigDBTest do config = insert(:config, value: [groups: [a: 1, b: 2]]) {:ok, deleted} = - ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]}) + ConfigDB.delete_or_update(%{group: config.group, key: config.key, subkeys: [:groups]}) assert Ecto.get_meta(deleted, :state) == :deleted refute ConfigDB.get_by_params(%{group: config.group, key: config.key}) end - end - - describe "to_elixir_types/1" do - test "string" do - assert ConfigDB.to_elixir_types("value as string") == "value as string" - end - - test "boolean" do - assert ConfigDB.to_elixir_types(false) == false - end - test "nil" do - assert ConfigDB.to_elixir_types(nil) == nil + test "delete struct" do + config = insert(:config) + {:ok, config} = ConfigDB.delete(config) + assert Ecto.get_meta(config, :state) == :deleted + assert Pleroma.Repo.aggregate(ConfigDB, :count) == 0 end + end - test "integer" do - assert ConfigDB.to_elixir_types(150) == 150 - end + test "all/0" do + config = insert(:config) - test "atom" do - assert ConfigDB.to_elixir_types(":atom") == :atom - end + assert [^config] = ConfigDB.all() + end - test "ssl options" do - assert ConfigDB.to_elixir_types([":tlsv1", ":tlsv1.1", ":tlsv1.2"]) == [ - :tlsv1, - :"tlsv1.1", - :"tlsv1.2" - ] - end + describe "reduce_defaults_and_merge_with_changes/2" do + test "common changes" do + defaults = [ + pleroma: [ + key1: [k1: 1, k2: 1, k3: 1], + key2: [k1: 2, k2: 2, k3: 2] + ], + logger: [k1: 3, k2: 3] + ] - test "pleroma module" do - assert ConfigDB.to_elixir_types("Pleroma.Bookmark") == Pleroma.Bookmark - end + config1 = insert(:config, key: :key1, value: [k1: 4, k2: 4]) + config2 = insert(:config, key: :key2, value: [k1: 5, k2: 5]) - test "pleroma string" do - assert ConfigDB.to_elixir_types("Pleroma") == "Pleroma" - end + {changes, [logger: [k1: 3, k2: 3]]} = + ConfigDB.reduce_defaults_and_merge_with_changes([config1, config2], defaults) - test "phoenix module" do - assert ConfigDB.to_elixir_types("Phoenix.Socket.V1.JSONSerializer") == - Phoenix.Socket.V1.JSONSerializer - end + Enum.each(changes, fn + %{key: :key1, value: value} -> + assert value == [k3: 1, k1: 4, k2: 4] - test "tesla module" do - assert ConfigDB.to_elixir_types("Tesla.Adapter.Hackney") == Tesla.Adapter.Hackney + %{key: :key2, value: value} -> + assert value == [k3: 2, k1: 5, k2: 5] + end) end - test "ExSyslogger module" do - assert ConfigDB.to_elixir_types("ExSyslogger") == ExSyslogger - end + test "changes for group without key" do + defaults = [ + cors_plug: [ + max_age: 86_400, + methods: ["POST", "PUT", "DELETE", "GET", "PATCH", "OPTIONS"] + ], + pleroma: [key1: [k1: 1, k2: 1, k3: 1]] + ] - test "Quack.Logger module" do - assert ConfigDB.to_elixir_types("Quack.Logger") == Quack.Logger - end + config = insert(:config, group: :cors_plug, key: nil, value: [max_age: 60_000]) - test "Swoosh.Adapters modules" do - assert ConfigDB.to_elixir_types("Swoosh.Adapters.SMTP") == Swoosh.Adapters.SMTP - assert ConfigDB.to_elixir_types("Swoosh.Adapters.AmazonSES") == Swoosh.Adapters.AmazonSES - end + {[change], [pleroma: [key1: [k1: 1, k2: 1, k3: 1]]]} = + ConfigDB.reduce_defaults_and_merge_with_changes([config], defaults) - test "sigil" do - assert ConfigDB.to_elixir_types("~r[comp[lL][aA][iI][nN]er]") == ~r/comp[lL][aA][iI][nN]er/ + assert change.value == [ + methods: ["POST", "PUT", "DELETE", "GET", "PATCH", "OPTIONS"], + max_age: 60_000 + ] end - test "link sigil" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/") == ~r/https:\/\/example.com/ - end + test "for logger backend setting and others" do + defaults = [ + logger: [ + ex_syslogger: [k1: 1, k2: 1], + console: [k1: 2, k2: 2], + backends: [:ex_syslogger, :console], + key: 1 + ], + pleroma: [key1: 1, key2: 2] + ] - test "link sigil with um modifiers" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/um") == - ~r/https:\/\/example.com/um - end + logger = + insert(:config, + group: :logger, + key: nil, + value: [ex_syslogger: [k1: 3, k2: 4], backends: [:console]] + ) - test "link sigil with i modifier" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/i") == ~r/https:\/\/example.com/i - end + {[change], [pleroma: [key1: 1, key2: 2]]} = + ConfigDB.reduce_defaults_and_merge_with_changes([logger], defaults) - test "link sigil with s modifier" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/s") == ~r/https:\/\/example.com/s + assert change.value == [ + console: [k1: 2, k2: 2], + key: 1, + ex_syslogger: [k1: 3, k2: 4], + backends: [:console] + ] end - test "raise if valid delimiter not found" do - assert_raise ArgumentError, "valid delimiter for Regex expression not found", fn -> - ConfigDB.to_elixir_types("~r/https://[]{}<>\"'()|example.com/s") - end - end + test "with ex_syslogger, console and backends changes" do + defaults = [ + logger: [ + ex_syslogger: [k1: 1, k2: 1], + console: [k1: 2, k2: 2], + backends: [:ex_syslogger, :console], + key: 1 + ], + pleroma: [key1: 1, key2: 2] + ] - test "2 child tuple" do - assert ConfigDB.to_elixir_types(%{"tuple" => ["v1", ":v2"]}) == {"v1", :v2} - end + logger = + insert(:config, + group: :logger, + key: nil, + value: [console: [k1: 4, k2: 4], k1: 3, k2: 4, backends: [:console]] + ) - test "proxy tuple with localhost" do - assert ConfigDB.to_elixir_types(%{ - "tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}] - }) == {:proxy_url, {:socks5, :localhost, 1234}} - end + {[change], [pleroma: [key1: 1, key2: 2]]} = + ConfigDB.reduce_defaults_and_merge_with_changes([logger], defaults) - test "proxy tuple with domain" do - assert ConfigDB.to_elixir_types(%{ - "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}] - }) == {:proxy_url, {:socks5, 'domain.com', 1234}} + assert change.value == [ + ex_syslogger: [k1: 1, k2: 1], + key: 1, + console: [k1: 4, k2: 4], + k1: 3, + k2: 4, + backends: [:console] + ] end + end - test "proxy tuple with ip" do - assert ConfigDB.to_elixir_types(%{ - "tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}] - }) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}} - end + test "all_with_db/0" do + config = insert(:config) + [change] = ConfigDB.all_with_db() + assert change.db == Keyword.keys(config.value) + end - test "tuple with n childs" do - assert ConfigDB.to_elixir_types(%{ - "tuple" => [ - "v1", - ":v2", - "Pleroma.Bookmark", - 150, - false, - "Phoenix.Socket.V1.JSONSerializer" + test "from_keyword_to_structs/2" do + keyword = [ + pleroma: [ + key1: [k1: 1, k2: 1, k3: 1], + key2: [k1: 2, k2: 2, k3: 2] + ], + logger: [k1: 3, k2: 3, ex_syslogger: [k1: 4, k2: 4], console: [k1: 5, k2: 5]] + ] + + changes = ConfigDB.from_keyword_to_structs(keyword) + + Enum.each(changes, fn + %{key: :key1} = change -> + assert change.group == :pleroma + assert change.value == [k1: 1, k2: 1, k3: 1] + + %{key: :key2} = change -> + assert change.group == :pleroma + assert change.value == [k1: 2, k2: 2, k3: 2] + + %{key: nil} = change -> + assert change.group == :logger + + assert change.value == [ + k1: 3, + k2: 3, + ex_syslogger: [k1: 4, k2: 4], + console: [k1: 5, k2: 5] ] - }) == {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} - end + end) + end - test "map with string key" do - assert ConfigDB.to_elixir_types(%{"key" => "value"}) == %{"key" => "value"} - end + describe "merge_changes_with_defaults/2" do + test "with existance changes" do + defaults = [ + pleroma: [ + key1: [k1: 1, k2: 1, k3: 1], + key2: [k1: 2, k2: 2, k3: 2] + ], + logger: [k1: 3, k2: 3] + ] - test "map with atom key" do - assert ConfigDB.to_elixir_types(%{":key" => "value"}) == %{key: "value"} - end + config1 = insert(:config, key: :key1, value: [k1: 4, k2: 4]) + config2 = insert(:config, key: :key2, value: [k1: 5, k2: 5]) - test "list of strings" do - assert ConfigDB.to_elixir_types(["v1", "v2", "v3"]) == ["v1", "v2", "v3"] - end + changes = ConfigDB.merge_changes_with_defaults([config1, config2], defaults) - test "list of modules" do - assert ConfigDB.to_elixir_types(["Pleroma.Repo", "Pleroma.Activity"]) == [ - Pleroma.Repo, - Pleroma.Activity - ] + Enum.each(changes, fn + %{key: :key1} = change -> assert change.value == [k3: 1, k1: 4, k2: 4] + %{key: :key2} = change -> assert change.value == [k3: 2, k1: 5, k2: 5] + end) end - test "list of atoms" do - assert ConfigDB.to_elixir_types([":v1", ":v2", ":v3"]) == [:v1, :v2, :v3] - end + test "full subkey update and deep merge" do + defaults = [ + pleroma: [ + assets: [ + mascots: [3, 4], + subkey: [key1: [key: :val2, key2: :val2], key2: :val2], + key: 5 + ] + ] + ] - test "list of mixed values" do - assert ConfigDB.to_elixir_types([ - "v1", - ":v2", - "Pleroma.Repo", - "Phoenix.Socket.V1.JSONSerializer", - 15, - false - ]) == [ - "v1", - :v2, - Pleroma.Repo, - Phoenix.Socket.V1.JSONSerializer, - 15, - false - ] - end + config = + insert(:config, + group: :pleroma, + key: :assets, + value: [mascots: [1, 2], subkey: [key1: [key: :val1, key2: :val1], key2: :val1]] + ) - test "simple keyword" do - assert ConfigDB.to_elixir_types([%{"tuple" => [":key", "value"]}]) == [key: "value"] - end + [merged] = ConfigDB.merge_changes_with_defaults([config], defaults) - test "keyword" do - assert ConfigDB.to_elixir_types([ - %{"tuple" => [":types", "Pleroma.PostgresTypes"]}, - %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]}, - %{"tuple" => [":migration_lock", nil]}, - %{"tuple" => [":key1", 150]}, - %{"tuple" => [":key2", "string"]} - ]) == [ - types: Pleroma.PostgresTypes, - telemetry_event: [Pleroma.Repo.Instrumenter], - migration_lock: nil, - key1: 150, - key2: "string" + assert merged.value == [ + mascots: [1, 2], + key: 5, + subkey: [key1: [key: :val1, key2: :val1], key2: :val1] ] end - test "trandformed keyword" do - assert ConfigDB.to_elixir_types(a: 1, b: 2, c: "string") == [a: 1, b: 2, c: "string"] - end + test "merge for other subkeys" do + defaults = [pleroma: [assets: [key: 5]]] - test "complex keyword with nested mixed childs" do - assert ConfigDB.to_elixir_types([ - %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]}, - %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]}, - %{"tuple" => [":link_name", true]}, - %{"tuple" => [":proxy_remote", false]}, - %{"tuple" => [":common_map", %{":key" => "value"}]}, - %{ - "tuple" => [ - ":proxy_opts", - [ - %{"tuple" => [":redirect_on_failure", false]}, - %{"tuple" => [":max_body_length", 1_048_576]}, - %{ - "tuple" => [ - ":http", - [ - %{"tuple" => [":follow_redirect", true]}, - %{"tuple" => [":pool", ":upload"]} - ] - ] - } - ] - ] - } - ]) == [ - uploader: Pleroma.Uploaders.Local, - filters: [Pleroma.Upload.Filter.Dedupe], - link_name: true, - proxy_remote: false, - common_map: %{key: "value"}, - proxy_opts: [ - redirect_on_failure: false, - max_body_length: 1_048_576, - http: [ - follow_redirect: true, - pool: :upload - ] - ] - ] - end + config = + insert(:config, + group: :pleroma, + key: :assets, + value: [subkey: 3, default_mascot: :test_mascot] + ) - test "common keyword" do - assert ConfigDB.to_elixir_types([ - %{"tuple" => [":level", ":warn"]}, - %{"tuple" => [":meta", [":all"]]}, - %{"tuple" => [":path", ""]}, - %{"tuple" => [":val", nil]}, - %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]} - ]) == [ - level: :warn, - meta: [:all], - path: "", - val: nil, - webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" - ] + [merged] = ConfigDB.merge_changes_with_defaults([config], defaults) + assert merged.value == [key: 5, subkey: 3, default_mascot: :test_mascot] end - test "complex keyword with sigil" do - assert ConfigDB.to_elixir_types([ - %{"tuple" => [":federated_timeline_removal", []]}, - %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]}, - %{"tuple" => [":replace", []]} - ]) == [ - federated_timeline_removal: [], - reject: [~r/comp[lL][aA][iI][nN]er/], - replace: [] - ] - end + test "with change deletion" do + defaults = [pleroma: [assets: [key: 5]]] - test "complex keyword with tuples with more than 2 values" do - assert ConfigDB.to_elixir_types([ - %{ - "tuple" => [ - ":http", - [ - %{ - "tuple" => [ - ":key1", - [ - %{ - "tuple" => [ - ":_", - [ - %{ - "tuple" => [ - "/api/v1/streaming", - "Pleroma.Web.MastodonAPI.WebsocketHandler", - [] - ] - }, - %{ - "tuple" => [ - "/websocket", - "Phoenix.Endpoint.CowboyWebSocket", - %{ - "tuple" => [ - "Phoenix.Transports.WebSocket", - %{ - "tuple" => [ - "Pleroma.Web.Endpoint", - "Pleroma.Web.UserSocket", - [] - ] - } - ] - } - ] - }, - %{ - "tuple" => [ - ":_", - "Phoenix.Endpoint.Cowboy2Handler", - %{"tuple" => ["Pleroma.Web.Endpoint", []]} - ] - } - ] - ] - } - ] - ] - } - ] - ] - } - ]) == [ - http: [ - key1: [ - {:_, - [ - {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, - {"/websocket", Phoenix.Endpoint.CowboyWebSocket, - {Phoenix.Transports.WebSocket, - {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}}, - {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} - ]} - ] - ] - ] + config = + insert(:config, + group: :pleroma, + key: :assets, + value: [subkey: 3, default_mascot: :test_mascot] + ) + + {:ok, config} = ConfigDB.delete(config) + [merged] = ConfigDB.merge_changes_with_defaults([config], defaults) + assert merged.value == [key: 5] end end end diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 8cd9f939b..5871f3a9e 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo - import ExUnit.CaptureLog import Pleroma.Factory import Swoosh.TestAssertions @@ -322,28 +321,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do setup do: clear_config(:configurable_from_database, true) test "pleroma restarts", %{conn: conn} do - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} - end) =~ "pleroma restarted" + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} - refute Restarter.Pleroma.need_reboot?() + refute Pleroma.Application.ConfigDependentDeps.need_reboot?() end end - test "need_reboot flag", %{conn: conn} do - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => false} - - Restarter.Pleroma.need_reboot() - - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => true} - - on_exit(fn -> Restarter.Pleroma.refresh() end) - end - describe "GET /api/pleroma/admin/users/:nickname/statuses" do setup do user = insert(:user) @@ -999,10 +982,3 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do end end end - -# Needed for testing -defmodule Pleroma.Web.Endpoint.NotReal do -end - -defmodule Pleroma.Captcha.NotReal do -end diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index c39c1b1e1..7a2c8727a 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -5,10 +5,9 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do use Pleroma.Web.ConnCase - import ExUnit.CaptureLog import Pleroma.Factory - alias Pleroma.ConfigDB + alias Pleroma.Config setup do admin = insert(:user, is_admin: true) @@ -18,7 +17,9 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do build_conn() |> assign(:user, admin) |> assign(:token, token) + |> put_req_header("content-type", "application/json") + on_exit(fn -> Pleroma.Application.ConfigDependentDeps.clear_state() end) {:ok, %{admin: admin, token: token, conn: conn}} end @@ -27,9 +28,10 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do test "when configuration from database is off", %{conn: conn} do clear_config(:configurable_from_database, false) - conn = get(conn, "/api/pleroma/admin/config") - assert json_response_and_validate_schema(conn, 400) == + assert conn + |> get("/api/pleroma/admin/config") + |> json_response_and_validate_schema(400) == %{ "error" => "You must enable configurable_from_database in your config file." } @@ -61,7 +63,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do end test "db is added to settings that are in db", %{conn: conn} do - _config = insert(:config, key: ":instance", value: [name: "Some name"]) + _config = insert(:config, key: :instance, value: [name: "Some name"]) %{"configs" => configs} = conn @@ -76,6 +78,27 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert instance_config["db"] == [":name"] end + test "setting with value not keyword", %{conn: conn} do + _config = + insert(:config, + key: Pleroma.Web.Auth.Authenticator, + value: Pleroma.Web.Auth.LDAPAuthenticator + ) + + %{"configs" => configs} = + conn + |> get("/api/pleroma/admin/config") + |> json_response_and_validate_schema(200) + + [instance_config] = + Enum.filter(configs, fn %{"group" => group, "key" => key} -> + group == ":pleroma" and key == "Pleroma.Web.Auth.Authenticator" + end) + + assert instance_config["db"] == ["Pleroma.Web.Auth.Authenticator"] + assert instance_config["value"] == "Pleroma.Web.Auth.LDAPAuthenticator" + end + test "merged default setting with db settings", %{conn: conn} do config1 = insert(:config) config2 = insert(:config) @@ -94,30 +117,19 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do saved_configs = [config1, config2, config3] keys = Enum.map(saved_configs, &inspect(&1.key)) + values = Map.new(saved_configs, fn config -> {config.key, config.value} end) - received_configs = - Enum.filter(configs, fn %{"group" => group, "key" => key} -> + configs = + configs + |> Enum.filter(fn %{"group" => group, "key" => key} -> group == ":pleroma" and key in keys end) + |> Config.Converter.to_elixir_types() - assert length(received_configs) == 3 - - db_keys = - config3.value - |> Keyword.keys() - |> ConfigDB.to_json_types() - - keys = Enum.map(saved_configs -- [config3], &inspect(&1.key)) + assert length(configs) == 3 - values = Enum.map(saved_configs, &ConfigDB.to_json_types(&1.value)) - - mapset_keys = MapSet.new(keys ++ db_keys) - - Enum.each(received_configs, fn %{"value" => value, "db" => db} -> - db = MapSet.new(db) - assert MapSet.subset?(db, mapset_keys) - - assert value in values + Enum.each(configs, fn %{"key" => key, "value" => value} -> + assert values[key] == value end) end @@ -145,8 +157,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) - emoji_val = ConfigDB.to_elixir_types(emoji["value"]) - assets_val = ConfigDB.to_elixir_types(assets["value"]) + emoji_val = Config.Converter.to_elixir_types(emoji["value"]) + assets_val = Config.Converter.to_elixir_types(assets["value"]) assert emoji_val[:groups] == [a: 1, b: 2] assert assets_val[:mascots] == [a: 1, b: 2] @@ -188,13 +200,11 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) Application.put_env(:pleroma, :http, http) Application.put_env(:tesla, :adapter, Tesla.Mock) - Restarter.Pleroma.refresh() end) end setup do: clear_config(:configurable_from_database, true) - @tag capture_log: true test "create new config setting in db", %{conn: conn} do ueberauth = Application.get_env(:ueberauth, Ueberauth) on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) @@ -204,7 +214,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do |> put_req_header("content-type", "application/json") |> post("/api/pleroma/admin/config", %{ configs: [ - %{group: ":pleroma", key: ":key1", value: "value1"}, + %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key", "value1"]}]}, %{ group: ":ueberauth", key: "Ueberauth", @@ -213,31 +223,40 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ group: ":pleroma", key: ":key2", - value: %{ - ":nested_1" => "nested_value1", - ":nested_2" => [ - %{":nested_22" => "nested_value222"}, - %{":nested_33" => %{":nested_44" => "nested_444"}} - ] - } + value: [ + %{"tuple" => [":nested_1", "nested_value1"]}, + %{ + "tuple" => [ + ":nested_2", + [ + %{":nested_22" => "nested_value222"}, + %{":nested_33" => %{":nested_44" => "nested_444"}} + ] + ] + } + ] }, %{ group: ":pleroma", key: ":key3", value: [ - %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, - %{"nested_4" => true} + %{"tuple" => [":key", ":nested_3"]}, + %{"tuple" => [":nested_33", "nested_33"]}, + %{"tuple" => [":key", true]} ] }, %{ group: ":pleroma", key: ":key4", - value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} + value: [ + %{"tuple" => [":nested_5", ":upload"]}, + %{"tuple" => [":endpoint", "https://example.com"]} + ] }, %{ group: ":idna", key: ":key5", - value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} + value: [%{"tuple" => [":string", "Pleroma.Captcha.NotReal"]}] } ] }) @@ -245,86 +264,92 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert json_response_and_validate_schema(conn, 200) == %{ "configs" => [ %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => "value1", - "db" => [":key1"] - }, - %{ + "db" => [":consumer_secret"], "group" => ":ueberauth", "key" => "Ueberauth", - "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], - "db" => [":consumer_secret"] + "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}] }, %{ + "db" => [":nested_5", ":endpoint"], "group" => ":pleroma", - "key" => ":key2", - "value" => %{ - ":nested_1" => "nested_value1", - ":nested_2" => [ - %{":nested_22" => "nested_value222"}, - %{":nested_33" => %{":nested_44" => "nested_444"}} - ] - }, - "db" => [":key2"] + "key" => ":key4", + "value" => [ + %{"tuple" => [":nested_5", ":upload"]}, + %{"tuple" => [":endpoint", "https://example.com"]} + ] }, %{ + "db" => [":key", ":nested_33", ":key"], "group" => ":pleroma", "key" => ":key3", "value" => [ - %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, - %{"nested_4" => true} - ], - "db" => [":key3"] + %{"tuple" => [":key", ":nested_3"]}, + %{"tuple" => [":nested_33", "nested_33"]}, + %{"tuple" => [":key", true]} + ] }, %{ + "db" => [":nested_1", ":nested_2"], "group" => ":pleroma", - "key" => ":key4", - "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, - "db" => [":key4"] + "key" => ":key2", + "value" => [ + %{"tuple" => [":nested_1", "nested_value1"]}, + %{ + "tuple" => [ + ":nested_2", + [ + %{":nested_22" => "nested_value222"}, + %{":nested_33" => %{":nested_44" => "nested_444"}} + ] + ] + } + ] }, %{ + "db" => [":key"], + "group" => ":pleroma", + "key" => ":key1", + "value" => [%{"tuple" => [":key", "value1"]}] + }, + %{ + "db" => [":string"], "group" => ":idna", "key" => ":key5", - "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, - "db" => [":key5"] + "value" => [%{"tuple" => [":string", "Pleroma.Captcha.NotReal"]}] } ], "need_reboot" => false } - assert Application.get_env(:pleroma, :key1) == "value1" + assert Application.get_env(:pleroma, :key1) == [key: "value1"] - assert Application.get_env(:pleroma, :key2) == %{ + assert Application.get_env(:pleroma, :key2) == [ nested_1: "nested_value1", nested_2: [ %{nested_22: "nested_value222"}, %{nested_33: %{nested_44: "nested_444"}} ] - } + ] assert Application.get_env(:pleroma, :key3) == [ - %{"nested_3" => :nested_3, "nested_33" => "nested_33"}, - %{"nested_4" => true} + key: :nested_3, + nested_33: "nested_33", + key: true ] - assert Application.get_env(:pleroma, :key4) == %{ - "endpoint" => "https://example.com", - nested_5: :upload - } + assert Application.get_env(:pleroma, :key4) == [ + nested_5: :upload, + endpoint: "https://example.com" + ] - assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} + assert Application.get_env(:idna, :key5) == [string: Pleroma.Captcha.NotReal] end - test "save configs setting without explicit key", %{conn: conn} do - level = Application.get_env(:quack, :level) - meta = Application.get_env(:quack, :meta) - webhook_url = Application.get_env(:quack, :webhook_url) + test "save configs setting without key", %{conn: conn} do + quack_env = Application.get_all_env(:quack) on_exit(fn -> - Application.put_env(:quack, :level, level) - Application.put_env(:quack, :meta, meta) - Application.put_env(:quack, :webhook_url, webhook_url) + Application.put_all_env(quack: quack_env) end) conn = @@ -334,18 +359,11 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do configs: [ %{ group: ":quack", - key: ":level", - value: ":info" - }, - %{ - group: ":quack", - key: ":meta", - value: [":none"] - }, - %{ - group: ":quack", - key: ":webhook_url", - value: "https://hooks.slack.com/services/KEY" + value: [ + %{"tuple" => [":level", ":info"]}, + %{"tuple" => [":meta", [":none"]]}, + %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/KEY"]} + ] } ] }) @@ -354,21 +372,13 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "configs" => [ %{ "group" => ":quack", - "key" => ":level", - "value" => ":info", - "db" => [":level"] - }, - %{ - "group" => ":quack", - "key" => ":meta", - "value" => [":none"], - "db" => [":meta"] - }, - %{ - "group" => ":quack", - "key" => ":webhook_url", - "value" => "https://hooks.slack.com/services/KEY", - "db" => [":webhook_url"] + "key" => nil, + "value" => [ + %{"tuple" => [":level", ":info"]}, + %{"tuple" => [":meta", [":none"]]}, + %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/KEY"]} + ], + "db" => [":level", ":meta", ":webhook_url"] } ], "need_reboot" => false @@ -380,7 +390,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do end test "saving config with partial update", %{conn: conn} do - insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) + insert(:config, key: ":key1", value: [key1: 1, key2: 2]) conn = conn @@ -440,10 +450,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert configs["need_reboot"] - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == - %{} - end) =~ "pleroma restarted" + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == + %{} configs = conn @@ -499,10 +507,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "need_reboot" => true } - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == - %{} - end) =~ "pleroma restarted" + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == + %{} configs = conn @@ -610,136 +616,86 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do ] end - test "saving full setting if value is in full_key_update list", %{conn: conn} do - backends = Application.get_env(:logger, :backends) - on_exit(fn -> Application.put_env(:logger, :backends, backends) end) - - insert(:config, - group: :logger, - key: :backends, - value: [] - ) - - Pleroma.Config.TransferTask.load_and_update_env([], false) - - assert Application.get_env(:logger, :backends) == [] + test "update config setting & delete with fallback to default value", %{conn: conn} do + ueberauth = Application.get_env(:ueberauth, Ueberauth) + insert(:config, key: :keyaa1, value: [key: "value"]) + insert(:config, key: :keyaa2, value: [key: "value"]) - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ + resp = + post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - group: ":logger", - key: ":backends", - value: [":console"] + group: ":pleroma", + key: ":keyaa1", + value: [ + %{"tuple" => [":key", "value2"]}, + %{"tuple" => [":key2", "value"]} + ] + }, + %{group: ":pleroma", key: ":keyaa2", value: [%{"tuple" => [":key", "value2"]}]}, + %{ + group: ":ueberauth", + key: "Ueberauth", + value: [ + %{"tuple" => [":another_key", "somevalue"]}, + %{"tuple" => [":another", "somevalue"]} + ] + }, + %{ + group: ":pleroma", + key: "Pleroma.Uploaders.Local", + delete: true } ] }) - assert json_response_and_validate_schema(conn, 200) == %{ + assert json_response_and_validate_schema(resp, 200) == %{ "configs" => [ %{ - "group" => ":logger", - "key" => ":backends", + "db" => [":another_key", ":another"], + "group" => ":ueberauth", + "key" => "Ueberauth", "value" => [ - ":console" - ], - "db" => [":backends"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:logger, :backends) == [ - :console - ] - end - - test "saving full setting if value is not keyword", %{conn: conn} do - insert(:config, - group: :tesla, - key: :adapter, - value: Tesla.Adapter.Hackey - ) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":tesla", key: ":adapter", value: "Tesla.Adapter.Httpc"} - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":tesla", - "key" => ":adapter", - "value" => "Tesla.Adapter.Httpc", - "db" => [":adapter"] - } - ], - "need_reboot" => false - } - end - - test "update config setting & delete with fallback to default value", %{ - conn: conn, - admin: admin, - token: token - } do - ueberauth = Application.get_env(:ueberauth, Ueberauth) - insert(:config, key: :keyaa1) - insert(:config, key: :keyaa2) - - config3 = - insert(:config, - group: :ueberauth, - key: Ueberauth - ) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":keyaa1", value: "another_value"}, - %{group: ":pleroma", key: ":keyaa2", value: "another_value"} - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ + %{"tuple" => [":another_key", "somevalue"]}, + %{"tuple" => [":another", "somevalue"]} + ] + }, %{ "group" => ":pleroma", - "key" => ":keyaa1", - "value" => "another_value", - "db" => [":keyaa1"] + "key" => ":keyaa2", + "value" => [ + %{"tuple" => [":key", "value2"]} + ], + "db" => [":key"] }, %{ "group" => ":pleroma", - "key" => ":keyaa2", - "value" => "another_value", - "db" => [":keyaa2"] + "key" => ":keyaa1", + "value" => [ + %{"tuple" => [":key", "value2"]}, + %{"tuple" => [":key2", "value"]} + ], + "db" => [":key", ":key2"] } ], "need_reboot" => false } - assert Application.get_env(:pleroma, :keyaa1) == "another_value" - assert Application.get_env(:pleroma, :keyaa2) == "another_value" - assert Application.get_env(:ueberauth, Ueberauth) == config3.value + assert Application.get_env(:pleroma, :keyaa1) == [key: "value2", key2: "value"] + assert Application.get_env(:pleroma, :keyaa2) == [key: "value2"] - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ + assert Application.get_env(:ueberauth, Ueberauth) == [ + base_path: "/oauth", + providers: [], + another_key: "somevalue", + another: "somevalue" + ] + + resp = + post(conn, "/api/pleroma/admin/config", %{ configs: [ %{group: ":pleroma", key: ":keyaa2", delete: true}, + %{group: ":pleroma", key: ":keyaa1", delete: true, subkeys: [":key"]}, %{ group: ":ueberauth", key: "Ueberauth", @@ -748,8 +704,15 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do ] }) - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [], + assert json_response_and_validate_schema(resp, 200) == %{ + "configs" => [ + %{ + "db" => [":key2"], + "group" => ":pleroma", + "key" => ":keyaa1", + "value" => [%{"tuple" => [":key2", "value"]}] + } + ], "need_reboot" => false } @@ -1023,34 +986,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do } end - test "value as map", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => %{"key" => "some_val"} - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == - %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => %{"key" => "some_val"}, - "db" => [":key1"] - } - ], - "need_reboot" => false - } - end - test "queues key as atom", %{conn: conn} do conn = conn @@ -1228,7 +1163,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert ":proxy_url" in db end - @tag capture_log: true test "doesn't set keys not in the whitelist", %{conn: conn} do clear_config(:database_config_whitelist, [ {:pleroma, :key1}, @@ -1241,21 +1175,29 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do |> put_req_header("content-type", "application/json") |> post("/api/pleroma/admin/config", %{ configs: [ - %{group: ":pleroma", key: ":key1", value: "value1"}, - %{group: ":pleroma", key: ":key2", value: "value2"}, - %{group: ":pleroma", key: ":key3", value: "value3"}, - %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, - %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, - %{group: ":not_real", key: ":anything", value: "value6"} + %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key", "value1"]}]}, + %{group: ":pleroma", key: ":key2", value: [%{"tuple" => [":key", "value2"]}]}, + %{group: ":pleroma", key: ":key3", value: [%{"tuple" => [":key", "value3"]}]}, + %{ + group: ":pleroma", + key: "Pleroma.Web.Endpoint.NotReal", + value: [%{"tuple" => [":key", "value4"]}] + }, + %{ + group: ":pleroma", + key: "Pleroma.Captcha.NotReal", + value: [%{"tuple" => [":key", "value5"]}] + }, + %{group: ":not_real", key: ":anything", value: [%{"tuple" => [":key", "value6"]}]} ] }) - assert Application.get_env(:pleroma, :key1) == "value1" - assert Application.get_env(:pleroma, :key2) == "value2" + assert Application.get_env(:pleroma, :key1) == [key: "value1"] + assert Application.get_env(:pleroma, :key2) == [key: "value2"] assert Application.get_env(:pleroma, :key3) == nil assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil - assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" - assert Application.get_env(:not_real, :anything) == "value6" + assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == [key: "value5"] + assert Application.get_env(:not_real, :anything) == [key: "value6"] end test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do @@ -1445,14 +1387,83 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "need_reboot" => false } - _res = - assert conn - |> get("/api/v1/instance") - |> json_response_and_validate_schema(200) + assert conn + |> get("/api/v1/instance") + |> json_response_and_validate_schema(200) assert res = %{"thumbnail" => "https://example.com/media/new_thumbnail.jpg"} end + test "value bad format error", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":quack", + value: %{} + } + ] + }) + + assert json_response_and_validate_schema(conn, 400) == %{ + "error" => + "Updating config failed: :value_must_be_keyword, group: quack, key: , value: %{}" + } + end + + test "error when value is list", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":quack", + value: [1] + } + ] + }) + + assert json_response_and_validate_schema(conn, 400) == %{ + "error" => + "Updating config failed: :value_must_be_keyword, group: quack, key: , value: [1]" + } + end + + test "saving pleroma group with value not a keyword", %{conn: conn} do + clear_config(Pleroma.Web.Auth.Authenticator) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":pleroma", + key: "Pleroma.Web.Auth.Authenticator", + value: "Pleroma.Web.Auth.LDAPAuthenticator" + } + ] + }) + + assert json_response_and_validate_schema(conn, 200) == %{ + "configs" => [ + %{ + "db" => ["Pleroma.Web.Auth.Authenticator"], + "group" => ":pleroma", + "key" => "Pleroma.Web.Auth.Authenticator", + "value" => "Pleroma.Web.Auth.LDAPAuthenticator" + } + ], + "need_reboot" => false + } + + assert Application.get_env(:pleroma, Pleroma.Web.Auth.Authenticator) == + Pleroma.Web.Auth.LDAPAuthenticator + end + test "Concurrent Limiter", %{conn: conn} do clear_config([ConcurrentLimiter]) @@ -1529,4 +1540,94 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert esshd["children"] end end + + describe "GET /api/pleroma/admin/config/versions/rollback" do + setup do: clear_config(:configurable_from_database, true) + + test "success rollback", %{conn: conn} do + version = insert(:config_version) + insert(:config_version) + insert(:config_version, current: true) + + conn + |> get("/api/pleroma/admin/config/versions/rollback/#{version.id}") + |> json_response_and_validate_schema(204) + + [config] = Pleroma.Repo.all(Pleroma.ConfigDB) + assert config.value == version.backup[config.group][config.key] + end + + test "not found error", %{conn: conn} do + assert conn + |> get("/api/pleroma/admin/config/versions/rollback/1") + |> json_response_and_validate_schema(404) == %{ + "error" => "Not found" + } + end + + test "on rollback to version, which is current", %{conn: conn} do + version = insert(:config_version, current: true) + + assert conn + |> get("/api/pleroma/admin/config/versions/rollback/#{version.id}") + |> json_response_and_validate_schema(400) == %{ + "error" => "Rollback is not possible: :version_is_already_current" + } + end + + test "when configuration from database is off", %{conn: conn} do + clear_config(:configurable_from_database, false) + + assert conn + |> get("/api/pleroma/admin/config/versions/rollback/1") + |> json_response_and_validate_schema(400) == + %{ + "error" => "You must enable configurable_from_database in your config file." + } + end + end + + describe "GET /api/pleroma/admin/config/versions" do + setup do: clear_config(:configurable_from_database, true) + + test "with no versions", %{conn: conn} do + assert conn + |> get("/api/pleroma/admin/config/versions") + |> json_response_and_validate_schema(200) == %{"versions" => []} + end + + test "with versions", %{conn: conn} do + version = insert(:config_version, current: true) + + assert conn + |> get("/api/pleroma/admin/config/versions") + |> json_response_and_validate_schema(200) == %{ + "versions" => [ + %{ + "current" => true, + "id" => version.id, + "inserted_at" => Pleroma.Web.CommonAPI.Utils.to_masto_date(version.inserted_at) + } + ] + } + end + + test "when configuration from database is off", %{conn: conn} do + clear_config(:configurable_from_database, false) + + assert conn + |> get("/api/pleroma/admin/config/versions") + |> json_response_and_validate_schema(400) == + %{ + "error" => "You must enable configurable_from_database in your config file." + } + end + end +end + +# Needed for testing +defmodule Pleroma.Web.Endpoint.NotReal do +end + +defmodule Pleroma.Captcha.NotReal do end |