diff options
Diffstat (limited to 'test/pleroma/config')
-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 |
4 files changed, 874 insertions, 132 deletions
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 |