diff options
| author | Maksim Pechnikov <parallel588@gmail.com> | 2020-01-23 11:42:10 +0300 | 
|---|---|---|
| committer | Maksim Pechnikov <parallel588@gmail.com> | 2020-01-23 11:42:10 +0300 | 
| commit | 2cfe1b93854c117fda19e54ea17c99f72413a569 (patch) | |
| tree | 1ae8ca344d7f970db4f6f6cb9283d3cf21d1756a /test | |
| parent | 5ea859644897354dfea47655ce39dda46439040a (diff) | |
| parent | dddebee047efc4ab1dff6565bef32954695846a7 (diff) | |
| download | pleroma-2cfe1b93854c117fda19e54ea17c99f72413a569.tar.gz pleroma-2cfe1b93854c117fda19e54ea17c99f72413a569.zip | |
Merge branch 'develop' into feature/tag_feed
Diffstat (limited to 'test')
| -rw-r--r-- | test/config/config_db_test.exs | 704 | ||||
| -rw-r--r-- | test/config/holder_test.exs | 34 | ||||
| -rw-r--r-- | test/config/loader_test.exs | 44 | ||||
| -rw-r--r-- | test/config/transfer_task_test.exs | 98 | ||||
| -rw-r--r-- | test/docs/generator_test.exs | 230 | ||||
| -rw-r--r-- | test/fixtures/config/temp.secret.exs | 9 | ||||
| -rw-r--r-- | test/notification_test.exs | 12 | ||||
| -rw-r--r-- | test/object_test.exs | 40 | ||||
| -rw-r--r-- | test/support/factory.ex | 12 | ||||
| -rw-r--r-- | test/support/helpers.ex | 15 | ||||
| -rw-r--r-- | test/tasks/config_test.exs | 248 | ||||
| -rw-r--r-- | test/tasks/instance_test.exs | 2 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 20 | ||||
| -rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 808 | ||||
| -rw-r--r-- | test/web/admin_api/config_test.exs | 497 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/notification_view_test.exs | 27 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/status_view_test.exs | 7 | ||||
| -rw-r--r-- | test/web/pleroma_api/controllers/pleroma_api_controller_test.exs | 4 | 
18 files changed, 2019 insertions, 792 deletions
| diff --git a/test/config/config_db_test.exs b/test/config/config_db_test.exs new file mode 100644 index 000000000..61a0b1d5d --- /dev/null +++ b/test/config/config_db_test.exs @@ -0,0 +1,704 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ConfigDBTest do +  use Pleroma.DataCase, async: true +  import Pleroma.Factory +  alias Pleroma.ConfigDB + +  test "get_by_key/1" do +    config = insert(:config) +    insert(:config) + +    assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key}) +  end + +  test "create/1" do +    {:ok, config} = ConfigDB.create(%{group: ":pleroma", key: ":some_key", value: "some_value"}) +    assert config == ConfigDB.get_by_params(%{group: ":pleroma", key: ":some_key"}) +  end + +  test "update/1" do +    config = insert(:config) +    {:ok, updated} = ConfigDB.update(config, %{value: "some_value"}) +    loaded = ConfigDB.get_by_params(%{group: config.group, key: config.key}) +    assert loaded == updated +  end + +  test "get_all_as_keyword/0" do +    saved = insert(:config) +    insert(:config, group: ":quack", key: ":level", value: ConfigDB.to_binary(:info)) +    insert(:config, group: ":quack", key: ":meta", value: ConfigDB.to_binary([:none])) + +    insert(:config, +      group: ":quack", +      key: ":webhook_url", +      value: ConfigDB.to_binary("https://hooks.slack.com/services/KEY/some_val") +    ) + +    config = ConfigDB.get_all_as_keyword() + +    assert config[:pleroma] == [ +             {ConfigDB.from_string(saved.key), ConfigDB.from_binary(saved.value)} +           ] + +    assert config[:quack] == [ +             level: :info, +             meta: [:none], +             webhook_url: "https://hooks.slack.com/services/KEY/some_val" +           ] +  end + +  describe "update_or_create/1" do +    test "common" do +      config = insert(:config) +      key2 = "another_key" + +      params = [ +        %{group: "pleroma", key: key2, value: "another_value"}, +        %{group: config.group, key: config.key, value: "new_value"} +      ] + +      assert Repo.all(ConfigDB) |> length() == 1 + +      Enum.each(params, &ConfigDB.update_or_create(&1)) + +      assert Repo.all(ConfigDB) |> length() == 2 + +      config1 = ConfigDB.get_by_params(%{group: config.group, key: config.key}) +      config2 = ConfigDB.get_by_params(%{group: "pleroma", key: key2}) + +      assert config1.value == ConfigDB.transform("new_value") +      assert config2.value == ConfigDB.transform("another_value") +    end + +    test "partial update" do +      config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: :val2)) + +      {:ok, _config} = +        ConfigDB.update_or_create(%{ +          group: config.group, +          key: config.key, +          value: [key1: :val1, key3: :val3] +        }) + +      updated = ConfigDB.get_by_params(%{group: config.group, key: config.key}) + +      value = ConfigDB.from_binary(updated.value) +      assert length(value) == 3 +      assert value[:key1] == :val1 +      assert value[:key2] == :val2 +      assert value[:key3] == :val3 +    end + +    test "deep merge" do +      config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: [k1: :v1, k2: "v2"])) + +      {:ok, config} = +        ConfigDB.update_or_create(%{ +          group: config.group, +          key: config.key, +          value: [key1: :val1, key2: [k2: :v2, k3: :v3], key3: :val3] +        }) + +      updated = ConfigDB.get_by_params(%{group: config.group, key: config.key}) + +      assert config.value == updated.value + +      value = ConfigDB.from_binary(updated.value) +      assert value[:key1] == :val1 +      assert value[:key2] == [k1: :v1, k2: :v2, k3: :v3] +      assert value[:key3] == :val3 +    end + +    test "only full update for some keys" do +      config1 = insert(:config, key: ":ecto_repos", value: ConfigDB.to_binary(repo: Pleroma.Repo)) + +      config2 = +        insert(:config, group: ":cors_plug", key: ":max_age", value: ConfigDB.to_binary(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 ConfigDB.from_binary(updated1.value) == [another_repo: [Pleroma.Repo]] +      assert ConfigDB.from_binary(updated2.value) == 777 +    end + +    test "full update if value is not keyword" do +      config = +        insert(:config, +          group: ":tesla", +          key: ":adapter", +          value: ConfigDB.to_binary(Tesla.Adapter.Hackney) +        ) + +      {:ok, _config} = +        ConfigDB.update_or_create(%{ +          group: config.group, +          key: config.key, +          value: Tesla.Adapter.Httpc +        }) + +      updated = ConfigDB.get_by_params(%{group: config.group, key: config.key}) + +      assert ConfigDB.from_binary(updated.value) == Tesla.Adapter.Httpc +    end + +    test "only full update for some subkeys" do +      config1 = +        insert(:config, +          key: ":emoji", +          value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]) +        ) + +      config2 = +        insert(:config, +          key: ":assets", +          value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1]) +        ) + +      {:ok, _config} = +        ConfigDB.update_or_create(%{ +          group: config1.group, +          key: config1.key, +          value: [groups: [c: 3, d: 4], key: [b: 2]] +        }) + +      {:ok, _config} = +        ConfigDB.update_or_create(%{ +          group: config2.group, +          key: config2.key, +          value: [mascots: [c: 3, d: 4], key: [b: 2]] +        }) + +      updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key}) +      updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key}) + +      assert ConfigDB.from_binary(updated1.value) == [groups: [c: 3, d: 4], key: [a: 1, b: 2]] +      assert ConfigDB.from_binary(updated2.value) == [mascots: [c: 3, d: 4], key: [a: 1, b: 2]] +    end +  end + +  describe "delete/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" +    end + +    test "full delete" do +      config = insert(:config) +      {:ok, deleted} = ConfigDB.delete(%{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 + +    test "partial subkeys delete" do +      config = insert(:config, value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])) + +      {:ok, deleted} = +        ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]}) + +      assert Ecto.get_meta(deleted, :state) == :loaded + +      assert deleted.value == ConfigDB.to_binary(key: [a: 1]) + +      updated = ConfigDB.get_by_params(%{group: config.group, key: config.key}) + +      assert updated.value == deleted.value +    end + +    test "full delete if remaining value after subkeys deletion is empty list" do +      config = insert(:config, value: ConfigDB.to_binary(groups: [a: 1, b: 2])) + +      {:ok, deleted} = +        ConfigDB.delete(%{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 "transform/1" do +    test "string" do +      binary = ConfigDB.transform("value as string") +      assert binary == :erlang.term_to_binary("value as string") +      assert ConfigDB.from_binary(binary) == "value as string" +    end + +    test "boolean" do +      binary = ConfigDB.transform(false) +      assert binary == :erlang.term_to_binary(false) +      assert ConfigDB.from_binary(binary) == false +    end + +    test "nil" do +      binary = ConfigDB.transform(nil) +      assert binary == :erlang.term_to_binary(nil) +      assert ConfigDB.from_binary(binary) == nil +    end + +    test "integer" do +      binary = ConfigDB.transform(150) +      assert binary == :erlang.term_to_binary(150) +      assert ConfigDB.from_binary(binary) == 150 +    end + +    test "atom" do +      binary = ConfigDB.transform(":atom") +      assert binary == :erlang.term_to_binary(:atom) +      assert ConfigDB.from_binary(binary) == :atom +    end + +    test "ssl options" do +      binary = ConfigDB.transform([":tlsv1", ":tlsv1.1", ":tlsv1.2"]) +      assert binary == :erlang.term_to_binary([:tlsv1, :"tlsv1.1", :"tlsv1.2"]) +      assert ConfigDB.from_binary(binary) == [:tlsv1, :"tlsv1.1", :"tlsv1.2"] +    end + +    test "pleroma module" do +      binary = ConfigDB.transform("Pleroma.Bookmark") +      assert binary == :erlang.term_to_binary(Pleroma.Bookmark) +      assert ConfigDB.from_binary(binary) == Pleroma.Bookmark +    end + +    test "pleroma string" do +      binary = ConfigDB.transform("Pleroma") +      assert binary == :erlang.term_to_binary("Pleroma") +      assert ConfigDB.from_binary(binary) == "Pleroma" +    end + +    test "phoenix module" do +      binary = ConfigDB.transform("Phoenix.Socket.V1.JSONSerializer") +      assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer) +      assert ConfigDB.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer +    end + +    test "tesla module" do +      binary = ConfigDB.transform("Tesla.Adapter.Hackney") +      assert binary == :erlang.term_to_binary(Tesla.Adapter.Hackney) +      assert ConfigDB.from_binary(binary) == Tesla.Adapter.Hackney +    end + +    test "ExSyslogger module" do +      binary = ConfigDB.transform("ExSyslogger") +      assert binary == :erlang.term_to_binary(ExSyslogger) +      assert ConfigDB.from_binary(binary) == ExSyslogger +    end + +    test "Quack.Logger module" do +      binary = ConfigDB.transform("Quack.Logger") +      assert binary == :erlang.term_to_binary(Quack.Logger) +      assert ConfigDB.from_binary(binary) == Quack.Logger +    end + +    test "sigil" do +      binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]") +      assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/) +      assert ConfigDB.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/ +    end + +    test "link sigil" do +      binary = ConfigDB.transform("~r/https:\/\/example.com/") +      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/) +      assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/ +    end + +    test "link sigil with um modifiers" do +      binary = ConfigDB.transform("~r/https:\/\/example.com/um") +      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/um) +      assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/um +    end + +    test "link sigil with i modifier" do +      binary = ConfigDB.transform("~r/https:\/\/example.com/i") +      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/i) +      assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/i +    end + +    test "link sigil with s modifier" do +      binary = ConfigDB.transform("~r/https:\/\/example.com/s") +      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/s) +      assert ConfigDB.from_binary(binary) == ~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 -> +        ConfigDB.transform("~r/https://[]{}<>\"'()|example.com/s") +      end +    end + +    test "2 child tuple" do +      binary = ConfigDB.transform(%{"tuple" => ["v1", ":v2"]}) +      assert binary == :erlang.term_to_binary({"v1", :v2}) +      assert ConfigDB.from_binary(binary) == {"v1", :v2} +    end + +    test "proxy tuple with localhost" do +      binary = +        ConfigDB.transform(%{ +          "tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}] +        }) + +      assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, :localhost, 1234}}) +      assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, :localhost, 1234}} +    end + +    test "proxy tuple with domain" do +      binary = +        ConfigDB.transform(%{ +          "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}] +        }) + +      assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, 'domain.com', 1234}}) +      assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, 'domain.com', 1234}} +    end + +    test "proxy tuple with ip" do +      binary = +        ConfigDB.transform(%{ +          "tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}] +        }) + +      assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}}) +      assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}} +    end + +    test "tuple with n childs" do +      binary = +        ConfigDB.transform(%{ +          "tuple" => [ +            "v1", +            ":v2", +            "Pleroma.Bookmark", +            150, +            false, +            "Phoenix.Socket.V1.JSONSerializer" +          ] +        }) + +      assert binary == +               :erlang.term_to_binary( +                 {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} +               ) + +      assert ConfigDB.from_binary(binary) == +               {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} +    end + +    test "map with string key" do +      binary = ConfigDB.transform(%{"key" => "value"}) +      assert binary == :erlang.term_to_binary(%{"key" => "value"}) +      assert ConfigDB.from_binary(binary) == %{"key" => "value"} +    end + +    test "map with atom key" do +      binary = ConfigDB.transform(%{":key" => "value"}) +      assert binary == :erlang.term_to_binary(%{key: "value"}) +      assert ConfigDB.from_binary(binary) == %{key: "value"} +    end + +    test "list of strings" do +      binary = ConfigDB.transform(["v1", "v2", "v3"]) +      assert binary == :erlang.term_to_binary(["v1", "v2", "v3"]) +      assert ConfigDB.from_binary(binary) == ["v1", "v2", "v3"] +    end + +    test "list of modules" do +      binary = ConfigDB.transform(["Pleroma.Repo", "Pleroma.Activity"]) +      assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity]) +      assert ConfigDB.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity] +    end + +    test "list of atoms" do +      binary = ConfigDB.transform([":v1", ":v2", ":v3"]) +      assert binary == :erlang.term_to_binary([:v1, :v2, :v3]) +      assert ConfigDB.from_binary(binary) == [:v1, :v2, :v3] +    end + +    test "list of mixed values" do +      binary = +        ConfigDB.transform([ +          "v1", +          ":v2", +          "Pleroma.Repo", +          "Phoenix.Socket.V1.JSONSerializer", +          15, +          false +        ]) + +      assert binary == +               :erlang.term_to_binary([ +                 "v1", +                 :v2, +                 Pleroma.Repo, +                 Phoenix.Socket.V1.JSONSerializer, +                 15, +                 false +               ]) + +      assert ConfigDB.from_binary(binary) == [ +               "v1", +               :v2, +               Pleroma.Repo, +               Phoenix.Socket.V1.JSONSerializer, +               15, +               false +             ] +    end + +    test "simple keyword" do +      binary = ConfigDB.transform([%{"tuple" => [":key", "value"]}]) +      assert binary == :erlang.term_to_binary([{:key, "value"}]) +      assert ConfigDB.from_binary(binary) == [{:key, "value"}] +      assert ConfigDB.from_binary(binary) == [key: "value"] +    end + +    test "keyword with partial_chain key" do +      binary = +        ConfigDB.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}]) + +      assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1) +      assert ConfigDB.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1] +    end + +    test "keyword" do +      binary = +        ConfigDB.transform([ +          %{"tuple" => [":types", "Pleroma.PostgresTypes"]}, +          %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]}, +          %{"tuple" => [":migration_lock", nil]}, +          %{"tuple" => [":key1", 150]}, +          %{"tuple" => [":key2", "string"]} +        ]) + +      assert binary == +               :erlang.term_to_binary( +                 types: Pleroma.PostgresTypes, +                 telemetry_event: [Pleroma.Repo.Instrumenter], +                 migration_lock: nil, +                 key1: 150, +                 key2: "string" +               ) + +      assert ConfigDB.from_binary(binary) == [ +               types: Pleroma.PostgresTypes, +               telemetry_event: [Pleroma.Repo.Instrumenter], +               migration_lock: nil, +               key1: 150, +               key2: "string" +             ] +    end + +    test "complex keyword with nested mixed childs" do +      binary = +        ConfigDB.transform([ +          %{"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"]}] +                  ] +                } +              ] +            ] +          } +        ]) + +      assert binary == +               :erlang.term_to_binary( +                 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 +                   ] +                 ] +               ) + +      assert ConfigDB.from_binary(binary) == +               [ +                 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 +      binary = +        ConfigDB.transform([ +          %{"tuple" => [":level", ":warn"]}, +          %{"tuple" => [":meta", [":all"]]}, +          %{"tuple" => [":path", ""]}, +          %{"tuple" => [":val", nil]}, +          %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]} +        ]) + +      assert binary == +               :erlang.term_to_binary( +                 level: :warn, +                 meta: [:all], +                 path: "", +                 val: nil, +                 webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" +               ) + +      assert ConfigDB.from_binary(binary) == [ +               level: :warn, +               meta: [:all], +               path: "", +               val: nil, +               webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" +             ] +    end + +    test "complex keyword with sigil" do +      binary = +        ConfigDB.transform([ +          %{"tuple" => [":federated_timeline_removal", []]}, +          %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]}, +          %{"tuple" => [":replace", []]} +        ]) + +      assert binary == +               :erlang.term_to_binary( +                 federated_timeline_removal: [], +                 reject: [~r/comp[lL][aA][iI][nN]er/], +                 replace: [] +               ) + +      assert ConfigDB.from_binary(binary) == +               [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []] +    end + +    test "complex keyword with tuples with more than 2 values" do +      binary = +        ConfigDB.transform([ +          %{ +            "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", []]} +                              ] +                            } +                          ] +                        ] +                      } +                    ] +                  ] +                } +              ] +            ] +          } +        ]) + +      assert binary == +               :erlang.term_to_binary( +                 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, []}} +                     ] +                   ] +                 ] +               ) + +      assert ConfigDB.from_binary(binary) == [ +               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 +end diff --git a/test/config/holder_test.exs b/test/config/holder_test.exs new file mode 100644 index 000000000..0c1882d0f --- /dev/null +++ b/test/config/holder_test.exs @@ -0,0 +1,34 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Config.HolderTest do +  use ExUnit.Case, async: true + +  alias Pleroma.Config.Holder + +  test "config/0" do +    config = Holder.config() +    assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads" +    assert config[:tesla][:adapter] == Tesla.Mock + +    refute config[:pleroma][Pleroma.Repo] +    refute config[:pleroma][Pleroma.Web.Endpoint] +    refute config[:pleroma][:env] +    refute config[:pleroma][:configurable_from_database] +    refute config[:pleroma][:database] +    refute config[:phoenix][:serve_endpoints] +  end + +  test "config/1" do +    pleroma_config = Holder.config(:pleroma) +    assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads" +    tesla_config = Holder.config(:tesla) +    assert tesla_config[:adapter] == Tesla.Mock +  end + +  test "config/2" do +    assert Holder.config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"] +    assert Holder.config(:tesla, :adapter) == Tesla.Mock +  end +end diff --git a/test/config/loader_test.exs b/test/config/loader_test.exs new file mode 100644 index 000000000..0dd4c60bb --- /dev/null +++ b/test/config/loader_test.exs @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Config.LoaderTest do +  use ExUnit.Case, async: true + +  alias Pleroma.Config.Loader + +  test "load/1" do +    config = Loader.load("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 "load_and_merge/0" do +    config = Loader.load_and_merge() + +    refute config[:pleroma][Pleroma.Repo] +    refute config[:pleroma][Pleroma.Web.Endpoint] +    refute config[:pleroma][:env] +    refute config[:pleroma][:configurable_from_database] +    refute config[:pleroma][:database] +    refute config[:phoenix][:serve_endpoints] + +    assert config[:pleroma][:ecto_repos] == [Pleroma.Repo] +    assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads" +    assert config[:tesla][:adapter] == Tesla.Mock +  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]}] +  end +end diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index 9074f3b97..b9072e0fc 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -5,47 +5,117 @@  defmodule Pleroma.Config.TransferTaskTest do    use Pleroma.DataCase -  clear_config([:instance, :dynamic_configuration]) do -    Pleroma.Config.put([:instance, :dynamic_configuration], true) +  alias Pleroma.Config.TransferTask +  alias Pleroma.ConfigDB + +  clear_config(:configurable_from_database) do +    Pleroma.Config.put(:configurable_from_database, true)    end    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) -    Pleroma.Web.AdminAPI.Config.create(%{ -      group: "pleroma", -      key: "test_key", +    ConfigDB.create(%{ +      group: ":pleroma", +      key: ":test_key",        value: [live: 2, com: 3]      }) -    Pleroma.Web.AdminAPI.Config.create(%{ -      group: "idna", -      key: "test_key", +    ConfigDB.create(%{ +      group: ":idna", +      key: ":test_key",        value: [live: 15, com: 35]      }) -    Pleroma.Config.TransferTask.start_link([]) +    ConfigDB.create(%{ +      group: ":quack", +      key: ":test_key", +      value: [:test_value1, :test_value2] +    }) + +    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]      on_exit(fn ->        Application.delete_env(:pleroma, :test_key)        Application.delete_env(:idna, :test_key) +      Application.delete_env(:quack, :test_key) +    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) + +    ConfigDB.create(%{ +      group: ":quack", +      key: ":level", +      value: :info +    }) + +    ConfigDB.create(%{ +      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.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 +    emoji = Application.get_env(:pleroma, :emoji) +    assets = Application.get_env(:pleroma, :assets) + +    ConfigDB.create(%{ +      group: ":pleroma", +      key: ":emoji", +      value: [groups: [a: 1, b: 2]] +    }) + +    ConfigDB.create(%{ +      group: ":pleroma", +      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] + +    on_exit(fn -> +      Application.put_env(:pleroma, :emoji, emoji) +      Application.put_env(:pleroma, :assets, assets)      end)    end    test "non existing atom" do -    Pleroma.Web.AdminAPI.Config.create(%{ -      group: "pleroma", -      key: "undefined_atom_key", +    ConfigDB.create(%{ +      group: ":pleroma", +      key: ":undefined_atom_key",        value: [live: 2, com: 3]      })      assert ExUnit.CaptureLog.capture_log(fn -> -             Pleroma.Config.TransferTask.start_link([]) +             TransferTask.start_link([])             end) =~ -             "updating env causes error, key: \"undefined_atom_key\", error: %ArgumentError{message: \"argument error\"}" +             "updating env causes error, group: \":pleroma\" key: \":undefined_atom_key\" value: [live: 2, com: 3] error: %ArgumentError{message: \"argument error\"}"    end  end diff --git a/test/docs/generator_test.exs b/test/docs/generator_test.exs new file mode 100644 index 000000000..9c9f4357b --- /dev/null +++ b/test/docs/generator_test.exs @@ -0,0 +1,230 @@ +defmodule Pleroma.Docs.GeneratorTest do +  use ExUnit.Case, async: true +  alias Pleroma.Docs.Generator + +  @descriptions [ +    %{ +      group: :pleroma, +      key: Pleroma.Upload, +      type: :group, +      description: "", +      children: [ +        %{ +          key: :uploader, +          type: :module, +          description: "", +          suggestions: +            Generator.list_modules_in_dir( +              "lib/pleroma/upload/filter", +              "Elixir.Pleroma.Upload.Filter." +            ) +        }, +        %{ +          key: :filters, +          type: {:list, :module}, +          description: "", +          suggestions: +            Generator.list_modules_in_dir( +              "lib/pleroma/web/activity_pub/mrf", +              "Elixir.Pleroma.Web.ActivityPub.MRF." +            ) +        }, +        %{ +          key: Pleroma.Upload, +          type: :string, +          description: "", +          suggestions: [""] +        }, +        %{ +          key: :some_key, +          type: :keyword, +          description: "", +          suggestions: [], +          children: [ +            %{ +              key: :another_key, +              type: :integer, +              description: "", +              suggestions: [5] +            }, +            %{ +              key: :another_key_with_label, +              label: "Another label", +              type: :integer, +              description: "", +              suggestions: [7] +            } +          ] +        }, +        %{ +          key: :key1, +          type: :atom, +          description: "", +          suggestions: [ +            :atom, +            Pleroma.Upload, +            {:tuple, "string", 8080}, +            [:atom, Pleroma.Upload, {:atom, Pleroma.Upload}] +          ] +        }, +        %{ +          key: Pleroma.Upload, +          label: "Special Label", +          type: :string, +          description: "", +          suggestions: [""] +        }, +        %{ +          group: {:subgroup, Swoosh.Adapters.SMTP}, +          key: :auth, +          type: :atom, +          description: "`Swoosh.Adapters.SMTP` adapter specific setting", +          suggestions: [:always, :never, :if_available] +        }, +        %{ +          key: "application/xml", +          type: {:list, :string}, +          suggestions: ["xml"] +        }, +        %{ +          key: :versions, +          type: {:list, :atom}, +          description: "List of TLS version to use", +          suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"] +        } +      ] +    }, +    %{ +      group: :tesla, +      key: :adapter, +      type: :group, +      description: "" +    }, +    %{ +      group: :cors_plug, +      type: :group, +      children: [%{key: :key1, type: :string, suggestions: [""]}] +    }, +    %{group: "Some string group", key: "Some string key", type: :group} +  ] + +  describe "convert_to_strings/1" do +    test "group, key, label" do +      [desc1, desc2 | _] = Generator.convert_to_strings(@descriptions) + +      assert desc1[:group] == ":pleroma" +      assert desc1[:key] == "Pleroma.Upload" +      assert desc1[:label] == "Pleroma.Upload" + +      assert desc2[:group] == ":tesla" +      assert desc2[:key] == ":adapter" +      assert desc2[:label] == "Adapter" +    end + +    test "group without key" do +      descriptions = Generator.convert_to_strings(@descriptions) +      desc = Enum.at(descriptions, 2) + +      assert desc[:group] == ":cors_plug" +      refute desc[:key] +      assert desc[:label] == "Cors plug" +    end + +    test "children key, label, type" do +      [%{children: [child1, child2, child3, child4 | _]} | _] = +        Generator.convert_to_strings(@descriptions) + +      assert child1[:key] == ":uploader" +      assert child1[:label] == "Uploader" +      assert child1[:type] == :module + +      assert child2[:key] == ":filters" +      assert child2[:label] == "Filters" +      assert child2[:type] == {:list, :module} + +      assert child3[:key] == "Pleroma.Upload" +      assert child3[:label] == "Pleroma.Upload" +      assert child3[:type] == :string + +      assert child4[:key] == ":some_key" +      assert child4[:label] == "Some key" +      assert child4[:type] == :keyword +    end + +    test "child with predefined label" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      child = Enum.at(children, 5) +      assert child[:key] == "Pleroma.Upload" +      assert child[:label] == "Special Label" +    end + +    test "subchild" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      child = Enum.at(children, 3) +      %{children: [subchild | _]} = child + +      assert subchild[:key] == ":another_key" +      assert subchild[:label] == "Another key" +      assert subchild[:type] == :integer +    end + +    test "subchild with predefined label" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      child = Enum.at(children, 3) +      %{children: subchildren} = child +      subchild = Enum.at(subchildren, 1) + +      assert subchild[:key] == ":another_key_with_label" +      assert subchild[:label] == "Another label" +    end + +    test "module suggestions" do +      [%{children: [%{suggestions: suggestions} | _]} | _] = +        Generator.convert_to_strings(@descriptions) + +      Enum.each(suggestions, fn suggestion -> +        assert String.starts_with?(suggestion, "Pleroma.") +      end) +    end + +    test "atoms in suggestions with leading `:`" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      %{suggestions: suggestions} = Enum.at(children, 4) +      assert Enum.at(suggestions, 0) == ":atom" +      assert Enum.at(suggestions, 1) == "Pleroma.Upload" +      assert Enum.at(suggestions, 2) == {":tuple", "string", 8080} +      assert Enum.at(suggestions, 3) == [":atom", "Pleroma.Upload", {":atom", "Pleroma.Upload"}] + +      %{suggestions: suggestions} = Enum.at(children, 6) +      assert Enum.at(suggestions, 0) == ":always" +      assert Enum.at(suggestions, 1) == ":never" +      assert Enum.at(suggestions, 2) == ":if_available" +    end + +    test "group, key as string in main desc" do +      descriptions = Generator.convert_to_strings(@descriptions) +      desc = Enum.at(descriptions, 3) +      assert desc[:group] == "Some string group" +      assert desc[:key] == "Some string key" +    end + +    test "key as string subchild" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      child = Enum.at(children, 7) +      assert child[:key] == "application/xml" +    end + +    test "suggestion for tls versions" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) +      child = Enum.at(children, 8) +      assert child[:suggestions] == [":tlsv1", ":tlsv1.1", ":tlsv1.2"] +    end + +    test "subgroup with module name" do +      [%{children: children} | _] = Generator.convert_to_strings(@descriptions) + +      %{group: subgroup} = Enum.at(children, 6) +      assert subgroup == {":subgroup", "Swoosh.Adapters.SMTP"} +    end +  end +end diff --git a/test/fixtures/config/temp.secret.exs b/test/fixtures/config/temp.secret.exs new file mode 100644 index 000000000..f4686c101 --- /dev/null +++ b/test/fixtures/config/temp.secret.exs @@ -0,0 +1,9 @@ +use Mix.Config + +config :pleroma, :first_setting, key: "value", key2: [Pleroma.Repo] + +config :pleroma, :second_setting, key: "value2", key2: ["Activity"] + +config :quack, level: :info + +config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox diff --git a/test/notification_test.exs b/test/notification_test.exs index 9a1c2f2b5..04bf5b41a 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -15,6 +15,18 @@ defmodule Pleroma.NotificationTest do    alias Pleroma.Web.Streamer    describe "create_notifications" do +    test "creates a notification for an emoji reaction" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"}) +      {:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +      {:ok, [notification]} = Notification.create_notifications(activity) + +      assert notification.user_id == user.id +    end +      test "notifies someone when they are directly addressed" do        user = insert(:user)        other_user = insert(:user) diff --git a/test/object_test.exs b/test/object_test.exs index b002c2bae..9b4e6f0bf 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -4,12 +4,14 @@  defmodule Pleroma.ObjectTest do    use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo    import ExUnit.CaptureLog    import Pleroma.Factory    import Tesla.Mock    alias Pleroma.Activity    alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.Web.CommonAPI    setup do @@ -99,6 +101,8 @@ defmodule Pleroma.ObjectTest do        Object.delete(note) +      ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) +        assert Object.get_by_id(attachment.id) == nil        assert {:ok, []} == File.ls("#{uploads_dir}/#{path}") @@ -133,10 +137,46 @@ defmodule Pleroma.ObjectTest do        Object.delete(note) +      ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) +        assert Object.get_by_id(attachment.id) == nil        assert {:ok, files} = File.ls(uploads_dir)        refute filename in files      end + +    test "with objects that have legacy data.url attribute" do +      Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      user = insert(:user) + +      {:ok, %Object{} = attachment} = +        Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id) + +      {:ok, %Object{}} = Object.create(%{url: "https://google.com", actor: user.ap_id}) + +      %{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} = +        note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}}) + +      uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads]) + +      path = href |> Path.dirname() |> Path.basename() + +      assert {:ok, ["an_image.jpg"]} == File.ls("#{uploads_dir}/#{path}") + +      Object.delete(note) + +      ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) + +      assert Object.get_by_id(attachment.id) == nil + +      assert {:ok, []} == File.ls("#{uploads_dir}/#{path}") +    end    end    describe "normalizer" do diff --git a/test/support/factory.ex b/test/support/factory.ex index 100864055..780235cb9 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -394,9 +394,15 @@ defmodule Pleroma.Factory do    end    def config_factory do -    %Pleroma.Web.AdminAPI.Config{ -      key: sequence(:key, &"some_key_#{&1}"), -      group: "pleroma", +    %Pleroma.ConfigDB{ +      key: +        sequence(:key, fn key -> +          # Atom dynamic registration hack in tests +          "some_key_#{key}" +          |> String.to_atom() +          |> inspect() +        end), +      group: ":pleroma",        value:          sequence(            :value, diff --git a/test/support/helpers.ex b/test/support/helpers.ex index af2b2eddf..9f817622d 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Tests.Helpers do    @moduledoc """    Helpers for use in tests.    """ +  alias Pleroma.Config    defmacro clear_config(config_path) do      quote do @@ -17,9 +18,9 @@ defmodule Pleroma.Tests.Helpers do    defmacro clear_config(config_path, do: yield) do      quote do        setup do -        initial_setting = Pleroma.Config.get(unquote(config_path)) +        initial_setting = Config.get(unquote(config_path))          unquote(yield) -        on_exit(fn -> Pleroma.Config.put(unquote(config_path), initial_setting) end) +        on_exit(fn -> Config.put(unquote(config_path), initial_setting) end)          :ok        end      end @@ -35,9 +36,9 @@ defmodule Pleroma.Tests.Helpers do    defmacro clear_config_all(config_path, do: yield) do      quote do        setup_all do -        initial_setting = Pleroma.Config.get(unquote(config_path)) +        initial_setting = Config.get(unquote(config_path))          unquote(yield) -        on_exit(fn -> Pleroma.Config.put(unquote(config_path), initial_setting) end) +        on_exit(fn -> Config.put(unquote(config_path), initial_setting) end)          :ok        end      end @@ -94,10 +95,10 @@ defmodule Pleroma.Tests.Helpers do        defmacro guards_config(config_path) do          quote do -          initial_setting = Pleroma.Config.get(config_path) +          initial_setting = Config.get(config_path) -          Pleroma.Config.put(config_path, true) -          on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end) +          Config.put(config_path, true) +          on_exit(fn -> Config.put(config_path, initial_setting) end)          end        end      end diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index fab9d6e9a..2e56e6cfe 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -4,143 +4,173 @@  defmodule Mix.Tasks.Pleroma.ConfigTest do    use Pleroma.DataCase + +  alias Pleroma.ConfigDB    alias Pleroma.Repo -  alias Pleroma.Web.AdminAPI.Config    setup_all do      Mix.shell(Mix.Shell.Process) -    temp_file = "config/temp.exported_from_db.secret.exs"      on_exit(fn ->        Mix.shell(Mix.Shell.IO)        Application.delete_env(:pleroma, :first_setting)        Application.delete_env(:pleroma, :second_setting) -      :ok = File.rm(temp_file)      end) -    {:ok, temp_file: temp_file} +    :ok    end -  clear_config_all([:instance, :dynamic_configuration]) do -    Pleroma.Config.put([:instance, :dynamic_configuration], true) +  clear_config_all(:configurable_from_database) do +    Pleroma.Config.put(:configurable_from_database, true)    end -  test "settings are migrated to db" do -    assert Repo.all(Config) == [] - -    Application.put_env(:pleroma, :first_setting, key: "value", key2: [Pleroma.Repo]) -    Application.put_env(:pleroma, :second_setting, key: "value2", key2: [Pleroma.Activity]) - +  test "error if file with custom settings doesn't exist" do      Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) -    first_db = Config.get_by_params(%{group: "pleroma", key: ":first_setting"}) -    second_db = Config.get_by_params(%{group: "pleroma", key: ":second_setting"}) -    refute Config.get_by_params(%{group: "pleroma", key: "Pleroma.Repo"}) - -    assert Config.from_binary(first_db.value) == [key: "value", key2: [Pleroma.Repo]] -    assert Config.from_binary(second_db.value) == [key: "value2", key2: [Pleroma.Activity]] +    assert_receive {:mix_shell, :info, +                    [ +                      "To migrate settings, you must define custom settings in config/test.secret.exs." +                    ]}, +                   15    end -  test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do -    Config.create(%{ -      group: "pleroma", -      key: ":setting_first", -      value: [key: "value", key2: [Pleroma.Activity]] -    }) - -    Config.create(%{ -      group: "pleroma", -      key: ":setting_second", -      value: [key: "valu2", key2: [Pleroma.Repo]] -    }) +  test "settings are migrated to db" do +    initial = Application.get_env(:quack, :level) +    on_exit(fn -> Application.put_env(:quack, :level, initial) end) +    assert Repo.all(ConfigDB) == [] -    Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp", "true"]) +    Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") -    assert Repo.all(Config) == [] -    assert File.exists?(temp_file) -    {:ok, file} = File.read(temp_file) +    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", key: ":level"}) +    refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) -    assert file =~ "config :pleroma, :setting_first," -    assert file =~ "config :pleroma, :setting_second," +    assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]] +    assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]] +    assert ConfigDB.from_binary(config3.value) == :info    end -  test "load a settings with large values and pass to file", %{temp_file: temp_file} do -    Config.create(%{ -      group: "pleroma", -      key: ":instance", -      value: [ -        name: "Pleroma", -        email: "example@example.com", -        notify_email: "noreply@example.com", -        description: "A Pleroma instance, an alternative fediverse server", -        limit: 5_000, -        chat_limit: 5_000, -        remote_limit: 100_000, -        upload_limit: 16_000_000, -        avatar_upload_limit: 2_000_000, -        background_upload_limit: 4_000_000, -        banner_upload_limit: 4_000_000, -        poll_limits: %{ -          max_options: 20, -          max_option_chars: 200, -          min_expiration: 0, -          max_expiration: 365 * 24 * 60 * 60 -        }, -        registrations_open: true, -        federating: true, -        federation_incoming_replies_max_depth: 100, -        federation_reachability_timeout_days: 7, -        federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher], -        allow_relay: true, -        rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy, -        public: true, -        quarantined_instances: [], -        managed_config: true, -        static_dir: "instance/static/", -        allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], -        mrf_transparency: true, -        mrf_transparency_exclusions: [], -        autofollowed_nicknames: [], -        max_pinned_statuses: 1, -        no_attachment_links: true, -        welcome_user_nickname: nil, -        welcome_message: nil, -        max_report_comment_size: 1000, -        safe_dm_mentions: false, -        healthcheck: false, -        remote_post_retention_days: 90, -        skip_thread_containment: true, -        limit_to_local_content: :unauthenticated, -        dynamic_configuration: false, -        user_bio_length: 5000, -        user_name_length: 100, -        max_account_fields: 10, -        max_remote_account_fields: 20, -        account_field_name_length: 512, -        account_field_value_length: 2048, -        external_user_synchronization: true, -        extended_nickname_format: true, -        multi_factor_authentication: [ -          totp: [ -            # digits 6 or 8 -            digits: 6, -            period: 30 -          ], -          backup_codes: [ -            number: 2, -            length: 6 +  describe "with deletion temp file" do +    setup do +      temp_file = "config/temp.exported_from_db.secret.exs" + +      on_exit(fn -> +        :ok = File.rm(temp_file) +      end) + +      {:ok, temp_file: temp_file} +    end + +    test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do +      ConfigDB.create(%{ +        group: ":pleroma", +        key: ":setting_first", +        value: [key: "value", key2: ["Activity"]] +      }) + +      ConfigDB.create(%{ +        group: ":pleroma", +        key: ":setting_second", +        value: [key: "value2", key2: [Repo]] +      }) + +      ConfigDB.create(%{group: ":quack", key: ":level", value: :info}) + +      Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) + +      assert Repo.all(ConfigDB) == [] + +      file = File.read!(temp_file) +      assert file =~ "config :pleroma, :setting_first," +      assert file =~ "config :pleroma, :setting_second," +      assert file =~ "config :quack, :level, :info" +    end + +    test "load a settings with large values and pass to file", %{temp_file: temp_file} do +      ConfigDB.create(%{ +        group: ":pleroma", +        key: ":instance", +        value: [ +          name: "Pleroma", +          email: "example@example.com", +          notify_email: "noreply@example.com", +          description: "A Pleroma instance, an alternative fediverse server", +          limit: 5_000, +          chat_limit: 5_000, +          remote_limit: 100_000, +          upload_limit: 16_000_000, +          avatar_upload_limit: 2_000_000, +          background_upload_limit: 4_000_000, +          banner_upload_limit: 4_000_000, +          poll_limits: %{ +            max_options: 20, +            max_option_chars: 200, +            min_expiration: 0, +            max_expiration: 365 * 24 * 60 * 60 +          }, +          registrations_open: true, +          federating: true, +          federation_incoming_replies_max_depth: 100, +          federation_reachability_timeout_days: 7, +          federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher], +          allow_relay: true, +          rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy, +          public: true, +          quarantined_instances: [], +          managed_config: true, +          static_dir: "instance/static/", +          allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], +          mrf_transparency: true, +          mrf_transparency_exclusions: [], +          autofollowed_nicknames: [], +          max_pinned_statuses: 1, +          no_attachment_links: true, +          welcome_user_nickname: nil, +          welcome_message: nil, +          max_report_comment_size: 1000, +          safe_dm_mentions: false, +          healthcheck: false, +          remote_post_retention_days: 90, +          skip_thread_containment: true, +          limit_to_local_content: :unauthenticated, +          user_bio_length: 5000, +          user_name_length: 100, +          max_account_fields: 10, +          max_remote_account_fields: 20, +          account_field_name_length: 512, +          account_field_value_length: 2048, +          external_user_synchronization: true, +          extended_nickname_format: true, +          multi_factor_authentication: [ +            totp: [ +              # digits 6 or 8 +              digits: 6, +              period: 30 +            ], +            backup_codes: [ +              number: 2, +              length: 6 +            ]            ]          ] -      ] -    }) +      }) + +      Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) -    Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp", "true"]) +      assert Repo.all(ConfigDB) == [] +      assert File.exists?(temp_file) +      {:ok, file} = File.read(temp_file) -    assert Repo.all(Config) == [] -    assert File.exists?(temp_file) -    {:ok, file} = File.read(temp_file) +      header = +        if Code.ensure_loaded?(Config.Reader) do +          "import Config" +        else +          "use Mix.Config" +        end -    assert file == -             "use Mix.Config\n\nconfig :pleroma, :instance,\n  name: \"Pleroma\",\n  email: \"example@example.com\",\n  notify_email: \"noreply@example.com\",\n  description: \"A Pleroma instance, an alternative fediverse server\",\n  limit: 5000,\n  chat_limit: 5000,\n  remote_limit: 100_000,\n  upload_limit: 16_000_000,\n  avatar_upload_limit: 2_000_000,\n  background_upload_limit: 4_000_000,\n  banner_upload_limit: 4_000_000,\n  poll_limits: %{\n    max_expiration: 31_536_000,\n    max_option_chars: 200,\n    max_options: 20,\n    min_expiration: 0\n  },\n  registrations_open: true,\n  federating: true,\n  federation_incoming_replies_max_depth: 100,\n  federation_reachability_timeout_days: 7,\n  federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n  allow_relay: true,\n  rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,\n  public: true,\n  quarantined_instances: [],\n  managed_config: true,\n  static_dir: \"instance/static/\",\n  allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n  mrf_transparency: true,\n  mrf_transparency_exclusions: [],\n  autofollowed_nicknames: [],\n  max_pinned_statuses: 1,\n  no_attachment_links: true,\n  welcome_user_nickname: nil,\n  welcome_message: nil,\n  max_report_comment_size: 1000,\n  safe_dm_mentions: false,\n  healthcheck: false,\n  remote_post_retention_days: 90,\n  skip_thread_containment: true,\n  limit_to_local_content: :unauthenticated,\n  dynamic_configuration: false,\n  user_bio_length: 5000,\n  user_name_length: 100,\n  max_account_fields: 10,\n  max_remote_account_fields: 20,\n  account_field_name_length: 512,\n  account_field_value_length: 2048,\n  external_user_synchronization: true,\n  extended_nickname_format: true,\n  multi_factor_authentication: [\n    totp: [digits: 6, period: 30],\n    backup_codes: [number: 2, length: 6]\n  ]\n" +      assert file == +               "#{header}\n\nconfig :pleroma, :instance,\n  name: \"Pleroma\",\n  email: \"example@example.com\",\n  notify_email: \"noreply@example.com\",\n  description: \"A Pleroma instance, an alternative fediverse server\",\n  limit: 5000,\n  chat_limit: 5000,\n  remote_limit: 100_000,\n  upload_limit: 16_000_000,\n  avatar_upload_limit: 2_000_000,\n  background_upload_limit: 4_000_000,\n  banner_upload_limit: 4_000_000,\n  poll_limits: %{\n    max_expiration: 31_536_000,\n    max_option_chars: 200,\n    max_options: 20,\n    min_expiration: 0\n  },\n  registrations_open: true,\n  federating: true,\n  federation_incoming_replies_max_depth: 100,\n  federation_reachability_timeout_days: 7,\n  federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n  allow_relay: true,\n  rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,\n  public: true,\n  quarantined_instances: [],\n  managed_config: true,\n  static_dir: \"instance/static/\",\n  allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n  mrf_transparency: true,\n  mrf_transparency_exclusions: [],\n  autofollowed_nicknames: [],\n  max_pinned_statuses: 1,\n  no_attachment_links: true,\n  welcome_user_nickname: nil,\n  welcome_message: nil,\n  max_report_comment_size: 1000,\n  safe_dm_mentions: false,\n  healthcheck: false,\n  remote_post_retention_days: 90,\n  skip_thread_containment: true,\n  limit_to_local_content: :unauthenticated,\n  user_bio_length: 5000,\n  user_name_length: 100,\n  max_account_fields: 10,\n  max_remote_account_fields: 20,\n  account_field_name_length: 512,\n  account_field_value_length: 2048,\n  external_user_synchronization: true,\n  extended_nickname_format: true,\n  multi_factor_authentication: [\n    totp: [digits: 6, period: 30],\n    backup_codes: [number: 2, length: 6]\n  ]\n" +    end    end  end diff --git a/test/tasks/instance_test.exs b/test/tasks/instance_test.exs index 6d7eed4c1..d69275726 100644 --- a/test/tasks/instance_test.exs +++ b/test/tasks/instance_test.exs @@ -78,7 +78,7 @@ defmodule Pleroma.InstanceTest do      assert generated_config =~ "database: \"dbname\""      assert generated_config =~ "username: \"dbuser\""      assert generated_config =~ "password: \"dbpass\"" -    assert generated_config =~ "dynamic_configuration: true" +    assert generated_config =~ "configurable_from_database: true"      assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]"      assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()    end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index ad6b9810c..ff4604a52 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -867,6 +867,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "adds an emoji reaction activity to the db" do        user = insert(:user)        reactor = insert(:user) +      third_user = insert(:user) +      fourth_user = insert(:user)        {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})        assert object = Object.normalize(activity) @@ -881,7 +883,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]]        assert reaction_activity.data["context"] == object.data["context"]        assert object.data["reaction_count"] == 1 -      assert object.data["reactions"]["🔥"] == [reactor.ap_id] +      assert object.data["reactions"] == [["🔥", [reactor.ap_id]]] + +      {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(third_user, object, "☕") + +      assert object.data["reaction_count"] == 2 +      assert object.data["reactions"] == [["🔥", [reactor.ap_id]], ["☕", [third_user.ap_id]]] + +      {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(fourth_user, object, "🔥") + +      assert object.data["reaction_count"] == 3 + +      assert object.data["reactions"] == [ +               ["🔥", [fourth_user.ap_id, reactor.ap_id]], +               ["☕", [third_user.ap_id]] +             ]      end    end @@ -919,7 +935,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        object = Object.get_by_ap_id(object.data["id"])        assert object.data["reaction_count"] == 0 -      assert object.data["reactions"] == %{} +      assert object.data["reactions"] == []      end    end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index c8f8ba310..5c767219a 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    use Oban.Testing, repo: Pleroma.Repo    alias Pleroma.Activity +  alias Pleroma.ConfigDB    alias Pleroma.HTML    alias Pleroma.ModerationLog    alias Pleroma.Repo @@ -597,7 +598,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, :no_content) -      token_record = List.last(Pleroma.Repo.all(Pleroma.UserInviteToken)) +      token_record = List.last(Repo.all(Pleroma.UserInviteToken))        assert token_record        refute token_record.used @@ -1884,25 +1885,42 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    end    describe "GET /api/pleroma/admin/config" do +    clear_config(:configurable_from_database) do +      Pleroma.Config.put(:configurable_from_database, true) +    end + +    test "when configuration from database is off", %{conn: conn} do +      initial = Pleroma.Config.get(:configurable_from_database) +      Pleroma.Config.put(:configurable_from_database, false) +      on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end) +      conn = get(conn, "/api/pleroma/admin/config") + +      assert json_response(conn, 400) == +               "To use this endpoint you need to enable configuration from database." +    end +      test "without any settings in db", %{conn: conn} do        conn = get(conn, "/api/pleroma/admin/config") -      assert json_response(conn, 200) == %{"configs" => []} +      assert json_response(conn, 400) == +               "To use configuration from database migrate your settings to database."      end -    test "with settings in db", %{conn: conn} do +    test "with settings only in db", %{conn: conn} do        config1 = insert(:config)        config2 = insert(:config) -      conn = get(conn, "/api/pleroma/admin/config") +      conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})        %{          "configs" => [            %{ +            "group" => ":pleroma",              "key" => key1,              "value" => _            },            %{ +            "group" => ":pleroma",              "key" => key2,              "value" => _            } @@ -1912,11 +1930,107 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert key1 == config1.key        assert key2 == config2.key      end + +    test "db is added to settings that are in db", %{conn: conn} do +      _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name")) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response(200) + +      [instance_config] = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key == ":instance" +        end) + +      assert instance_config["db"] == [":name"] +    end + +    test "merged default setting with db settings", %{conn: conn} do +      config1 = insert(:config) +      config2 = insert(:config) + +      config3 = +        insert(:config, +          value: ConfigDB.to_binary(k1: :v1, k2: :v2) +        ) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response(200) + +      assert length(configs) > 3 + +      received_configs = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key in [config1.key, config2.key, config3.key] +        end) + +      assert length(received_configs) == 3 + +      db_keys = +        config3.value +        |> ConfigDB.from_binary() +        |> Keyword.keys() +        |> ConfigDB.convert() + +      Enum.each(received_configs, fn %{"value" => value, "db" => db} -> +        assert db in [[config1.key], [config2.key], db_keys] + +        assert value in [ +                 ConfigDB.from_binary_with_convert(config1.value), +                 ConfigDB.from_binary_with_convert(config2.value), +                 ConfigDB.from_binary_with_convert(config3.value) +               ] +      end) +    end + +    test "subkeys with full update right merge", %{conn: conn} do +      config1 = +        insert(:config, +          key: ":emoji", +          value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]) +        ) + +      config2 = +        insert(:config, +          key: ":assets", +          value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1]) +        ) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response(200) + +      vals = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key in [config1.key, config2.key] +        end) + +      emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) +      assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) + +      emoji_val = ConfigDB.transform_with_out_binary(emoji["value"]) +      assets_val = ConfigDB.transform_with_out_binary(assets["value"]) + +      assert emoji_val[:groups] == [a: 1, b: 2] +      assert assets_val[:mascots] == [a: 1, b: 2] +    end +  end + +  test "POST /api/pleroma/admin/config error", %{conn: conn} do +    conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []}) + +    assert json_response(conn, 400) == +             "To use this endpoint you need to enable configuration from database."    end    describe "POST /api/pleroma/admin/config" do      setup do -      temp_file = "config/test.exported_from_db.secret.exs" +      http = Application.get_env(:pleroma, :http)        on_exit(fn ->          Application.delete_env(:pleroma, :key1) @@ -1927,28 +2041,33 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          Application.delete_env(:pleroma, :keyaa2)          Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)          Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) -        :ok = File.rm(temp_file) +        Application.put_env(:pleroma, :http, http) +        Application.put_env(:tesla, :adapter, Tesla.Mock) +        :ok = File.rm("config/test.exported_from_db.secret.exs")        end)      end -    clear_config([:instance, :dynamic_configuration]) do -      Pleroma.Config.put([:instance, :dynamic_configuration], true) +    clear_config(:configurable_from_database) do +      Pleroma.Config.put(:configurable_from_database, true)      end      @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) +        conn =          post(conn, "/api/pleroma/admin/config", %{            configs: [ -            %{group: "pleroma", key: "key1", value: "value1"}, +            %{group: ":pleroma", key: ":key1", value: "value1"},              %{ -              group: "ueberauth", -              key: "Ueberauth.Strategy.Twitter.OAuth", +              group: ":ueberauth", +              key: "Ueberauth",                value: [%{"tuple" => [":consumer_secret", "aaaa"]}]              },              %{ -              group: "pleroma", -              key: "key2", +              group: ":pleroma", +              key: ":key2",                value: %{                  ":nested_1" => "nested_value1",                  ":nested_2" => [ @@ -1958,21 +2077,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                }              },              %{ -              group: "pleroma", -              key: "key3", +              group: ":pleroma", +              key: ":key3",                value: [                  %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},                  %{"nested_4" => true}                ]              },              %{ -              group: "pleroma", -              key: "key4", +              group: ":pleroma", +              key: ":key4",                value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}              },              %{ -              group: "idna", -              key: "key5", +              group: ":idna", +              key: ":key5",                value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}              }            ] @@ -1981,43 +2100,49 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "pleroma", -                   "key" => "key1", -                   "value" => "value1" +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => "value1", +                   "db" => [":key1"]                   },                   %{ -                   "group" => "ueberauth", -                   "key" => "Ueberauth.Strategy.Twitter.OAuth", -                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}] +                   "group" => ":ueberauth", +                   "key" => "Ueberauth", +                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], +                   "db" => [":consumer_secret"]                   },                   %{ -                   "group" => "pleroma", -                   "key" => "key2", +                   "group" => ":pleroma", +                   "key" => ":key2",                     "value" => %{                       ":nested_1" => "nested_value1",                       ":nested_2" => [                         %{":nested_22" => "nested_value222"},                         %{":nested_33" => %{":nested_44" => "nested_444"}}                       ] -                   } +                   }, +                   "db" => [":key2"]                   },                   %{ -                   "group" => "pleroma", -                   "key" => "key3", +                   "group" => ":pleroma", +                   "key" => ":key3",                     "value" => [                       %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},                       %{"nested_4" => true} -                   ] +                   ], +                   "db" => [":key3"]                   },                   %{ -                   "group" => "pleroma", -                   "key" => "key4", -                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"} +                   "group" => ":pleroma", +                   "key" => ":key4", +                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, +                   "db" => [":key4"]                   },                   %{ -                   "group" => "idna", -                   "key" => "key5", -                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} +                   "group" => ":idna", +                   "key" => ":key5", +                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, +                   "db" => [":key5"]                   }                 ]               } @@ -2045,25 +2170,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}      end -    test "update config setting & delete", %{conn: conn} do -      config1 = insert(:config, key: "keyaa1") -      config2 = insert(:config, key: "keyaa2") +    test "save config setting without key", %{conn: conn} do +      level = Application.get_env(:quack, :level) +      meta = Application.get_env(:quack, :meta) +      webhook_url = Application.get_env(:quack, :webhook_url) -      insert(:config, -        group: "ueberauth", -        key: "Ueberauth.Strategy.Microsoft.OAuth", -        value: :erlang.term_to_binary([]) -      ) +      on_exit(fn -> +        Application.put_env(:quack, :level, level) +        Application.put_env(:quack, :meta, meta) +        Application.put_env(:quack, :webhook_url, webhook_url) +      end)        conn =          post(conn, "/api/pleroma/admin/config", %{            configs: [ -            %{group: config1.group, key: config1.key, value: "another_value"}, -            %{group: config2.group, key: config2.key, delete: "true"},              %{ -              group: "ueberauth", -              key: "Ueberauth.Strategy.Microsoft.OAuth", -              delete: "true" +              group: ":quack", +              key: ":level", +              value: ":info" +            }, +            %{ +              group: ":quack", +              key: ":meta", +              value: [":none"] +            }, +            %{ +              group: ":quack", +              key: ":webhook_url", +              value: "https://hooks.slack.com/services/KEY"              }            ]          }) @@ -2071,23 +2205,300 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "pleroma", +                   "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"] +                 } +               ] +             } + +      assert Application.get_env(:quack, :level) == :info +      assert Application.get_env(:quack, :meta) == [:none] +      assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY" +    end + +    test "saving config with partial update", %{conn: conn} do +      config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) + +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]} +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{"tuple" => [":key1", 1]}, +                     %{"tuple" => [":key2", 2]}, +                     %{"tuple" => [":key3", 3]} +                   ], +                   "db" => [":key1", ":key2", ":key3"] +                 } +               ] +             } +    end + +    test "saving config with nested merge", %{conn: conn} do +      config = +        insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2])) + +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              value: [ +                %{"tuple" => [":key3", 3]}, +                %{ +                  "tuple" => [ +                    ":key2", +                    [ +                      %{"tuple" => [":k2", 1]}, +                      %{"tuple" => [":k3", 3]} +                    ] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{"tuple" => [":key1", 1]}, +                     %{"tuple" => [":key3", 3]}, +                     %{ +                       "tuple" => [ +                         ":key2", +                         [ +                           %{"tuple" => [":k1", 1]}, +                           %{"tuple" => [":k2", 1]}, +                           %{"tuple" => [":k3", 3]} +                         ] +                       ] +                     } +                   ], +                   "db" => [":key1", ":key3", ":key2"] +                 } +               ] +             } +    end + +    test "saving special atoms", %{conn: conn} do +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          "configs" => [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => [ +                %{ +                  "tuple" => [ +                    ":ssl_options", +                    [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{ +                       "tuple" => [ +                         ":ssl_options", +                         [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] +                       ] +                     } +                   ], +                   "db" => [":ssl_options"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :key1) == [ +               ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]] +             ] +    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) + +      config = +        insert(:config, +          group: ":logger", +          key: ":backends", +          value: :erlang.term_to_binary([]) +        ) + +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}] +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":logger", +                   "key" => ":backends", +                   "value" => [ +                     ":console", +                     %{"tuple" => ["ExSyslogger", ":ex_syslogger"]} +                   ], +                   "db" => [":backends"] +                 } +               ] +             } + +      assert Application.get_env(:logger, :backends) == [ +               :console, +               {ExSyslogger, :ex_syslogger} +             ] + +      ExUnit.CaptureLog.capture_log(fn -> +        require Logger +        Logger.warn("Ooops...") +      end) =~ "Ooops..." +    end + +    test "saving full setting if value is not keyword", %{conn: conn} do +      config = +        insert(:config, +          group: ":tesla", +          key: ":adapter", +          value: :erlang.term_to_binary(Tesla.Adapter.Hackey) +        ) + +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"} +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":tesla", +                   "key" => ":adapter", +                   "value" => "Tesla.Adapter.Httpc", +                   "db" => [":adapter"] +                 } +               ] +             } +    end + +    test "update config setting & delete with fallback to default value", %{ +      conn: conn, +      admin: admin, +      token: token +    } do +      ueberauth = Application.get_env(:ueberauth, Ueberauth) +      config1 = insert(:config, key: ":keyaa1") +      config2 = insert(:config, key: ":keyaa2") + +      config3 = +        insert(:config, +          group: ":ueberauth", +          key: "Ueberauth" +        ) + +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config1.group, key: config1.key, value: "another_value"}, +            %{group: config2.group, key: config2.key, value: "another_value"} +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma",                     "key" => config1.key, -                   "value" => "another_value" +                   "value" => "another_value", +                   "db" => [":keyaa1"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => config2.key, +                   "value" => "another_value", +                   "db" => [":keyaa2"]                   }                 ]               }        assert Application.get_env(:pleroma, :keyaa1) == "another_value" -      refute Application.get_env(:pleroma, :keyaa2) +      assert Application.get_env(:pleroma, :keyaa2) == "another_value" +      assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> assign(:token, token) +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config2.group, key: config2.key, delete: true}, +            %{ +              group: ":ueberauth", +              key: "Ueberauth", +              delete: true +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [] +             } + +      assert Application.get_env(:ueberauth, Ueberauth) == ueberauth +      refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)      end      test "common config example", %{conn: conn} do +      adapter = Application.get_env(:tesla, :adapter) +      on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end) +        conn =          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "pleroma", +              "group" => ":pleroma",                "key" => "Pleroma.Captcha.NotReal",                "value" => [                  %{"tuple" => [":enabled", false]}, @@ -2099,16 +2510,25 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                  %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},                  %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},                  %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, -                %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]} +                %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}, +                %{"tuple" => [":name", "Pleroma"]}                ] +            }, +            %{ +              "group" => ":tesla", +              "key" => ":adapter", +              "value" => "Tesla.Adapter.Httpc"              }            ]          }) +      assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc +      assert Pleroma.Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" +        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "pleroma", +                   "group" => ":pleroma",                     "key" => "Pleroma.Captcha.NotReal",                     "value" => [                       %{"tuple" => [":enabled", false]}, @@ -2120,8 +2540,28 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                       %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},                       %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},                       %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, -                     %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]} +                     %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}, +                     %{"tuple" => [":name", "Pleroma"]} +                   ], +                   "db" => [ +                     ":enabled", +                     ":method", +                     ":seconds_valid", +                     ":path", +                     ":key1", +                     ":partial_chain", +                     ":regex1", +                     ":regex2", +                     ":regex3", +                     ":regex4", +                     ":name"                     ] +                 }, +                 %{ +                   "group" => ":tesla", +                   "key" => ":adapter", +                   "value" => "Tesla.Adapter.Httpc", +                   "db" => [":adapter"]                   }                 ]               } @@ -2132,7 +2572,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "pleroma", +              "group" => ":pleroma",                "key" => "Pleroma.Web.Endpoint.NotReal",                "value" => [                  %{ @@ -2196,7 +2636,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "pleroma", +                   "group" => ":pleroma",                     "key" => "Pleroma.Web.Endpoint.NotReal",                     "value" => [                       %{ @@ -2252,7 +2692,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                           ]                         ]                       } -                   ] +                   ], +                   "db" => [":http"]                   }                 ]               } @@ -2263,7 +2704,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "pleroma", +              "group" => ":pleroma",                "key" => ":key1",                "value" => [                  %{"tuple" => [":key2", "some_val"]}, @@ -2293,7 +2734,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 %{                   "configs" => [                     %{ -                     "group" => "pleroma", +                     "group" => ":pleroma",                       "key" => ":key1",                       "value" => [                         %{"tuple" => [":key2", "some_val"]}, @@ -2314,7 +2755,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                             }                           ]                         } -                     ] +                     ], +                     "db" => [":key2", ":key3"]                     }                   ]                 } @@ -2325,7 +2767,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "pleroma", +              "group" => ":pleroma",                "key" => ":key1",                "value" => %{"key" => "some_val"}              } @@ -2336,83 +2778,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 %{                   "configs" => [                     %{ -                     "group" => "pleroma", +                     "group" => ":pleroma",                       "key" => ":key1", -                     "value" => %{"key" => "some_val"} +                     "value" => %{"key" => "some_val"}, +                     "db" => [":key1"]                     }                   ]                 }      end -    test "dispatch setting", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => "pleroma", -              "key" => "Pleroma.Web.Endpoint.NotReal", -              "value" => [ -                %{ -                  "tuple" => [ -                    ":http", -                    [ -                      %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]}, -                      %{"tuple" => [":dispatch", ["{:_, -       [ -         {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, -         {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, -          {Phoenix.Transports.WebSocket, -           {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, -         {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} -       ]}"]]} -                    ] -                  ] -                } -              ] -            } -          ] -        }) - -      dispatch_string = -        "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <> -          "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <> -          "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <> -          "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}" - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => "pleroma", -                   "key" => "Pleroma.Web.Endpoint.NotReal", -                   "value" => [ -                     %{ -                       "tuple" => [ -                         ":http", -                         [ -                           %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]}, -                           %{ -                             "tuple" => [ -                               ":dispatch", -                               [ -                                 dispatch_string -                               ] -                             ] -                           } -                         ] -                       ] -                     } -                   ] -                 } -               ] -             } -    end -      test "queues key as atom", %{conn: conn} do        conn =          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "oban", +              "group" => ":oban",                "key" => ":queues",                "value" => [                  %{"tuple" => [":federator_incoming", 50]}, @@ -2430,7 +2810,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "oban", +                   "group" => ":oban",                     "key" => ":queues",                     "value" => [                       %{"tuple" => [":federator_incoming", 50]}, @@ -2440,6 +2820,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                       %{"tuple" => [":transmogrifier", 20]},                       %{"tuple" => [":scheduled_activities", 10]},                       %{"tuple" => [":background", 5]} +                   ], +                   "db" => [ +                     ":federator_incoming", +                     ":federator_outgoing", +                     ":web_push", +                     ":mailer", +                     ":transmogrifier", +                     ":scheduled_activities", +                     ":background"                     ]                   }                 ] @@ -2449,7 +2838,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      test "delete part of settings by atom subkeys", %{conn: conn} do        config =          insert(:config, -          key: "keyaa1", +          key: ":keyaa1",            value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")          ) @@ -2460,41 +2849,127 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                group: config.group,                key: config.key,                subkeys: [":subkey1", ":subkey3"], -              delete: "true" +              delete: true              }            ]          }) -      assert( -        json_response(conn, 200) == %{ -          "configs" => [ +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":keyaa1", +                   "value" => [%{"tuple" => [":subkey2", "val2"]}], +                   "db" => [":subkey2"] +                 } +               ] +             } +    end + +    test "proxy tuple localhost", %{conn: conn} do +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [              %{ -              "group" => "pleroma", -              "key" => "keyaa1", -              "value" => [%{"tuple" => [":subkey2", "val2"]}] +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}, +                %{"tuple" => [":send_user_agent", false]} +              ]              }            ] -        } -      ) +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => [ +                     %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}, +                     %{"tuple" => [":send_user_agent", false]} +                   ], +                   "db" => [":proxy_url", ":send_user_agent"] +                 } +               ] +             } +    end + +    test "proxy tuple domain", %{conn: conn} do +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}, +                %{"tuple" => [":send_user_agent", false]} +              ] +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => [ +                     %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}, +                     %{"tuple" => [":send_user_agent", false]} +                   ], +                   "db" => [":proxy_url", ":send_user_agent"] +                 } +               ] +             } +    end + +    test "proxy tuple ip", %{conn: conn} do +      conn = +        post(conn, "/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}, +                %{"tuple" => [":send_user_agent", false]} +              ] +            } +          ] +        }) + +      assert json_response(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => [ +                     %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}, +                     %{"tuple" => [":send_user_agent", false]} +                   ], +                   "db" => [":proxy_url", ":send_user_agent"] +                 } +               ] +             }      end    end    describe "config mix tasks run" do      setup do -      temp_file = "config/test.exported_from_db.secret.exs" -        Mix.shell(Mix.Shell.Quiet)        on_exit(fn ->          Mix.shell(Mix.Shell.IO) -        :ok = File.rm(temp_file)        end)        :ok      end -    clear_config([:instance, :dynamic_configuration]) do -      Pleroma.Config.put([:instance, :dynamic_configuration], true) +    clear_config(:configurable_from_database) do +      Pleroma.Config.put(:configurable_from_database, true)      end      clear_config([:feed, :post_title]) do @@ -2502,15 +2977,27 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end      test "transfer settings to DB and to file", %{conn: conn} do -      assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] -      ret_conn = get(conn, "/api/pleroma/admin/config/migrate_to_db") -      assert json_response(ret_conn, 200) == %{} -      assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0 +      assert Repo.all(Pleroma.ConfigDB) == [] +      Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") +      assert Repo.aggregate(Pleroma.ConfigDB, :count, :id) > 0 + +      conn = get(conn, "/api/pleroma/admin/config/migrate_from_db") -      ret_conn = get(conn, "/api/pleroma/admin/config/migrate_from_db") +      assert json_response(conn, 200) == %{} +      assert Repo.all(Pleroma.ConfigDB) == [] +    end + +    test "returns error if configuration from database is off", %{conn: conn} do +      initial = Pleroma.Config.get(:configurable_from_database) +      on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end) +      Pleroma.Config.put(:configurable_from_database, false) + +      conn = get(conn, "/api/pleroma/admin/config/migrate_from_db") -      assert json_response(ret_conn, 200) == %{} -      assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] +      assert json_response(conn, 400) == +               "To use this endpoint you need to enable configuration from database." + +      assert Repo.all(Pleroma.ConfigDB) == []      end    end @@ -2979,6 +3466,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert ReportNote |> Repo.all() |> length() == 1      end    end + +  test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do +    admin = insert(:user, is_admin: true) + +    conn = +      assign(conn, :user, admin) +      |> get("/api/pleroma/admin/config/descriptions") + +    assert [child | _others] = json_response(conn, 200) + +    assert child["children"] +    assert child["key"] +    assert String.starts_with?(child["group"], ":") +    assert child["description"] +  end  end  # Needed for testing diff --git a/test/web/admin_api/config_test.exs b/test/web/admin_api/config_test.exs deleted file mode 100644 index 204446b79..000000000 --- a/test/web/admin_api/config_test.exs +++ /dev/null @@ -1,497 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.ConfigTest do -  use Pleroma.DataCase, async: true -  import Pleroma.Factory -  alias Pleroma.Web.AdminAPI.Config - -  test "get_by_key/1" do -    config = insert(:config) -    insert(:config) - -    assert config == Config.get_by_params(%{group: config.group, key: config.key}) -  end - -  test "create/1" do -    {:ok, config} = Config.create(%{group: "pleroma", key: "some_key", value: "some_value"}) -    assert config == Config.get_by_params(%{group: "pleroma", key: "some_key"}) -  end - -  test "update/1" do -    config = insert(:config) -    {:ok, updated} = Config.update(config, %{value: "some_value"}) -    loaded = Config.get_by_params(%{group: config.group, key: config.key}) -    assert loaded == updated -  end - -  test "update_or_create/1" do -    config = insert(:config) -    key2 = "another_key" - -    params = [ -      %{group: "pleroma", key: key2, value: "another_value"}, -      %{group: config.group, key: config.key, value: "new_value"} -    ] - -    assert Repo.all(Config) |> length() == 1 - -    Enum.each(params, &Config.update_or_create(&1)) - -    assert Repo.all(Config) |> length() == 2 - -    config1 = Config.get_by_params(%{group: config.group, key: config.key}) -    config2 = Config.get_by_params(%{group: "pleroma", key: key2}) - -    assert config1.value == Config.transform("new_value") -    assert config2.value == Config.transform("another_value") -  end - -  test "delete/1" do -    config = insert(:config) -    {:ok, _} = Config.delete(%{key: config.key, group: config.group}) -    refute Config.get_by_params(%{key: config.key, group: config.group}) -  end - -  describe "transform/1" do -    test "string" do -      binary = Config.transform("value as string") -      assert binary == :erlang.term_to_binary("value as string") -      assert Config.from_binary(binary) == "value as string" -    end - -    test "boolean" do -      binary = Config.transform(false) -      assert binary == :erlang.term_to_binary(false) -      assert Config.from_binary(binary) == false -    end - -    test "nil" do -      binary = Config.transform(nil) -      assert binary == :erlang.term_to_binary(nil) -      assert Config.from_binary(binary) == nil -    end - -    test "integer" do -      binary = Config.transform(150) -      assert binary == :erlang.term_to_binary(150) -      assert Config.from_binary(binary) == 150 -    end - -    test "atom" do -      binary = Config.transform(":atom") -      assert binary == :erlang.term_to_binary(:atom) -      assert Config.from_binary(binary) == :atom -    end - -    test "pleroma module" do -      binary = Config.transform("Pleroma.Bookmark") -      assert binary == :erlang.term_to_binary(Pleroma.Bookmark) -      assert Config.from_binary(binary) == Pleroma.Bookmark -    end - -    test "phoenix module" do -      binary = Config.transform("Phoenix.Socket.V1.JSONSerializer") -      assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer) -      assert Config.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer -    end - -    test "sigil" do -      binary = Config.transform("~r/comp[lL][aA][iI][nN]er/") -      assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/) -      assert Config.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/ -    end - -    test "link sigil" do -      binary = Config.transform("~r/https:\/\/example.com/") -      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/) -      assert Config.from_binary(binary) == ~r/https:\/\/example.com/ -    end - -    test "link sigil with u modifier" do -      binary = Config.transform("~r/https:\/\/example.com/u") -      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/u) -      assert Config.from_binary(binary) == ~r/https:\/\/example.com/u -    end - -    test "link sigil with i modifier" do -      binary = Config.transform("~r/https:\/\/example.com/i") -      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/i) -      assert Config.from_binary(binary) == ~r/https:\/\/example.com/i -    end - -    test "link sigil with s modifier" do -      binary = Config.transform("~r/https:\/\/example.com/s") -      assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/s) -      assert Config.from_binary(binary) == ~r/https:\/\/example.com/s -    end - -    test "2 child tuple" do -      binary = Config.transform(%{"tuple" => ["v1", ":v2"]}) -      assert binary == :erlang.term_to_binary({"v1", :v2}) -      assert Config.from_binary(binary) == {"v1", :v2} -    end - -    test "tuple with n childs" do -      binary = -        Config.transform(%{ -          "tuple" => [ -            "v1", -            ":v2", -            "Pleroma.Bookmark", -            150, -            false, -            "Phoenix.Socket.V1.JSONSerializer" -          ] -        }) - -      assert binary == -               :erlang.term_to_binary( -                 {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} -               ) - -      assert Config.from_binary(binary) == -               {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer} -    end - -    test "tuple with dispatch key" do -      binary = Config.transform(%{"tuple" => [":dispatch", ["{:_, -       [ -         {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, -         {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, -          {Phoenix.Transports.WebSocket, -           {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, -         {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} -       ]}"]]}) - -      assert binary == -               :erlang.term_to_binary( -                 {:dispatch, -                  [ -                    {:_, -                     [ -                       {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, -                       {"/websocket", Phoenix.Endpoint.CowboyWebSocket, -                        {Phoenix.Transports.WebSocket, -                         {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}}, -                       {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} -                     ]} -                  ]} -               ) - -      assert Config.from_binary(binary) == -               {:dispatch, -                [ -                  {:_, -                   [ -                     {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, -                     {"/websocket", Phoenix.Endpoint.CowboyWebSocket, -                      {Phoenix.Transports.WebSocket, -                       {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}}, -                     {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} -                   ]} -                ]} -    end - -    test "map with string key" do -      binary = Config.transform(%{"key" => "value"}) -      assert binary == :erlang.term_to_binary(%{"key" => "value"}) -      assert Config.from_binary(binary) == %{"key" => "value"} -    end - -    test "map with atom key" do -      binary = Config.transform(%{":key" => "value"}) -      assert binary == :erlang.term_to_binary(%{key: "value"}) -      assert Config.from_binary(binary) == %{key: "value"} -    end - -    test "list of strings" do -      binary = Config.transform(["v1", "v2", "v3"]) -      assert binary == :erlang.term_to_binary(["v1", "v2", "v3"]) -      assert Config.from_binary(binary) == ["v1", "v2", "v3"] -    end - -    test "list of modules" do -      binary = Config.transform(["Pleroma.Repo", "Pleroma.Activity"]) -      assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity]) -      assert Config.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity] -    end - -    test "list of atoms" do -      binary = Config.transform([":v1", ":v2", ":v3"]) -      assert binary == :erlang.term_to_binary([:v1, :v2, :v3]) -      assert Config.from_binary(binary) == [:v1, :v2, :v3] -    end - -    test "list of mixed values" do -      binary = -        Config.transform([ -          "v1", -          ":v2", -          "Pleroma.Repo", -          "Phoenix.Socket.V1.JSONSerializer", -          15, -          false -        ]) - -      assert binary == -               :erlang.term_to_binary([ -                 "v1", -                 :v2, -                 Pleroma.Repo, -                 Phoenix.Socket.V1.JSONSerializer, -                 15, -                 false -               ]) - -      assert Config.from_binary(binary) == [ -               "v1", -               :v2, -               Pleroma.Repo, -               Phoenix.Socket.V1.JSONSerializer, -               15, -               false -             ] -    end - -    test "simple keyword" do -      binary = Config.transform([%{"tuple" => [":key", "value"]}]) -      assert binary == :erlang.term_to_binary([{:key, "value"}]) -      assert Config.from_binary(binary) == [{:key, "value"}] -      assert Config.from_binary(binary) == [key: "value"] -    end - -    test "keyword with partial_chain key" do -      binary = -        Config.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}]) - -      assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1) -      assert Config.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1] -    end - -    test "keyword" do -      binary = -        Config.transform([ -          %{"tuple" => [":types", "Pleroma.PostgresTypes"]}, -          %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]}, -          %{"tuple" => [":migration_lock", nil]}, -          %{"tuple" => [":key1", 150]}, -          %{"tuple" => [":key2", "string"]} -        ]) - -      assert binary == -               :erlang.term_to_binary( -                 types: Pleroma.PostgresTypes, -                 telemetry_event: [Pleroma.Repo.Instrumenter], -                 migration_lock: nil, -                 key1: 150, -                 key2: "string" -               ) - -      assert Config.from_binary(binary) == [ -               types: Pleroma.PostgresTypes, -               telemetry_event: [Pleroma.Repo.Instrumenter], -               migration_lock: nil, -               key1: 150, -               key2: "string" -             ] -    end - -    test "complex keyword with nested mixed childs" do -      binary = -        Config.transform([ -          %{"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"]}] -                  ] -                } -              ] -            ] -          } -        ]) - -      assert binary == -               :erlang.term_to_binary( -                 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 -                   ] -                 ] -               ) - -      assert Config.from_binary(binary) == -               [ -                 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 -      binary = -        Config.transform([ -          %{"tuple" => [":level", ":warn"]}, -          %{"tuple" => [":meta", [":all"]]}, -          %{"tuple" => [":path", ""]}, -          %{"tuple" => [":val", nil]}, -          %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]} -        ]) - -      assert binary == -               :erlang.term_to_binary( -                 level: :warn, -                 meta: [:all], -                 path: "", -                 val: nil, -                 webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" -               ) - -      assert Config.from_binary(binary) == [ -               level: :warn, -               meta: [:all], -               path: "", -               val: nil, -               webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE" -             ] -    end - -    test "complex keyword with sigil" do -      binary = -        Config.transform([ -          %{"tuple" => [":federated_timeline_removal", []]}, -          %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]}, -          %{"tuple" => [":replace", []]} -        ]) - -      assert binary == -               :erlang.term_to_binary( -                 federated_timeline_removal: [], -                 reject: [~r/comp[lL][aA][iI][nN]er/], -                 replace: [] -               ) - -      assert Config.from_binary(binary) == -               [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []] -    end - -    test "complex keyword with tuples with more than 2 values" do -      binary = -        Config.transform([ -          %{ -            "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", []]} -                              ] -                            } -                          ] -                        ] -                      } -                    ] -                  ] -                } -              ] -            ] -          } -        ]) - -      assert binary == -               :erlang.term_to_binary( -                 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, []}} -                     ] -                   ] -                 ] -               ) - -      assert Config.from_binary(binary) == [ -               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 -end diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index ba1721e06..1fe83cb2c 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -134,4 +134,31 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do      assert [expected] ==               NotificationView.render("index.json", %{notifications: [notification], for: follower})    end + +  test "EmojiReaction notification" do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) +    {:ok, _activity, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    activity = Repo.get(Activity, activity.id) + +    [notification] = Notification.for_user(user) + +    assert notification + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "pleroma:emoji_reaction", +      emoji: "☕", +      account: AccountView.render("show.json", %{user: other_user, for: user}), +      status: StatusView.render("show.json", %{activity: activity, for: user}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    assert expected == +             NotificationView.render("show.json", %{notification: notification, for: user}) +  end  end diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index b54b19c0b..069bb8eac 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -31,13 +31,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"})      {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "☕") -    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")      {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵") +    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")      activity = Repo.get(Activity, activity.id)      status = StatusView.render("show.json", activity: activity) -    assert status[:pleroma][:emoji_reactions]["🍵"] == 1 -    assert status[:pleroma][:emoji_reactions]["☕"] == 2 +    assert status[:pleroma][:emoji_reactions] == [["☕", 2], ["🍵", 1]]    end    test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do @@ -189,7 +188,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do          expires_at: nil,          direct_conversation_id: nil,          thread_muted: false, -        emoji_reactions: %{} +        emoji_reactions: []        }      } diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index fb7500134..a79ecd05b 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -62,7 +62,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do        |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")        |> json_response(200) -    assert result == %{} +    assert result == []      {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") @@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do        |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")        |> json_response(200) -    [represented_user] = result["🎅"] +    [["🎅", [represented_user]]] = result      assert represented_user["id"] == other_user.id    end | 
