aboutsummaryrefslogtreecommitdiff
path: root/test/pleroma/config
diff options
context:
space:
mode:
Diffstat (limited to 'test/pleroma/config')
-rw-r--r--test/pleroma/config/converter_test.exs432
-rw-r--r--test/pleroma/config/loader_test.exs40
-rw-r--r--test/pleroma/config/transfer_task_test.exs120
-rw-r--r--test/pleroma/config/versioning_test.exs414
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