diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/federation/federation_test.exs | 47 | ||||
| -rw-r--r-- | test/fixtures/tesla_mock/admin@mastdon.example.org.json | 9 | ||||
| -rw-r--r-- | test/fixtures/users_mock/friendica_followers.json | 19 | ||||
| -rw-r--r-- | test/fixtures/users_mock/friendica_following.json | 19 | ||||
| -rw-r--r-- | test/html_test.exs | 11 | ||||
| -rw-r--r-- | test/notification_test.exs | 29 | ||||
| -rw-r--r-- | test/support/cluster.ex | 218 | ||||
| -rw-r--r-- | test/support/factory.ex | 1 | ||||
| -rw-r--r-- | test/support/http_request_mock.ex | 16 | ||||
| -rw-r--r-- | test/test_helper.exs | 3 | ||||
| -rw-r--r-- | test/user_test.exs | 103 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 78 | ||||
| -rw-r--r-- | test/web/activity_pub/transmogrifier_test.exs | 60 | ||||
| -rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 1 | ||||
| -rw-r--r-- | test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs | 15 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/account_view_test.exs | 13 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/notification_view_test.exs | 27 | ||||
| -rw-r--r-- | test/web/streamer/streamer_test.exs | 2 | 
18 files changed, 581 insertions, 90 deletions
| diff --git a/test/federation/federation_test.exs b/test/federation/federation_test.exs new file mode 100644 index 000000000..45800568a --- /dev/null +++ b/test/federation/federation_test.exs @@ -0,0 +1,47 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Integration.FederationTest do +  use Pleroma.DataCase +  @moduletag :federated +  import Pleroma.Cluster + +  setup_all do +    Pleroma.Cluster.spawn_default_cluster() +    :ok +  end + +  @federated1 :"federated1@127.0.0.1" +  describe "federated cluster primitives" do +    test "within/2 captures local bindings and executes block on remote node" do +      captured_binding = :captured + +      result = +        within @federated1 do +          user = Pleroma.Factory.insert(:user) +          {captured_binding, node(), user} +        end + +      assert {:captured, @federated1, user} = result +      refute Pleroma.User.get_by_id(user.id) +      assert user.id == within(@federated1, do: Pleroma.User.get_by_id(user.id)).id +    end + +    test "runs webserver on customized port" do +      {nickname, url, url_404} = +        within @federated1 do +          import Pleroma.Web.Router.Helpers +          user = Pleroma.Factory.insert(:user) +          user_url = account_url(Pleroma.Web.Endpoint, :show, user) +          url_404 = account_url(Pleroma.Web.Endpoint, :show, "not-exists") + +          {user.nickname, user_url, url_404} +        end + +      assert {:ok, {{_, 200, _}, _headers, body}} = :httpc.request(~c"#{url}") +      assert %{"acct" => ^nickname} = Jason.decode!(body) +      assert {:ok, {{_, 404, _}, _headers, _body}} = :httpc.request(~c"#{url_404}") +    end +  end +end diff --git a/test/fixtures/tesla_mock/admin@mastdon.example.org.json b/test/fixtures/tesla_mock/admin@mastdon.example.org.json index 8159dc20a..9fdd6557c 100644 --- a/test/fixtures/tesla_mock/admin@mastdon.example.org.json +++ b/test/fixtures/tesla_mock/admin@mastdon.example.org.json @@ -9,7 +9,11 @@      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",      "conversation": "ostatus:conversation",      "toot": "http://joinmastodon.org/ns#", -    "Emoji": "toot:Emoji" +    "Emoji": "toot:Emoji", +    "alsoKnownAs": { +      "@id": "as:alsoKnownAs", +      "@type": "@id" +    }    }],    "id": "http://mastodon.example.org/users/admin",    "type": "Person", @@ -50,5 +54,6 @@      "type": "Image",      "mediaType": "image/png",      "url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" -  } +  }, +  "alsoKnownAs": ["http://example.org/users/foo"]  } diff --git a/test/fixtures/users_mock/friendica_followers.json b/test/fixtures/users_mock/friendica_followers.json new file mode 100644 index 000000000..7b86b5fe2 --- /dev/null +++ b/test/fixtures/users_mock/friendica_followers.json @@ -0,0 +1,19 @@ +{ +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "vcard": "http://www.w3.org/2006/vcard/ns#", +      "dfrn": "http://purl.org/macgirvin/dfrn/1.0/", +      "diaspora": "https://diasporafoundation.org/ns/", +      "litepub": "http://litepub.social/ns#", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "sensitive": "as:sensitive", +      "Hashtag": "as:Hashtag", +      "directMessage": "litepub:directMessage" +    } +  ], +  "id": "http://localhost:8080/followers/fuser3", +  "type": "OrderedCollection", +  "totalItems": 296 +} diff --git a/test/fixtures/users_mock/friendica_following.json b/test/fixtures/users_mock/friendica_following.json new file mode 100644 index 000000000..7c526befc --- /dev/null +++ b/test/fixtures/users_mock/friendica_following.json @@ -0,0 +1,19 @@ +{ +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "vcard": "http://www.w3.org/2006/vcard/ns#", +      "dfrn": "http://purl.org/macgirvin/dfrn/1.0/", +      "diaspora": "https://diasporafoundation.org/ns/", +      "litepub": "http://litepub.social/ns#", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "sensitive": "as:sensitive", +      "Hashtag": "as:Hashtag", +      "directMessage": "litepub:directMessage" +    } +  ], +  "id": "http://localhost:8080/following/fuser3", +  "type": "OrderedCollection", +  "totalItems": 32 +} diff --git a/test/html_test.exs b/test/html_test.exs index f0869534c..c918dbe20 100644 --- a/test/html_test.exs +++ b/test/html_test.exs @@ -228,5 +228,16 @@ defmodule Pleroma.HTMLTest do        assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"      end + +    test "does not crash when there is an HTML entity in a link" do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{"status" => "\"http://cofe.com/?boomer=ok&foo=bar\""}) + +      object = Object.normalize(activity) + +      assert {:ok, nil} = HTML.extract_first_external_url(object, object.data["content"]) +    end    end  end diff --git a/test/notification_test.exs b/test/notification_test.exs index f8d429223..dcbffeafe 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -630,6 +630,35 @@ defmodule Pleroma.NotificationTest do        assert Enum.empty?(Notification.for_user(local_user))      end + +    test "move activity generates a notification" do +      %{ap_id: old_ap_id} = old_user = insert(:user) +      %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) +      follower = insert(:user) +      other_follower = insert(:user, %{allow_following_move: false}) + +      User.follow(follower, old_user) +      User.follow(other_follower, old_user) + +      Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) +      ObanHelpers.perform_all() + +      assert [ +               %{ +                 activity: %{ +                   data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id} +                 } +               } +             ] = Notification.for_user(follower) + +      assert [ +               %{ +                 activity: %{ +                   data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id} +                 } +               } +             ] = Notification.for_user(other_follower) +    end    end    describe "for_user" do diff --git a/test/support/cluster.ex b/test/support/cluster.ex new file mode 100644 index 000000000..deb37f361 --- /dev/null +++ b/test/support/cluster.ex @@ -0,0 +1,218 @@ +defmodule Pleroma.Cluster do +  @moduledoc """ +  Facilities for managing a cluster of slave VM's for federated testing. + +  ## Spawning the federated cluster + +  `spawn_cluster/1` spawns a map of slave nodes that are started +  within the running VM. During startup, the slave node is sent all configuration +  from the parent node, as well as all code. After receiving configuration and +  code, the slave then starts all applications currently running on the parent. +  The configuration passed to `spawn_cluster/1` overrides any parent application +  configuration for the provided OTP app and key. This is useful for customizing +  the Ecto database, Phoenix webserver ports, etc. + +  For example, to start a single federated VM named ":federated1", with the +  Pleroma Endpoint running on port 4123, and with a database named +  "pleroma_test1", you would run: + +    endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint) +    repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo) + +    Pleroma.Cluster.spawn_cluster(%{ +      :"federated1@127.0.0.1" => [ +        {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test1")}, +        {:pleroma, Pleroma.Web.Endpoint, +        Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)} +      ] +    }) + +  *Note*: application configuration for a given key is not merged, +  so any customization requires first fetching the existing values +  and merging yourself by providing the merged configuration, +  such as above with the endpoint config and repo config. + +  ## Executing code within a remote node + +  Use the `within/2` macro to execute code within the context of a remote +  federated node. The code block captures all local variable bindings from +  the parent's context and returns the result of the expression after executing +  it on the remote node. For example: + +      import Pleroma.Cluster + +      parent_value = 123 + +      result = +        within :"federated1@127.0.0.1" do +          {node(), parent_value} +        end + +      assert result == {:"federated1@127.0.0.1, 123} + +  *Note*: while local bindings are captured and available within the block, +  other parent contexts like required, aliased, or imported modules are not +  in scope. Those will need to be reimported/aliases/required within the block +  as `within/2` is a remote procedure call. +  """ + +  @extra_apps Pleroma.Mixfile.application()[:extra_applications] + +  @doc """ +  Spawns the default Pleroma federated cluster. + +  Values before may be customized as needed for the test suite. +  """ +  def spawn_default_cluster do +    endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint) +    repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo) + +    spawn_cluster(%{ +      :"federated1@127.0.0.1" => [ +        {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated1")}, +        {:pleroma, Pleroma.Web.Endpoint, +         Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)} +      ], +      :"federated2@127.0.0.1" => [ +        {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated2")}, +        {:pleroma, Pleroma.Web.Endpoint, +         Keyword.merge(endpoint_conf, http: [port: 4012], url: [port: 4012], server: true)} +      ] +    }) +  end + +  @doc """ +  Spawns a configured map of federated nodes. + +  See `Pleroma.Cluster` module documentation for details. +  """ +  def spawn_cluster(node_configs) do +    # Turn node into a distributed node with the given long name +    :net_kernel.start([:"primary@127.0.0.1"]) + +    # Allow spawned nodes to fetch all code from this node +    {:ok, _} = :erl_boot_server.start([]) +    allow_boot("127.0.0.1") + +    silence_logger_warnings(fn -> +      node_configs +      |> Enum.map(&Task.async(fn -> start_slave(&1) end)) +      |> Enum.map(&Task.await(&1, 60_000)) +    end) +  end + +  @doc """ +  Executes block of code again remote node. + +  See `Pleroma.Cluster` module documentation for details. +  """ +  defmacro within(node, do: block) do +    quote do +      rpc(unquote(node), unquote(__MODULE__), :eval_quoted, [ +        unquote(Macro.escape(block)), +        binding() +      ]) +    end +  end + +  @doc false +  def eval_quoted(block, binding) do +    {result, _binding} = Code.eval_quoted(block, binding, __ENV__) +    result +  end + +  defp start_slave({node_host, override_configs}) do +    log(node_host, "booting federated VM") +    {:ok, node} = :slave.start(~c"127.0.0.1", node_name(node_host), vm_args()) +    add_code_paths(node) +    load_apps_and_transfer_configuration(node, override_configs) +    ensure_apps_started(node) +    {:ok, node} +  end + +  def rpc(node, module, function, args) do +    :rpc.block_call(node, module, function, args) +  end + +  defp vm_args do +    ~c"-loader inet -hosts 127.0.0.1 -setcookie #{:erlang.get_cookie()}" +  end + +  defp allow_boot(host) do +    {:ok, ipv4} = :inet.parse_ipv4_address(~c"#{host}") +    :ok = :erl_boot_server.add_slave(ipv4) +  end + +  defp add_code_paths(node) do +    rpc(node, :code, :add_paths, [:code.get_path()]) +  end + +  defp load_apps_and_transfer_configuration(node, override_configs) do +    Enum.each(Application.loaded_applications(), fn {app_name, _, _} -> +      app_name +      |> Application.get_all_env() +      |> Enum.each(fn {key, primary_config} -> +        rpc(node, Application, :put_env, [app_name, key, primary_config, [persistent: true]]) +      end) +    end) + +    Enum.each(override_configs, fn {app_name, key, val} -> +      rpc(node, Application, :put_env, [app_name, key, val, [persistent: true]]) +    end) +  end + +  defp log(node, msg), do: IO.puts("[#{node}] #{msg}") + +  defp ensure_apps_started(node) do +    loaded_names = Enum.map(Application.loaded_applications(), fn {name, _, _} -> name end) +    app_names = @extra_apps ++ (loaded_names -- @extra_apps) + +    rpc(node, Application, :ensure_all_started, [:mix]) +    rpc(node, Mix, :env, [Mix.env()]) +    rpc(node, __MODULE__, :prepare_database, []) + +    log(node, "starting application") + +    Enum.reduce(app_names, MapSet.new(), fn app, loaded -> +      if Enum.member?(loaded, app) do +        loaded +      else +        {:ok, started} = rpc(node, Application, :ensure_all_started, [app]) +        MapSet.union(loaded, MapSet.new(started)) +      end +    end) +  end + +  @doc false +  def prepare_database do +    log(node(), "preparing database") +    repo_config = Application.get_env(:pleroma, Pleroma.Repo) +    repo_config[:adapter].storage_down(repo_config) +    repo_config[:adapter].storage_up(repo_config) + +    {:ok, _, _} = +      Ecto.Migrator.with_repo(Pleroma.Repo, fn repo -> +        Ecto.Migrator.run(repo, :up, log: false, all: true) +      end) + +    Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual) +    {:ok, _} = Application.ensure_all_started(:ex_machina) +  end + +  defp silence_logger_warnings(func) do +    prev_level = Logger.level() +    Logger.configure(level: :error) +    res = func.() +    Logger.configure(level: prev_level) + +    res +  end + +  defp node_name(node_host) do +    node_host +    |> to_string() +    |> String.split("@") +    |> Enum.at(0) +    |> String.to_atom() +  end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index e3f797f64..bb8a64e72 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -31,7 +31,6 @@ defmodule Pleroma.Factory do        nickname: sequence(:nickname, &"nick#{&1}"),        password_hash: Comeonin.Pbkdf2.hashpwsalt("test"),        bio: sequence(:bio, &"Tester Number #{&1}"), -      info: %{},        last_digest_emailed_at: NaiveDateTime.utc_now()      } diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 965335e96..e3a621f49 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1035,6 +1035,22 @@ defmodule HttpRequestMock do       }}    end +  def get("http://localhost:8080/followers/fuser3", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/users_mock/friendica_followers.json") +     }} +  end + +  def get("http://localhost:8080/following/fuser3", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/users_mock/friendica_following.json") +     }} +  end +    def get("http://localhost:4001/users/fuser2/followers", _, _, _) do      {:ok,       %Tesla.Env{ diff --git a/test/test_helper.exs b/test/test_helper.exs index c8dbee010..241ad1f94 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -3,7 +3,8 @@  # SPDX-License-Identifier: AGPL-3.0-only  os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [] -ExUnit.start(exclude: os_exclude) +ExUnit.start(exclude: [:federated | os_exclude]) +  Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)  Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)  {:ok, _} = Application.ensure_all_started(:ex_machina) diff --git a/test/user_test.exs b/test/user_test.exs index e6302b525..c345e43e9 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -367,18 +367,6 @@ defmodule Pleroma.UserTest do        assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"      end - -    test "it ensures info is not nil" do -      changeset = User.register_changeset(%User{}, @full_user_data) - -      assert changeset.valid? - -      {:ok, user} = -        changeset -        |> Repo.insert() - -      refute is_nil(user.info) -    end    end    describe "user registration, with :account_activation_required" do @@ -432,8 +420,7 @@ defmodule Pleroma.UserTest do            :user,            local: false,            nickname: "admin@mastodon.example.org", -          ap_id: ap_id, -          info: %{} +          ap_id: ap_id          )        {:ok, fetched_user} = User.get_or_fetch(ap_id) @@ -494,8 +481,7 @@ defmodule Pleroma.UserTest do            local: false,            nickname: "admin@mastodon.example.org",            ap_id: "http://mastodon.example.org/users/admin", -          last_refreshed_at: a_week_ago, -          info: %{} +          last_refreshed_at: a_week_ago          )        assert orig_user.last_refreshed_at == a_week_ago @@ -536,7 +522,6 @@ defmodule Pleroma.UserTest do        name: "Someone",        nickname: "a@b.de",        ap_id: "http...", -      info: %{some: "info"},        avatar: %{some: "avatar"}      } @@ -961,9 +946,9 @@ defmodule Pleroma.UserTest do        {:ok, user} = User.follow(user, user2)        {:ok, _user} = User.deactivate(user) -      info = User.get_cached_user_info(user2) +      user2 = User.get_cached_by_id(user2.id) -      assert info.follower_count == 0 +      assert user2.follower_count == 0        assert [] = User.get_followers(user2)      end @@ -977,10 +962,10 @@ defmodule Pleroma.UserTest do        {:ok, _user} = User.deactivate(user) -      info = User.get_cached_user_info(user2) +      user2 = User.get_cached_by_id(user2.id)        assert refresh_record(user2).following_count == 0 -      assert info.following_count == 0 +      assert user2.following_count == 0        assert User.following_count(user2) == 0        assert [] = User.get_friends(user2)      end @@ -1143,8 +1128,7 @@ defmodule Pleroma.UserTest do          ap_id: user.ap_id,          name: user.name,          nickname: user.nickname, -        bio: String.duplicate("h", current_max_length + 1), -        info: %{} +        bio: String.duplicate("h", current_max_length + 1)        }        assert {:ok, %User{}} = User.insert_or_update_user(data) @@ -1157,8 +1141,7 @@ defmodule Pleroma.UserTest do        data = %{          ap_id: user.ap_id,          name: String.duplicate("h", current_max_length + 1), -        nickname: user.nickname, -        info: %{} +        nickname: user.nickname        }        assert {:ok, %User{}} = User.insert_or_update_user(data) @@ -1182,13 +1165,12 @@ defmodule Pleroma.UserTest do    describe "caching" do      test "invalidate_cache works" do        user = insert(:user) -      _user_info = User.get_cached_user_info(user) +      User.set_cache(user)        User.invalidate_cache(user)        {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")        {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}") -      {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")      end      test "User.delete() plugs any possible zombie objects" do @@ -1344,7 +1326,7 @@ defmodule Pleroma.UserTest do      {:ok, user} = User.block(user, follower) -    assert User.user_info(user).follower_count == 2 +    assert user.follower_count == 2    end    describe "list_inactive_users_query/1" do @@ -1521,51 +1503,6 @@ defmodule Pleroma.UserTest do      end    end -  describe "set_info_cache/2" do -    setup do -      user = insert(:user) -      {:ok, user: user} -    end - -    test "update from args", %{user: user} do -      User.set_info_cache(user, %{following_count: 15, follower_count: 18}) - -      %{follower_count: followers, following_count: following} = User.get_cached_user_info(user) -      assert followers == 18 -      assert following == 15 -    end - -    test "without args", %{user: user} do -      User.set_info_cache(user, %{}) - -      %{follower_count: followers, following_count: following} = User.get_cached_user_info(user) -      assert followers == 0 -      assert following == 0 -    end -  end - -  describe "user_info/2" do -    setup do -      user = insert(:user) -      {:ok, user: user} -    end - -    test "update from args", %{user: user} do -      %{follower_count: followers, following_count: following} = -        User.user_info(user, %{following_count: 15, follower_count: 18}) - -      assert followers == 18 -      assert following == 15 -    end - -    test "without args", %{user: user} do -      %{follower_count: followers, following_count: following} = User.user_info(user) - -      assert followers == 0 -      assert following == 0 -    end -  end -    describe "is_internal_user?/1" do      test "non-internal user returns false" do        user = insert(:user) @@ -1622,14 +1559,14 @@ defmodule Pleroma.UserTest do            ap_enabled: true          ) -      assert User.user_info(other_user).following_count == 0 -      assert User.user_info(other_user).follower_count == 0 +      assert other_user.following_count == 0 +      assert other_user.follower_count == 0        {:ok, user} = Pleroma.User.follow(user, other_user)        other_user = Pleroma.User.get_by_id(other_user.id) -      assert User.user_info(user).following_count == 1 -      assert User.user_info(other_user).follower_count == 1 +      assert user.following_count == 1 +      assert other_user.follower_count == 1      end      test "syncronizes the counters with the remote instance for the followed when enabled" do @@ -1645,14 +1582,14 @@ defmodule Pleroma.UserTest do            ap_enabled: true          ) -      assert User.user_info(other_user).following_count == 0 -      assert User.user_info(other_user).follower_count == 0 +      assert other_user.following_count == 0 +      assert other_user.follower_count == 0        Pleroma.Config.put([:instance, :external_user_synchronization], true)        {:ok, _user} = User.follow(user, other_user)        other_user = User.get_by_id(other_user.id) -      assert User.user_info(other_user).follower_count == 437 +      assert other_user.follower_count == 437      end      test "syncronizes the counters with the remote instance for the follower when enabled" do @@ -1668,13 +1605,13 @@ defmodule Pleroma.UserTest do            ap_enabled: true          ) -      assert User.user_info(other_user).following_count == 0 -      assert User.user_info(other_user).follower_count == 0 +      assert other_user.following_count == 0 +      assert other_user.follower_count == 0        Pleroma.Config.put([:instance, :external_user_synchronization], true)        {:ok, other_user} = User.follow(other_user, user) -      assert User.user_info(other_user).following_count == 152 +      assert other_user.following_count == 152      end    end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index d437ad456..2677b9e36 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -4,8 +4,11 @@  defmodule Pleroma.Web.ActivityPub.ActivityPubTest do    use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo +    alias Pleroma.Activity    alias Pleroma.Builders.ActivityBuilder +  alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub @@ -1554,5 +1557,80 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert follow_info.hide_followers == false        assert follow_info.hide_follows == true      end + +    test "detects hidden follows/followers for friendica" do +      user = +        insert(:user, +          local: false, +          follower_address: "http://localhost:8080/followers/fuser3", +          following_address: "http://localhost:8080/following/fuser3" +        ) + +      {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) +      assert follow_info.hide_followers == true +      assert follow_info.follower_count == 296 +      assert follow_info.following_count == 32 +      assert follow_info.hide_follows == true +    end +  end + +  describe "Move activity" do +    test "create" do +      %{ap_id: old_ap_id} = old_user = insert(:user) +      %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) +      follower = insert(:user) +      follower_move_opted_out = insert(:user, allow_following_move: false) + +      User.follow(follower, old_user) +      User.follow(follower_move_opted_out, old_user) + +      assert User.following?(follower, old_user) +      assert User.following?(follower_move_opted_out, old_user) + +      assert {:ok, activity} = ActivityPub.move(old_user, new_user) + +      assert %Activity{ +               actor: ^old_ap_id, +               data: %{ +                 "actor" => ^old_ap_id, +                 "object" => ^old_ap_id, +                 "target" => ^new_ap_id, +                 "type" => "Move" +               }, +               local: true +             } = activity + +      params = %{ +        "op" => "move_following", +        "origin_id" => old_user.id, +        "target_id" => new_user.id +      } + +      assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params) + +      Pleroma.Workers.BackgroundWorker.perform(params, nil) + +      refute User.following?(follower, old_user) +      assert User.following?(follower, new_user) + +      assert User.following?(follower_move_opted_out, old_user) +      refute User.following?(follower_move_opted_out, new_user) + +      activity = %Activity{activity | object: nil} + +      assert [%Notification{activity: ^activity}] = +               Notification.for_user_since(follower, ~N[2019-04-13 11:22:33]) + +      assert [%Notification{activity: ^activity}] = +               Notification.for_user_since(follower_move_opted_out, ~N[2019-04-13 11:22:33]) +    end + +    test "old user must be in the new user's `also_known_as` list" do +      old_user = insert(:user) +      new_user = insert(:user) + +      assert {:error, "Target account must have the origin in `alsoKnownAs`"} = +               ActivityPub.move(old_user, new_user) +    end    end  end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 0bdd514e9..5da358c43 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -39,6 +39,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert activity == returned_activity      end +    @tag capture_log: true      test "it fetches replied-to activities if we don't have them" do        data =          File.read!("test/fixtures/mastodon-post-activity.json") @@ -533,6 +534,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert object.data["content"] == "this is a private toot"      end +    @tag capture_log: true      test "it rejects incoming announces with an inlined activity from another origin" do        data =          File.read!("test/fixtures/bogus-mastodon-announce.json") @@ -681,6 +683,37 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert user.bio == "<p>Some bio</p>"      end +    test "it works with alsoKnownAs" do +      {:ok, %Activity{data: %{"actor" => actor}}} = +        "test/fixtures/mastodon-post-activity.json" +        |> File.read!() +        |> Poison.decode!() +        |> Transmogrifier.handle_incoming() + +      assert User.get_cached_by_ap_id(actor).also_known_as == ["http://example.org/users/foo"] + +      {:ok, _activity} = +        "test/fixtures/mastodon-update.json" +        |> File.read!() +        |> Poison.decode!() +        |> Map.put("actor", actor) +        |> Map.update!("object", fn object -> +          object +          |> Map.put("actor", actor) +          |> Map.put("id", actor) +          |> Map.put("alsoKnownAs", [ +            "http://mastodon.example.org/users/foo", +            "http://example.org/users/bar" +          ]) +        end) +        |> Transmogrifier.handle_incoming() + +      assert User.get_cached_by_ap_id(actor).also_known_as == [ +               "http://mastodon.example.org/users/foo", +               "http://example.org/users/bar" +             ] +    end +      test "it works with custom profile fields" do        {:ok, activity} =          "test/fixtures/mastodon-post-activity.json" @@ -814,6 +847,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert Activity.get_by_id(activity.id)      end +    @tag capture_log: true      test "it works for incoming user deletes" do        %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin") @@ -1269,6 +1303,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]        assert [user.follower_address] == activity.data["to"]      end + +    test "it accepts Move activities" do +      old_user = insert(:user) +      new_user = insert(:user) + +      message = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "type" => "Move", +        "actor" => old_user.ap_id, +        "object" => old_user.ap_id, +        "target" => new_user.ap_id +      } + +      assert :error = Transmogrifier.handle_incoming(message) + +      {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]}) + +      assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message) +      assert activity.actor == old_user.ap_id +      assert activity.data["actor"] == old_user.ap_id +      assert activity.data["object"] == old_user.ap_id +      assert activity.data["target"] == new_user.ap_id +      assert activity.data["type"] == "Move" +    end    end    describe "prepare outgoing" do @@ -1749,6 +1807,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert modified_object["inReplyToAtomUri"] == ""      end +    @tag capture_log: true      test "returns modified object when allowed incoming reply", %{data: data} do        object_with_reply =          Map.put( @@ -1868,6 +1927,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do               end) =~ "Unsupported URI scheme"      end +    @tag capture_log: true      test "returns {:ok, %Object{}} for success case" do        assert {:ok, %Object{}} =                 Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873") diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 108baad91..4148f04bc 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1989,6 +1989,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        Pleroma.Config.put([:instance, :dynamic_configuration], true)      end +    @tag capture_log: true      test "create new config setting in db", %{conn: conn} do        conn =          post(conn, "/api/pleroma/admin/config", %{ diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index 519b56d6c..77cfce4fa 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -103,6 +103,21 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert user["locked"] == true      end +    test "updates the user's allow_following_move", %{conn: conn} do +      user = insert(:user) + +      assert user.allow_following_move == true + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{allow_following_move: "false"}) + +      assert refresh_record(user).allow_following_move == false +      assert user = json_response(conn, 200) +      assert user["pleroma"]["allow_following_move"] == false +    end +      test "updates the user's default scope", %{conn: conn} do        user = insert(:user) diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index af88841ed..35aefb7dc 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -102,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do      privacy = user.default_scope      assert %{ -             pleroma: %{notification_settings: ^notification_settings}, +             pleroma: %{notification_settings: ^notification_settings, allow_following_move: true},               source: %{privacy: ^privacy}             } = AccountView.render("show.json", %{user: user, for: user})    end @@ -350,7 +350,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        }      } -    assert expected == AccountView.render("show.json", %{user: user, for: other_user}) +    assert expected == +             AccountView.render("show.json", %{user: refresh_record(user), for: other_user})    end    test "returns the settings store if the requesting user is the represented user and it's requested specifically" do @@ -374,6 +375,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do      refute result.display_name == "<marquee> username </marquee>"    end +  test "never display nil user follow counts" do +    user = insert(:user, following_count: 0, follower_count: 0) +    result = AccountView.render("show.json", %{user: user}) + +    assert result.following_count == 0 +    assert result.followers_count == 0 +  end +    describe "hiding follows/following" do      test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do        user = diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index c9043a69a..26e1afc85 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -107,4 +107,31 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do      assert [] ==               NotificationView.render("index.json", %{notifications: [notification], for: followed})    end + +  test "Move notification" do +    %{ap_id: old_ap_id} = old_user = insert(:user) +    %{ap_id: _new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) +    follower = insert(:user) + +    User.follow(follower, old_user) +    Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) +    Pleroma.Tests.ObanHelpers.perform_all() + +    old_user = refresh_record(old_user) +    new_user = refresh_record(new_user) + +    [notification] = Notification.for_user(follower) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "move", +      account: AccountView.render("show.json", %{user: old_user, for: follower}), +      target: AccountView.render("show.json", %{user: new_user, for: follower}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    assert [expected] == +             NotificationView.render("index.json", %{notifications: [notification], for: follower}) +  end  end diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 80a7541b2..8265f18dd 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -15,7 +15,7 @@ defmodule Pleroma.Web.StreamerTest do    alias Pleroma.Web.Streamer.StreamerSocket    alias Pleroma.Web.Streamer.Worker -  @moduletag needs_streamer: true +  @moduletag needs_streamer: true, capture_log: true    clear_config_all([:instance, :skip_thread_containment])    describe "user streams" do | 
