Merge branch 'preload-data' into 'develop'
[akkoma] / test / web / activity_pub / transmogrifier_test.exs
index 4df3024a6c53ad878f1c646e97bfe8dbbe79e751..100821056203140c700efd960336b8a9337824e9 100644 (file)
@@ -1,9 +1,11 @@
 # Pleroma: A lightweight social networking server
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
+  use Oban.Testing, repo: Pleroma.Repo
   use Pleroma.DataCase
   use Pleroma.DataCase
+
   alias Pleroma.Activity
   alias Pleroma.Object
   alias Pleroma.Object.Fetcher
   alias Pleroma.Activity
   alias Pleroma.Object
   alias Pleroma.Object.Fetcher
@@ -23,9 +25,66 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
     :ok
   end
 
     :ok
   end
 
-  clear_config([:instance, :max_remote_account_fields])
+  setup do: clear_config([:instance, :max_remote_account_fields])
 
   describe "handle_incoming" do
 
   describe "handle_incoming" do
+    test "it works for incoming notices with tag not being an array (kroeg)" do
+      data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      object = Object.normalize(data["object"])
+
+      assert object.data["emoji"] == %{
+               "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
+             }
+
+      data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      object = Object.normalize(data["object"])
+
+      assert "test" in object.data["tag"]
+    end
+
+    test "it works for incoming notices with url not being a string (prismo)" do
+      data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      object = Object.normalize(data["object"])
+
+      assert object.data["url"] == "https://prismo.news/posts/83"
+    end
+
+    test "it cleans up incoming notices which are not really DMs" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      to = [user.ap_id, other_user.ap_id]
+
+      data =
+        File.read!("test/fixtures/mastodon-post-activity.json")
+        |> Poison.decode!()
+        |> Map.put("to", to)
+        |> Map.put("cc", [])
+
+      object =
+        data["object"]
+        |> Map.put("to", to)
+        |> Map.put("cc", [])
+
+      data = Map.put(data, "object", object)
+
+      {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+      assert data["to"] == []
+      assert data["cc"] == to
+
+      object_data = Object.normalize(activity).data
+
+      assert object_data["to"] == []
+      assert object_data["cc"] == to
+    end
+
     test "it ignores an incoming notice if we already have it" do
       activity = insert(:note_activity)
 
     test "it ignores an incoming notice if we already have it" do
       activity = insert(:note_activity)
 
@@ -39,7 +98,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert activity == returned_activity
     end
 
       assert activity == returned_activity
     end
 
-    test "it fetches replied-to activities if we don't have them" do
+    @tag capture_log: true
+    test "it fetches reply-to activities if we don't have them" do
       data =
         File.read!("test/fixtures/mastodon-post-activity.json")
         |> Poison.decode!()
       data =
         File.read!("test/fixtures/mastodon-post-activity.json")
         |> Poison.decode!()
@@ -60,7 +120,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
     end
 
       assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
     end
 
-    test "it does not fetch replied-to activities beyond max_replies_depth" do
+    test "it does not fetch reply-to activities beyond max replies depth limit" do
       data =
         File.read!("test/fixtures/mastodon-post-activity.json")
         |> Poison.decode!()
       data =
         File.read!("test/fixtures/mastodon-post-activity.json")
         |> Poison.decode!()
@@ -72,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       data = Map.put(data, "object", object)
 
       with_mock Pleroma.Web.Federator,
       data = Map.put(data, "object", object)
 
       with_mock Pleroma.Web.Federator,
-        allowed_incoming_reply_depth?: fn _ -> false end do
+        allowed_thread_distance?: fn _ -> false end do
         {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
 
         returned_object = Object.normalize(returned_activity, false)
         {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
 
         returned_object = Object.normalize(returned_activity, false)
@@ -209,8 +269,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       {:ok, activity} =
         CommonAPI.post(user, %{
 
       {:ok, activity} =
         CommonAPI.post(user, %{
-          "status" => "suya...",
-          "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
+          status: "suya...",
+          poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10}
         })
 
       object = Object.normalize(activity)
         })
 
       object = Object.normalize(activity)
@@ -257,232 +317,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
                "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
     end
 
                "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
     end
 
-    test "it works for incoming announces with actor being inlined (kroeg)" do
-      data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "https://puckipedia.com/"
-    end
-
-    test "it works for incoming notices with tag not being an array (kroeg)" do
-      data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      object = Object.normalize(data["object"])
-
-      assert object.data["emoji"] == %{
-               "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
-             }
-
-      data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      object = Object.normalize(data["object"])
-
-      assert "test" in object.data["tag"]
-    end
-
-    test "it works for incoming notices with url not being a string (prismo)" do
-      data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      object = Object.normalize(data["object"])
-
-      assert object.data["url"] == "https://prismo.news/posts/83"
-    end
-
-    test "it cleans up incoming notices which are not really DMs" do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      to = [user.ap_id, other_user.ap_id]
-
-      data =
-        File.read!("test/fixtures/mastodon-post-activity.json")
-        |> Poison.decode!()
-        |> Map.put("to", to)
-        |> Map.put("cc", [])
-
-      object =
-        data["object"]
-        |> Map.put("to", to)
-        |> Map.put("cc", [])
-
-      data = Map.put(data, "object", object)
-
-      {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
-
-      assert data["to"] == []
-      assert data["cc"] == to
-
-      object_data = Object.normalize(activity).data
-
-      assert object_data["to"] == []
-      assert object_data["cc"] == to
-    end
-
-    test "it works for incoming likes" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
-
-      data =
-        File.read!("test/fixtures/mastodon-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Like"
-      assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
-      assert data["object"] == activity.data["object"]
-    end
-
-    test "it returns an error for incoming unlikes wihout a like activity" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
-
-      data =
-        File.read!("test/fixtures/mastodon-undo-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
-
-      assert Transmogrifier.handle_incoming(data) == :error
-    end
-
-    test "it works for incoming unlikes with an existing like activity" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
-
-      like_data =
-        File.read!("test/fixtures/mastodon-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
-
-      {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
-
-      data =
-        File.read!("test/fixtures/mastodon-undo-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", like_data)
-        |> Map.put("actor", like_data["actor"])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Undo"
-      assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
-      assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
-    end
-
-    test "it works for incoming unlikes with an existing like activity and a compact object" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
-
-      like_data =
-        File.read!("test/fixtures/mastodon-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
-
-      {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
-
-      data =
-        File.read!("test/fixtures/mastodon-undo-like.json")
-        |> Poison.decode!()
-        |> Map.put("object", like_data["id"])
-        |> Map.put("actor", like_data["actor"])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Undo"
-      assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
-      assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
-    end
-
-    test "it works for incoming announces" do
-      data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Announce"
-
-      assert data["id"] ==
-               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
-
-      assert data["object"] ==
-               "http://mastodon.example.org/users/admin/statuses/99541947525187367"
-
-      assert Activity.get_create_by_object_ap_id(data["object"])
-    end
-
-    test "it works for incoming announces with an existing activity" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
-
-      data =
-        File.read!("test/fixtures/mastodon-announce.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Announce"
-
-      assert data["id"] ==
-               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
-
-      assert data["object"] == activity.data["object"]
-
-      assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
-    end
-
-    test "it works for incoming announces with an inlined activity" do
-      data =
-        File.read!("test/fixtures/mastodon-announce-private.json")
-        |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-      assert data["type"] == "Announce"
-
-      assert data["id"] ==
-               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
-
-      object = Object.normalize(data["object"])
-
-      assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
-      assert object.data["content"] == "this is a private toot"
-    end
-
-    test "it rejects incoming announces with an inlined activity from another origin" do
-      data =
-        File.read!("test/fixtures/bogus-mastodon-announce.json")
-        |> Poison.decode!()
-
-      assert :error = Transmogrifier.handle_incoming(data)
-    end
-
-    test "it does not clobber the addressing on announce activities" do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
-
-      data =
-        File.read!("test/fixtures/mastodon-announce.json")
-        |> Poison.decode!()
-        |> Map.put("object", Object.normalize(activity).data["id"])
-        |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
-        |> Map.put("cc", [])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
-    end
-
     test "it ensures that as:Public activities make it to their followers collection" do
       user = insert(:user)
 
     test "it ensures that as:Public activities make it to their followers collection" do
       user = insert(:user)
 
@@ -553,231 +387,18 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       refute Map.has_key?(object.data, "likes")
     end
 
       refute Map.has_key?(object.data, "likes")
     end
 
-    test "it works for incoming update activities" do
-      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
-
-      object =
-        update_data["object"]
-        |> Map.put("actor", data["actor"])
-        |> Map.put("id", data["actor"])
-
-      update_data =
-        update_data
-        |> Map.put("actor", data["actor"])
-        |> Map.put("object", object)
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
-
-      assert data["id"] == update_data["id"]
-
-      user = User.get_cached_by_ap_id(data["actor"])
-      assert user.name == "gargle"
-
-      assert user.avatar["url"] == [
-               %{
-                 "href" =>
-                   "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
-               }
-             ]
-
-      assert user.banner["url"] == [
-               %{
-                 "href" =>
-                   "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
-               }
-             ]
-
-      assert user.bio == "<p>Some bio</p>"
-    end
-
-    test "it works with custom profile fields" do
-      {:ok, activity} =
-        "test/fixtures/mastodon-post-activity.json"
-        |> File.read!()
-        |> Poison.decode!()
-        |> Transmogrifier.handle_incoming()
-
-      user = User.get_cached_by_ap_id(activity.actor)
-
-      assert User.fields(user) == [
-               %{"name" => "foo", "value" => "bar"},
-               %{"name" => "foo1", "value" => "bar1"}
-             ]
-
-      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
-
-      object =
-        update_data["object"]
-        |> Map.put("actor", user.ap_id)
-        |> Map.put("id", user.ap_id)
-
-      update_data =
-        update_data
-        |> Map.put("actor", user.ap_id)
-        |> Map.put("object", object)
-
-      {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data)
-
-      user = User.get_cached_by_ap_id(user.ap_id)
-
-      assert User.fields(user) == [
-               %{"name" => "foo", "value" => "updated"},
-               %{"name" => "foo1", "value" => "updated"}
-             ]
-
-      Pleroma.Config.put([:instance, :max_remote_account_fields], 2)
-
-      update_data =
-        put_in(update_data, ["object", "attachment"], [
-          %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"},
-          %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"},
-          %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"}
-        ])
-
-      {:ok, _} = Transmogrifier.handle_incoming(update_data)
-
-      user = User.get_cached_by_ap_id(user.ap_id)
-
-      assert User.fields(user) == [
-               %{"name" => "foo", "value" => "updated"},
-               %{"name" => "foo1", "value" => "updated"}
-             ]
-
-      update_data = put_in(update_data, ["object", "attachment"], [])
-
-      {:ok, _} = Transmogrifier.handle_incoming(update_data)
-
-      user = User.get_cached_by_ap_id(user.ap_id)
-
-      assert User.fields(user) == []
-    end
-
-    test "it works for incoming update activities which lock the account" do
-      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
-
-      object =
-        update_data["object"]
-        |> Map.put("actor", data["actor"])
-        |> Map.put("id", data["actor"])
-        |> Map.put("manuallyApprovesFollowers", true)
-
-      update_data =
-        update_data
-        |> Map.put("actor", data["actor"])
-        |> Map.put("object", object)
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
-
-      user = User.get_cached_by_ap_id(data["actor"])
-      assert user.locked == true
-    end
-
-    test "it works for incoming deletes" do
-      activity = insert(:note_activity)
-      deleting_user = insert(:user)
-
-      data =
-        File.read!("test/fixtures/mastodon-delete.json")
-        |> Poison.decode!()
-
-      object =
-        data["object"]
-        |> Map.put("id", activity.data["object"])
-
-      data =
-        data
-        |> Map.put("object", object)
-        |> Map.put("actor", deleting_user.ap_id)
-
-      {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
-        Transmogrifier.handle_incoming(data)
-
-      assert id == data["id"]
-      refute Activity.get_by_id(activity.id)
-      assert actor == deleting_user.ap_id
-    end
-
-    test "it fails for incoming deletes with spoofed origin" do
-      activity = insert(:note_activity)
-
-      data =
-        File.read!("test/fixtures/mastodon-delete.json")
-        |> Poison.decode!()
-
-      object =
-        data["object"]
-        |> Map.put("id", activity.data["object"])
-
-      data =
-        data
-        |> Map.put("object", object)
-
-      assert capture_log(fn ->
-               :error = Transmogrifier.handle_incoming(data)
-             end) =~
-               "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, :nxdomain}"
-
-      assert Activity.get_by_id(activity.id)
-    end
-
-    test "it works for incoming user deletes" do
-      %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
-
-      data =
-        File.read!("test/fixtures/mastodon-delete-user.json")
-        |> Poison.decode!()
-
-      {:ok, _} = Transmogrifier.handle_incoming(data)
-      ObanHelpers.perform_all()
-
-      refute User.get_cached_by_ap_id(ap_id)
-    end
-
-    test "it fails for incoming user deletes with spoofed origin" do
-      %{ap_id: ap_id} = insert(:user)
-
-      data =
-        File.read!("test/fixtures/mastodon-delete-user.json")
-        |> Poison.decode!()
-        |> Map.put("actor", ap_id)
-
-      assert :error == Transmogrifier.handle_incoming(data)
-      assert User.get_cached_by_ap_id(ap_id)
-    end
-
-    test "it works for incoming unannounces with an existing notice" do
+    test "it strips internal reactions" do
       user = insert(:user)
       user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+      {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢")
 
 
-      announce_data =
-        File.read!("test/fixtures/mastodon-announce.json")
-        |> Poison.decode!()
-        |> Map.put("object", activity.data["object"])
+      %{object: object} = Activity.get_by_id_with_object(activity.id)
+      assert Map.has_key?(object.data, "reactions")
+      assert Map.has_key?(object.data, "reaction_count")
 
 
-      {:ok, %Activity{data: announce_data, local: false}} =
-        Transmogrifier.handle_incoming(announce_data)
-
-      data =
-        File.read!("test/fixtures/mastodon-undo-announce.json")
-        |> Poison.decode!()
-        |> Map.put("object", announce_data)
-        |> Map.put("actor", announce_data["actor"])
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
-      assert data["type"] == "Undo"
-      assert object_data = data["object"]
-      assert object_data["type"] == "Announce"
-      assert object_data["object"] == activity.data["object"]
-
-      assert object_data["id"] ==
-               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
+      object_data = Transmogrifier.strip_internal_fields(object.data)
+      refute Map.has_key?(object_data, "reactions")
+      refute Map.has_key?(object_data, "reaction_count")
     end
 
     test "it works for incomming unfollows with an existing follow" do
     end
 
     test "it works for incomming unfollows with an existing follow" do
@@ -805,6 +426,25 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
     end
 
       refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
     end
 
+    test "it works for incoming follows to locked account" do
+      pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
+      user = insert(:user, locked: true)
+
+      data =
+        File.read!("test/fixtures/mastodon-follow-activity.json")
+        |> Poison.decode!()
+        |> Map.put("object", user.ap_id)
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+      assert data["type"] == "Follow"
+      assert data["object"] == user.ap_id
+      assert data["state"] == "pending"
+      assert data["actor"] == "http://mastodon.example.org/users/admin"
+
+      assert [^pending_follower] = User.get_follow_requests(user)
+    end
+
     test "it works for incoming blocks" do
       user = insert(:user)
 
     test "it works for incoming blocks" do
       user = insert(:user)
 
@@ -855,32 +495,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       refute User.following?(blocked, blocker)
     end
 
       refute User.following?(blocked, blocker)
     end
 
-    test "it works for incoming unblocks with an existing block" do
-      user = insert(:user)
-
-      block_data =
-        File.read!("test/fixtures/mastodon-block-activity.json")
-        |> Poison.decode!()
-        |> Map.put("object", user.ap_id)
-
-      {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
-
-      data =
-        File.read!("test/fixtures/mastodon-unblock-activity.json")
-        |> Poison.decode!()
-        |> Map.put("object", block_data)
-
-      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-      assert data["type"] == "Undo"
-      assert data["object"]["type"] == "Block"
-      assert data["object"]["object"] == user.ap_id
-      assert data["actor"] == "http://mastodon.example.org/users/admin"
-
-      blocker = User.get_cached_by_ap_id(data["actor"])
-
-      refute User.blocks?(blocker, user)
-    end
-
     test "it works for incoming accepts which were pre-accepted" do
       follower = insert(:user)
       followed = insert(:user)
     test "it works for incoming accepts which were pre-accepted" do
       follower = insert(:user)
       followed = insert(:user)
@@ -954,6 +568,12 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       follower = User.get_cached_by_id(follower.id)
 
       assert User.following?(follower, followed) == true
       follower = User.get_cached_by_id(follower.id)
 
       assert User.following?(follower, followed) == true
+
+      follower = User.get_by_id(follower.id)
+      assert follower.following_count == 1
+
+      followed = User.get_by_id(followed.id)
+      assert followed.follower_count == 1
     end
 
     test "it fails for incoming accepts which cannot be correlated" do
     end
 
     test "it fails for incoming accepts which cannot be correlated" do
@@ -1054,6 +674,35 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       :error = Transmogrifier.handle_incoming(data)
     end
 
       :error = Transmogrifier.handle_incoming(data)
     end
 
+    test "skip converting the content when it is nil" do
+      object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe"
+
+      {:ok, object} = Fetcher.fetch_and_contain_remote_object_from_id(object_id)
+
+      result =
+        Pleroma.Web.ActivityPub.Transmogrifier.fix_object(Map.merge(object, %{"content" => nil}))
+
+      assert result["content"] == nil
+    end
+
+    test "it converts content of object to html" do
+      object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe"
+
+      {:ok, %{"content" => content_markdown}} =
+        Fetcher.fetch_and_contain_remote_object_from_id(object_id)
+
+      {:ok, %Pleroma.Object{data: %{"content" => content}} = object} =
+        Fetcher.fetch_object_from_id(object_id)
+
+      assert content_markdown ==
+               "Support this and our other Michigan!/usr/group videos and meetings. Learn more at http://mug.org/membership\n\nTwenty Years in Jail: FreeBSD's Jails, Then and Now\n\nJails started as a limited virtualization system, but over the last two years they've..."
+
+      assert content ==
+               "<p>Support this and our other Michigan!/usr/group videos and meetings. Learn more at <a href=\"http://mug.org/membership\">http://mug.org/membership</a></p><p>Twenty Years in Jail: FreeBSD’s Jails, Then and Now</p><p>Jails started as a limited virtualization system, but over the last two years they’ve…</p>"
+
+      assert object.data["mediaType"] == "text/html"
+    end
+
     test "it remaps video URLs as attachments if necessary" do
       {:ok, object} =
         Fetcher.fetch_object_from_id(
     test "it remaps video URLs as attachments if necessary" do
       {:ok, object} =
         Fetcher.fetch_object_from_id(
@@ -1063,19 +712,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       attachment = %{
         "type" => "Link",
         "mediaType" => "video/mp4",
       attachment = %{
         "type" => "Link",
         "mediaType" => "video/mp4",
-        "href" =>
-          "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
-        "mimeType" => "video/mp4",
-        "size" => 5_015_880,
         "url" => [
           %{
             "href" =>
               "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
         "url" => [
           %{
             "href" =>
               "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
-            "mediaType" => "video/mp4",
-            "type" => "Link"
+            "mediaType" => "video/mp4"
           }
           }
-        ],
-        "width" => 480
+        ]
       }
 
       assert object.data["url"] ==
       }
 
       assert object.data["url"] ==
@@ -1088,7 +731,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       user = insert(:user)
       other_user = insert(:user)
 
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
       object = Object.normalize(activity)
 
       note_obj = %{
       object = Object.normalize(activity)
 
       note_obj = %{
@@ -1159,15 +802,128 @@ 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
       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 "`handle_incoming/2`, Mastodon format `replies` handling" do
+    setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
+    setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
+
+    setup do
+      data =
+        "test/fixtures/mastodon-post-activity.json"
+        |> File.read!()
+        |> Poison.decode!()
+
+      items = get_in(data, ["object", "replies", "first", "items"])
+      assert length(items) > 0
+
+      %{data: data, items: items}
+    end
+
+    test "schedules background fetching of `replies` items if max thread depth limit allows", %{
+      data: data,
+      items: items
+    } do
+      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10)
+
+      {:ok, _activity} = Transmogrifier.handle_incoming(data)
+
+      for id <- items do
+        job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
+        assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
+      end
+    end
+
+    test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
+         %{data: data} do
+      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
+
+      {:ok, _activity} = Transmogrifier.handle_incoming(data)
+
+      assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
+    end
+  end
+
+  describe "`handle_incoming/2`, Pleroma format `replies` handling" do
+    setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
+    setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
+
+    setup do
+      user = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(user, %{status: "post1"})
+
+      {:ok, reply1} =
+        CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id})
+
+      {:ok, reply2} =
+        CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id})
+
+      replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end)
+
+      {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data)
+
+      Repo.delete(activity.object)
+      Repo.delete(activity)
+
+      %{federation_output: federation_output, replies_uris: replies_uris}
+    end
+
+    test "schedules background fetching of `replies` items if max thread depth limit allows", %{
+      federation_output: federation_output,
+      replies_uris: replies_uris
+    } do
+      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 1)
+
+      {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
+
+      for id <- replies_uris do
+        job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
+        assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
+      end
+    end
+
+    test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
+         %{federation_output: federation_output} do
+      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
+
+      {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
+
+      assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
+    end
   end
 
   describe "prepare outgoing" do
     test "it inlines private announced objects" do
       user = insert(:user)
 
   end
 
   describe "prepare outgoing" do
     test "it inlines private announced objects" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey", "visibility" => "private"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
 
 
-      {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user)
+      {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
 
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
 
@@ -1180,31 +936,36 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       other_user = insert(:user)
 
       {:ok, activity} =
       other_user = insert(:user)
 
       {:ok, activity} =
-        CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
+        CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"})
 
 
-      {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-      object = modified["object"]
+      with_mock Pleroma.Notification,
+        get_notified_from_activity: fn _, _ -> [] end do
+        {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
 
-      expected_mention = %{
-        "href" => other_user.ap_id,
-        "name" => "@#{other_user.nickname}",
-        "type" => "Mention"
-      }
+        object = modified["object"]
 
 
-      expected_tag = %{
-        "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
-        "type" => "Hashtag",
-        "name" => "#2hu"
-      }
+        expected_mention = %{
+          "href" => other_user.ap_id,
+          "name" => "@#{other_user.nickname}",
+          "type" => "Mention"
+        }
+
+        expected_tag = %{
+          "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
+          "type" => "Hashtag",
+          "name" => "#2hu"
+        }
 
 
-      assert Enum.member?(object["tag"], expected_tag)
-      assert Enum.member?(object["tag"], expected_mention)
+        refute called(Pleroma.Notification.get_notified_from_activity(:_, :_))
+        assert Enum.member?(object["tag"], expected_tag)
+        assert Enum.member?(object["tag"], expected_mention)
+      end
     end
 
     test "it adds the sensitive property" do
       user = insert(:user)
 
     end
 
     test "it adds the sensitive property" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "#nsfw hey"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"})
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["object"]["sensitive"]
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["object"]["sensitive"]
@@ -1213,7 +974,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
     test "it adds the json-ld context and the conversation property" do
       user = insert(:user)
 
     test "it adds the json-ld context and the conversation property" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["@context"] ==
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["@context"] ==
@@ -1225,7 +986,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
     test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
       user = insert(:user)
 
     test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["object"]["actor"] == modified["object"]["attributedTo"]
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["object"]["actor"] == modified["object"]["attributedTo"]
@@ -1234,7 +995,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
     test "it strips internal hashtag data" do
       user = insert(:user)
 
     test "it strips internal hashtag data" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"})
 
       expected_tag = %{
         "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
 
       expected_tag = %{
         "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
@@ -1250,7 +1011,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
     test "it strips internal fields" do
       user = insert(:user)
 
     test "it strips internal fields" do
       user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :firefox:"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "#2hu :firefox:"})
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
@@ -1282,14 +1043,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       user = insert(:user)
       other_user = insert(:user)
 
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"})
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["directMessage"] == false
 
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["directMessage"] == false
 
-      {:ok, activity} =
-        CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"})
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
@@ -1297,8 +1057,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       {:ok, activity} =
         CommonAPI.post(user, %{
 
       {:ok, activity} =
         CommonAPI.post(user, %{
-          "status" => "@#{other_user.nickname} :moominmamma:",
-          "visibility" => "direct"
+          status: "@#{other_user.nickname} :moominmamma:",
+          visibility: "direct"
         })
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
         })
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
@@ -1310,8 +1070,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       user = insert(:user)
       {:ok, list} = Pleroma.List.create("foo", user)
 
       user = insert(:user)
       {:ok, list} = Pleroma.List.create("foo", user)
 
-      {:ok, activity} =
-        CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
 
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
@@ -1343,10 +1102,11 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
           follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
         })
 
           follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
         })
 
-      user_two = insert(:user, %{following: [user.follower_address]})
+      user_two = insert(:user)
+      Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
 
 
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
-      {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
+      {:ok, activity} = CommonAPI.post(user, %{status: "test"})
+      {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"})
       assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
 
       user = User.get_cached_by_id(user.id)
       assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
 
       user = User.get_cached_by_id(user.id)
@@ -1390,8 +1150,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       refute user.follower_address in unrelated_activity.recipients
 
       user_two = User.get_cached_by_id(user_two.id)
       refute user.follower_address in unrelated_activity.recipients
 
       user_two = User.get_cached_by_id(user_two.id)
-      assert user.follower_address in user_two.following
-      refute "..." in user_two.following
+      assert User.following?(user_two, user)
+      refute "..." in User.following(user_two)
     end
   end
 
     end
   end
 
@@ -1417,7 +1177,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
         "type" => "Announce"
       }
 
         "type" => "Announce"
       }
 
-      :error = Transmogrifier.handle_incoming(data)
+      assert capture_log(fn ->
+               {:error, _} = Transmogrifier.handle_incoming(data)
+             end) =~ "Object containment failed"
     end
 
     test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
     end
 
     test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
@@ -1430,7 +1192,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
         "type" => "Announce"
       }
 
         "type" => "Announce"
       }
 
-      :error = Transmogrifier.handle_incoming(data)
+      assert capture_log(fn ->
+               {:error, _} = Transmogrifier.handle_incoming(data)
+             end) =~ "Object containment failed"
     end
 
     test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
     end
 
     test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
@@ -1443,7 +1207,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
         "type" => "Announce"
       }
 
         "type" => "Announce"
       }
 
-      :error = Transmogrifier.handle_incoming(data)
+      assert capture_log(fn ->
+               {:error, _} = Transmogrifier.handle_incoming(data)
+             end) =~ "Object containment failed"
     end
   end
 
     end
   end
 
@@ -1506,8 +1272,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
     {:ok, poll_activity} =
       CommonAPI.post(user, %{
 
     {:ok, poll_activity} =
       CommonAPI.post(user, %{
-        "status" => "suya...",
-        "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
+        status: "suya...",
+        poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10}
       })
 
     poll_object = Object.normalize(poll_activity)
       })
 
     poll_object = Object.normalize(poll_activity)
@@ -1591,7 +1357,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
   end
 
   describe "fix_in_reply_to/2" do
   end
 
   describe "fix_in_reply_to/2" do
-    clear_config([:instance, :federation_incoming_replies_max_depth])
+    setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
 
     setup do
       data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
 
     setup do
       data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
@@ -1632,6 +1398,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert modified_object["inReplyToAtomUri"] == ""
     end
 
       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(
     test "returns modified object when allowed incoming reply", %{data: data} do
       object_with_reply =
         Map.put(
@@ -1648,9 +1415,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
 
 
       assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
 
-      assert modified_object["conversation"] ==
-               "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
-
       assert modified_object["context"] ==
                "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
     end
       assert modified_object["context"] ==
                "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
     end
@@ -1746,9 +1510,12 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
   describe "get_obj_helper/2" do
     test "returns nil when cannot normalize object" do
 
   describe "get_obj_helper/2" do
     test "returns nil when cannot normalize object" do
-      refute Transmogrifier.get_obj_helper("test-obj-id")
+      assert capture_log(fn ->
+               refute Transmogrifier.get_obj_helper("test-obj-id")
+             end) =~ "Unsupported URI scheme"
     end
 
     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")
     test "returns {:ok, %Object{}} for success case" do
       assert {:ok, %Object{}} =
                Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
@@ -1772,11 +1539,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
                  %{
                    "mediaType" => "video/mp4",
                    "url" => [
                  %{
                    "mediaType" => "video/mp4",
                    "url" => [
-                     %{
-                       "href" => "https://peertube.moe/stat-480.mp4",
-                       "mediaType" => "video/mp4",
-                       "type" => "Link"
-                     }
+                     %{"href" => "https://peertube.moe/stat-480.mp4", "mediaType" => "video/mp4"}
                    ]
                  }
                ]
                    ]
                  }
                ]
@@ -1794,23 +1557,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
                  %{
                    "mediaType" => "video/mp4",
                    "url" => [
                  %{
                    "mediaType" => "video/mp4",
                    "url" => [
-                     %{
-                       "href" => "https://pe.er/stat-480.mp4",
-                       "mediaType" => "video/mp4",
-                       "type" => "Link"
-                     }
+                     %{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"}
                    ]
                  },
                  %{
                    ]
                  },
                  %{
-                   "href" => "https://pe.er/stat-480.mp4",
                    "mediaType" => "video/mp4",
                    "mediaType" => "video/mp4",
-                   "mimeType" => "video/mp4",
                    "url" => [
                    "url" => [
-                     %{
-                       "href" => "https://pe.er/stat-480.mp4",
-                       "mediaType" => "video/mp4",
-                       "type" => "Link"
-                     }
+                     %{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"}
                    ]
                  }
                ]
                    ]
                  }
                ]
@@ -1848,4 +1601,60 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
              }
     end
   end
              }
     end
   end
+
+  describe "set_replies/1" do
+    setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
+
+    test "returns unmodified object if activity doesn't have self-replies" do
+      data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+      assert Transmogrifier.set_replies(data) == data
+    end
+
+    test "sets `replies` collection with a limited number of self-replies" do
+      [user, another_user] = insert_list(2, :user)
+
+      {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
+
+      {:ok, %{id: id2} = self_reply1} =
+        CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1})
+
+      {:ok, self_reply2} =
+        CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1})
+
+      # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
+      {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1})
+
+      {:ok, _} =
+        CommonAPI.post(user, %{
+          status: "self-reply to self-reply",
+          in_reply_to_status_id: id2
+        })
+
+      {:ok, _} =
+        CommonAPI.post(another_user, %{
+          status: "another user's reply",
+          in_reply_to_status_id: id1
+        })
+
+      object = Object.normalize(activity)
+      replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
+
+      assert %{"type" => "Collection", "items" => ^replies_uris} =
+               Transmogrifier.set_replies(object.data)["replies"]
+    end
+  end
+
+  test "take_emoji_tags/1" do
+    user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}})
+
+    assert Transmogrifier.take_emoji_tags(user) == [
+             %{
+               "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
+               "id" => "https://example.org/firefox.png",
+               "name" => ":firefox:",
+               "type" => "Emoji",
+               "updated" => "1970-01-01T00:00:00Z"
+             }
+           ]
+  end
 end
 end