diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/emoji_test.exs | 8 | ||||
| -rw-r--r-- | test/fixtures/emoji-reaction.json | 30 | ||||
| -rw-r--r-- | test/fixtures/misskey-like.json | 14 | ||||
| -rw-r--r-- | test/object/containment_test.exs | 10 | ||||
| -rw-r--r-- | test/plugs/rate_limiter_test.exs | 257 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 72 | ||||
| -rw-r--r-- | test/web/activity_pub/transmogrifier_test.exs | 88 | ||||
| -rw-r--r-- | test/web/activity_pub/utils_test.exs | 43 | ||||
| -rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 233 | ||||
| -rw-r--r-- | test/web/common_api/common_api_test.exs | 56 | ||||
| -rw-r--r-- | test/web/node_info_test.exs | 24 | ||||
| -rw-r--r-- | test/web/oauth/oauth_controller_test.exs | 23 | ||||
| -rw-r--r-- | test/web/pleroma_api/controllers/pleroma_api_controller_test.exs | 60 | ||||
| -rw-r--r-- | test/web/static_fe/static_fe_controller_test.exs | 210 | 
14 files changed, 999 insertions, 129 deletions
| diff --git a/test/emoji_test.exs b/test/emoji_test.exs index 1fdbd0fdf..7bdf2b6fa 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -6,6 +6,14 @@ defmodule Pleroma.EmojiTest do    use ExUnit.Case, async: true    alias Pleroma.Emoji +  describe "is_unicode_emoji?/1" do +    test "tells if a string is an unicode emoji" do +      refute Emoji.is_unicode_emoji?("X") +      assert Emoji.is_unicode_emoji?("☂") +      assert Emoji.is_unicode_emoji?("🥺") +    end +  end +    describe "get_all/0" do      setup do        emoji_list = Emoji.get_all() diff --git a/test/fixtures/emoji-reaction.json b/test/fixtures/emoji-reaction.json new file mode 100644 index 000000000..3812e43ad --- /dev/null +++ b/test/fixtures/emoji-reaction.json @@ -0,0 +1,30 @@ +{ +  "type": "EmojiReaction", +  "signature": { +    "type": "RsaSignature2017", +    "signatureValue": "fdxMfQSMwbC6wP6sh6neS/vM5879K67yQkHTbiT5Npr5wAac0y6+o3Ij+41tN3rL6wfuGTosSBTHOtta6R4GCOOhCaCSLMZKypnp1VltCzLDoyrZELnYQIC8gpUXVmIycZbREk22qWUe/w7DAFaKK4UscBlHDzeDVcA0K3Se5Sluqi9/Zh+ldAnEzj/rSEPDjrtvf5wGNf3fHxbKSRKFt90JvKK6hS+vxKUhlRFDf6/SMETw+EhwJSNW4d10yMUakqUWsFv4Acq5LW7l+HpYMvlYY1FZhNde1+uonnCyuQDyvzkff8zwtEJmAXC4RivO/VVLa17SmqheJZfI8oluVg==", +    "creator": "http://mastodon.example.org/users/admin#main-key", +    "created": "2018-02-17T18:57:49Z" +  }, +  "object": "http://localtesting.pleroma.lol/objects/eb92579d-3417-42a8-8652-2492c2d4f454", +  "content": "👌", +  "nickname": "lain", +  "id": "http://mastodon.example.org/users/admin#reactions/2", +  "actor": "http://mastodon.example.org/users/admin", +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "toot": "http://joinmastodon.org/ns#", +      "sensitive": "as:sensitive", +      "ostatus": "http://ostatus.org#", +      "movedTo": "as:movedTo", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "inReplyToAtomUri": "ostatus:inReplyToAtomUri", +      "conversation": "ostatus:conversation", +      "atomUri": "ostatus:atomUri", +      "Hashtag": "as:Hashtag", +      "Emoji": "toot:Emoji" +    } +  ] +} diff --git a/test/fixtures/misskey-like.json b/test/fixtures/misskey-like.json new file mode 100644 index 000000000..84d56f473 --- /dev/null +++ b/test/fixtures/misskey-like.json @@ -0,0 +1,14 @@ +{ +  "@context" : [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    {"Hashtag" : "as:Hashtag"} +  ], +  "_misskey_reaction" : "pudding", +  "actor": "http://mastodon.example.org/users/admin", +  "cc" : ["https://testing.pleroma.lol/users/lain"], +  "id" : "https://misskey.xyz/75149198-2f45-46e4-930a-8b0538297075", +  "nickname" : "lain", +  "object" : "https://testing.pleroma.lol/objects/c331bbf7-2eb9-4801-a709-2a6103492a5a", +  "type" : "Like" +} diff --git a/test/object/containment_test.exs b/test/object/containment_test.exs index 71fe5204c..7636803a6 100644 --- a/test/object/containment_test.exs +++ b/test/object/containment_test.exs @@ -17,6 +17,16 @@ defmodule Pleroma.Object.ContainmentTest do    end    describe "general origin containment" do +    test "works for completely actorless posts" do +      assert :error == +               Containment.contain_origin("https://glaceon.social/users/monorail", %{ +                 "deleted" => "2019-10-30T05:48:50.249606Z", +                 "formerType" => "Note", +                 "id" => "https://glaceon.social/users/monorail/statuses/103049757364029187", +                 "type" => "Tombstone" +               }) +    end +      test "contain_origin_from_id() catches obvious spoofing attempts" do        data = %{          "id" => "http://example.com/~alyssa/activities/1234.json" diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs index 395095079..49f63c424 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/plugs/rate_limiter_test.exs @@ -12,163 +12,196 @@ defmodule Pleroma.Plugs.RateLimiterTest do    # Note: each example must work with separate buckets in order to prevent concurrency issues -  test "init/1" do -    limiter_name = :test_init -    Pleroma.Config.put([:rate_limit, limiter_name], {1, 1}) +  describe "config" do +    test "config is required for plug to work" do +      limiter_name = :test_init +      Pleroma.Config.put([:rate_limit, limiter_name], {1, 1}) -    assert {limiter_name, {1, 1}, []} == RateLimiter.init(limiter_name) -    assert nil == RateLimiter.init(:foo) -  end +      assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} == +               RateLimiter.init(name: limiter_name) -  test "ip/1" do -    assert "127.0.0.1" == RateLimiter.ip(%{remote_ip: {127, 0, 0, 1}}) -  end +      assert nil == RateLimiter.init(name: :foo) +    end -  test "it restricts by opts" do -    limiter_name = :test_opts -    scale = 1000 -    limit = 5 +    test "it restricts based on config values" do +      limiter_name = :test_opts +      scale = 80 +      limit = 5 -    Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) +      Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) -    opts = RateLimiter.init(limiter_name) -    conn = conn(:get, "/") -    bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}" +      opts = RateLimiter.init(name: limiter_name) +      conn = conn(:get, "/") -    conn = RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      for i <- 1..5 do +        conn = RateLimiter.call(conn, opts) +        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +        Process.sleep(10) +      end -    conn = RateLimiter.call(conn, opts) -    assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = RateLimiter.call(conn, opts) +      assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) +      assert conn.halted -    conn = RateLimiter.call(conn, opts) -    assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      Process.sleep(50) -    conn = RateLimiter.call(conn, opts) -    assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = conn(:get, "/") -    conn = RateLimiter.call(conn, opts) -    assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = RateLimiter.call(conn, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) -    conn = RateLimiter.call(conn, opts) +      refute conn.status == Plug.Conn.Status.code(:too_many_requests) +      refute conn.resp_body +      refute conn.halted +    end +  end -    assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) -    assert conn.halted +  describe "options" do +    test "`bucket_name` option overrides default bucket name" do +      limiter_name = :test_bucket_name -    Process.sleep(to_reset) +      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) -    conn = conn(:get, "/") +      base_bucket_name = "#{limiter_name}:group1" +      opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name) -    conn = RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = conn(:get, "/") -    refute conn.status == Plug.Conn.Status.code(:too_many_requests) -    refute conn.resp_body -    refute conn.halted -  end +      RateLimiter.call(conn, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts) +      assert {:err, :not_found} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +    end -  test "`bucket_name` option overrides default bucket name" do -    limiter_name = :test_bucket_name -    scale = 1000 -    limit = 5 +    test "`params` option allows different queries to be tracked independently" do +      limiter_name = :test_params +      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) -    Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) -    base_bucket_name = "#{limiter_name}:group1" -    opts = RateLimiter.init({limiter_name, bucket_name: base_bucket_name}) +      opts = RateLimiter.init(name: limiter_name, params: ["id"]) -    conn = conn(:get, "/") -    default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}" -    customized_bucket_name = "#{base_bucket_name}:#{RateLimiter.ip(conn)}" +      conn = conn(:get, "/?id=1") +      conn = Plug.Conn.fetch_query_params(conn) +      conn_2 = conn(:get, "/?id=2") -    RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(customized_bucket_name, scale, limit) -    assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit) -  end - -  test "`params` option appends specified params' values to bucket name" do -    limiter_name = :test_params -    scale = 1000 -    limit = 5 +      RateLimiter.call(conn, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) +    end -    Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) -    opts = RateLimiter.init({limiter_name, params: ["id"]}) -    id = "1" +    test "it supports combination of options modifying bucket name" do +      limiter_name = :test_options_combo +      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) -    conn = conn(:get, "/?id=#{id}") -    conn = Plug.Conn.fetch_query_params(conn) +      base_bucket_name = "#{limiter_name}:group1" +      opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name, params: ["id"]) +      id = "100" -    default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}" -    parametrized_bucket_name = "#{limiter_name}:#{id}:#{RateLimiter.ip(conn)}" +      conn = conn(:get, "/?id=#{id}") +      conn = Plug.Conn.fetch_query_params(conn) +      conn_2 = conn(:get, "/?id=#{101}") -    RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(parametrized_bucket_name, scale, limit) -    assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit) +      RateLimiter.call(conn, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts) +      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, base_bucket_name, opts) +    end    end -  test "it supports combination of options modifying bucket name" do -    limiter_name = :test_options_combo -    scale = 1000 -    limit = 5 +  describe "unauthenticated users" do +    test "are restricted based on remote IP" do +      limiter_name = :test_unauthenticated +      Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}]) + +      opts = RateLimiter.init(name: limiter_name) -    Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) -    base_bucket_name = "#{limiter_name}:group1" -    opts = RateLimiter.init({limiter_name, bucket_name: base_bucket_name, params: ["id"]}) -    id = "100" +      conn = %{conn(:get, "/") | remote_ip: {127, 0, 0, 2}} +      conn_2 = %{conn(:get, "/") | remote_ip: {127, 0, 0, 3}} -    conn = conn(:get, "/?id=#{id}") -    conn = Plug.Conn.fetch_query_params(conn) +      for i <- 1..5 do +        conn = RateLimiter.call(conn, opts) +        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +        refute conn.halted +      end -    default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}" -    parametrized_bucket_name = "#{base_bucket_name}:#{id}:#{RateLimiter.ip(conn)}" +      conn = RateLimiter.call(conn, opts) -    RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(parametrized_bucket_name, scale, limit) -    assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit) +      assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) +      assert conn.halted + +      conn_2 = RateLimiter.call(conn_2, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) + +      refute conn_2.status == Plug.Conn.Status.code(:too_many_requests) +      refute conn_2.resp_body +      refute conn_2.halted +    end    end -  test "optional limits for authenticated users" do -    limiter_name = :test_authenticated -    Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) +  describe "authenticated users" do +    setup do +      Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) + +      :ok +    end + +    test "can have limits seperate from unauthenticated connections" do +      limiter_name = :test_authenticated + +      scale = 1000 +      limit = 5 +      Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}]) + +      opts = RateLimiter.init(name: limiter_name) -    scale = 1000 -    limit = 5 -    Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}]) +      user = insert(:user) +      conn = conn(:get, "/") |> assign(:user, user) -    opts = RateLimiter.init(limiter_name) +      for i <- 1..5 do +        conn = RateLimiter.call(conn, opts) +        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +        refute conn.halted +      end -    user = insert(:user) -    conn = conn(:get, "/") |> assign(:user, user) -    bucket_name = "#{limiter_name}:#{user.id}" +      conn = RateLimiter.call(conn, opts) -    conn = RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) +      assert conn.halted -    conn = RateLimiter.call(conn, opts) -    assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      Process.sleep(1550) -    conn = RateLimiter.call(conn, opts) -    assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = conn(:get, "/") |> assign(:user, user) +      conn = RateLimiter.call(conn, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) -    conn = RateLimiter.call(conn, opts) -    assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      refute conn.status == Plug.Conn.Status.code(:too_many_requests) +      refute conn.resp_body +      refute conn.halted +    end -    conn = RateLimiter.call(conn, opts) -    assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +    test "diffrerent users are counted independently" do +      limiter_name = :test_authenticated +      Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}]) -    conn = RateLimiter.call(conn, opts) +      opts = RateLimiter.init(name: limiter_name) -    assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) -    assert conn.halted +      user = insert(:user) +      conn = conn(:get, "/") |> assign(:user, user) -    Process.sleep(to_reset) +      user_2 = insert(:user) +      conn_2 = conn(:get, "/") |> assign(:user, user_2) -    conn = conn(:get, "/") |> assign(:user, user) +      for i <- 1..5 do +        conn = RateLimiter.call(conn, opts) +        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) +      end -    conn = RateLimiter.call(conn, opts) -    assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) +      conn = RateLimiter.call(conn, opts) +      assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) +      assert conn.halted -    refute conn.status == Plug.Conn.Status.code(:too_many_requests) -    refute conn.resp_body -    refute conn.halted +      conn_2 = RateLimiter.call(conn_2, opts) +      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) +      refute conn_2.status == Plug.Conn.Status.code(:too_many_requests) +      refute conn_2.resp_body +      refute conn_2.halted +    end    end  end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 0d0281faf..d437ad456 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -812,6 +812,78 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end +  describe "react to an object" do +    test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do +      Pleroma.Config.put([:instance, :federating], true) +      user = insert(:user) +      reactor = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) +      assert object = Object.normalize(activity) + +      {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥") + +      assert called(Pleroma.Web.Federator.publish(reaction_activity)) +    end + +    test "adds an emoji reaction activity to the db" do +      user = insert(:user) +      reactor = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) +      assert object = Object.normalize(activity) + +      {:ok, reaction_activity, object} = ActivityPub.react_with_emoji(reactor, object, "🔥") + +      assert reaction_activity + +      assert reaction_activity.data["actor"] == reactor.ap_id +      assert reaction_activity.data["type"] == "EmojiReaction" +      assert reaction_activity.data["content"] == "🔥" +      assert reaction_activity.data["object"] == object.data["id"] +      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] +    end +  end + +  describe "unreacting to an object" do +    test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do +      Pleroma.Config.put([:instance, :federating], true) +      user = insert(:user) +      reactor = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) +      assert object = Object.normalize(activity) + +      {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥") + +      assert called(Pleroma.Web.Federator.publish(reaction_activity)) + +      {:ok, unreaction_activity, _object} = +        ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"]) + +      assert called(Pleroma.Web.Federator.publish(unreaction_activity)) +    end + +    test "adds an undo activity to the db" do +      user = insert(:user) +      reactor = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) +      assert object = Object.normalize(activity) + +      {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥") + +      {:ok, unreaction_activity, _object} = +        ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"]) + +      assert unreaction_activity.actor == reactor.ap_id +      assert unreaction_activity.data["object"] == reaction_activity.data["id"] + +      object = Object.get_by_ap_id(object.data["id"]) +      assert object.data["reaction_count"] == 0 +      assert object.data["reactions"] == %{} +    end +  end +    describe "like an object" do      test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do        Pleroma.Config.put([:instance, :federating], true) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 4645eb39d..0bdd514e9 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -339,6 +339,80 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"] == activity.data["object"]      end +    test "it works for incoming misskey likes, turning them into EmojiReactions" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"}) + +      data = +        File.read!("test/fixtures/misskey-like.json") +        |> Poison.decode!() +        |> Map.put("object", activity.data["object"]) + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +      assert data["actor"] == data["actor"] +      assert data["type"] == "EmojiReaction" +      assert data["id"] == data["id"] +      assert data["object"] == activity.data["object"] +      assert data["content"] == "🍮" +    end + +    test "it works for incoming misskey likes that contain unicode emojis, turning them into EmojiReactions" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"}) + +      data = +        File.read!("test/fixtures/misskey-like.json") +        |> Poison.decode!() +        |> Map.put("object", activity.data["object"]) +        |> Map.put("_misskey_reaction", "⭐") + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +      assert data["actor"] == data["actor"] +      assert data["type"] == "EmojiReaction" +      assert data["id"] == data["id"] +      assert data["object"] == activity.data["object"] +      assert data["content"] == "⭐" +    end + +    test "it works for incoming emoji reactions" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"}) + +      data = +        File.read!("test/fixtures/emoji-reaction.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"] == "EmojiReaction" +      assert data["id"] == "http://mastodon.example.org/users/admin#reactions/2" +      assert data["object"] == activity.data["object"] +      assert data["content"] == "👌" +    end + +    test "it works for incoming emoji reaction undos" do +      user = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"}) +      {:ok, reaction_activity, _object} = CommonAPI.react_with_emoji(activity.id, user, "👌") + +      data = +        File.read!("test/fixtures/mastodon-undo-like.json") +        |> Poison.decode!() +        |> Map.put("object", reaction_activity.data["id"]) +        |> Map.put("actor", user.ap_id) + +      {:ok, activity} = Transmogrifier.handle_incoming(data) + +      assert activity.actor == user.ap_id +      assert activity.data["id"] == data["id"] +      assert activity.data["type"] == "Undo" +    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"}) @@ -553,6 +627,20 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        refute Map.has_key?(object.data, "likes")      end +    test "it strips internal reactions" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) +      {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "📢") + +      %{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") + +      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 incoming update activities" do        data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index 586eb1d2f..1feb076ba 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -636,4 +636,47 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        assert updated_object.data["announcement_count"] == 1      end    end + +  describe "get_reports_grouped_by_status/1" do +    setup do +      [reporter, target_user] = insert_pair(:user) +      first_status = insert(:note_activity, user: target_user) +      second_status = insert(:note_activity, user: target_user) + +      CommonAPI.report(reporter, %{ +        "account_id" => target_user.id, +        "comment" => "I feel offended", +        "status_ids" => [first_status.id] +      }) + +      CommonAPI.report(reporter, %{ +        "account_id" => target_user.id, +        "comment" => "I feel offended2", +        "status_ids" => [second_status.id] +      }) + +      data = [%{activity: first_status.data["id"]}, %{activity: second_status.data["id"]}] + +      {:ok, +       %{ +         first_status: first_status, +         second_status: second_status, +         data: data +       }} +    end + +    test "works for deprecated reports format", %{ +      first_status: first_status, +      second_status: second_status, +      data: data +    } do +      groups = Utils.get_reports_grouped_by_status(data).groups + +      first_group = Enum.find(groups, &(&1.status.id == first_status.data["id"])) +      second_group = Enum.find(groups, &(&1.status.id == second_status.data["id"])) + +      assert first_group.status.id == first_status.data["id"] +      assert second_group.status.id == second_status.data["id"] +    end +  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 5958e6462..471477f2c 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1312,7 +1312,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "PUT /api/pleroma/admin/reports/:id" do +  describe "PATCH /api/pleroma/admin/reports" do      setup %{conn: conn} do        admin = insert(:user, is_admin: true)        [reporter, target_user] = insert_pair(:user) @@ -1325,16 +1325,32 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do            "status_ids" => [activity.id]          }) -      %{conn: assign(conn, :user, admin), id: report_id, admin: admin} +      {:ok, %{id: second_report_id}} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "comment" => "I feel very offended", +          "status_ids" => [activity.id] +        }) + +      %{ +        conn: assign(conn, :user, admin), +        id: report_id, +        admin: admin, +        second_report_id: second_report_id +      }      end      test "mark report as resolved", %{conn: conn, id: id, admin: admin} do -      response = -        conn -        |> put("/api/pleroma/admin/reports/#{id}", %{"state" => "resolved"}) -        |> json_response(:ok) +      conn +      |> patch("/api/pleroma/admin/reports", %{ +        "reports" => [ +          %{"state" => "resolved", "id" => id} +        ] +      }) +      |> json_response(:no_content) -      assert response["state"] == "resolved" +      activity = Activity.get_by_id(id) +      assert activity.data["state"] == "resolved"        log_entry = Repo.one(ModerationLog) @@ -1343,12 +1359,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end      test "closes report", %{conn: conn, id: id, admin: admin} do -      response = -        conn -        |> put("/api/pleroma/admin/reports/#{id}", %{"state" => "closed"}) -        |> json_response(:ok) +      conn +      |> patch("/api/pleroma/admin/reports", %{ +        "reports" => [ +          %{"state" => "closed", "id" => id} +        ] +      }) +      |> json_response(:no_content) -      assert response["state"] == "closed" +      activity = Activity.get_by_id(id) +      assert activity.data["state"] == "closed"        log_entry = Repo.one(ModerationLog) @@ -1359,17 +1379,54 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      test "returns 400 when state is unknown", %{conn: conn, id: id} do        conn =          conn -        |> put("/api/pleroma/admin/reports/#{id}", %{"state" => "test"}) +        |> patch("/api/pleroma/admin/reports", %{ +          "reports" => [ +            %{"state" => "test", "id" => id} +          ] +        }) -      assert json_response(conn, :bad_request) == "Unsupported state" +      assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"      end      test "returns 404 when report is not exist", %{conn: conn} do        conn =          conn -        |> put("/api/pleroma/admin/reports/test", %{"state" => "closed"}) +        |> patch("/api/pleroma/admin/reports", %{ +          "reports" => [ +            %{"state" => "closed", "id" => "test"} +          ] +        }) -      assert json_response(conn, :not_found) == "Not found" +      assert hd(json_response(conn, :bad_request))["error"] == "not_found" +    end + +    test "updates state of multiple reports", %{ +      conn: conn, +      id: id, +      admin: admin, +      second_report_id: second_report_id +    } do +      conn +      |> patch("/api/pleroma/admin/reports", %{ +        "reports" => [ +          %{"state" => "resolved", "id" => id}, +          %{"state" => "closed", "id" => second_report_id} +        ] +      }) +      |> json_response(:no_content) + +      activity = Activity.get_by_id(id) +      second_activity = Activity.get_by_id(second_report_id) +      assert activity.data["state"] == "resolved" +      assert second_activity.data["state"] == "closed" + +      [first_log_entry, second_log_entry] = Repo.all(ModerationLog) + +      assert ModerationLog.get_log_entry_message(first_log_entry) == +               "@#{admin.nickname} updated report ##{id} with 'resolved' state" + +      assert ModerationLog.get_log_entry_message(second_log_entry) == +               "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"      end    end @@ -1492,7 +1549,145 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  # +  describe "GET /api/pleroma/admin/grouped_reports" do +    setup %{conn: conn} do +      admin = insert(:user, is_admin: true) +      [reporter, target_user] = insert_pair(:user) + +      date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!() +      date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!() +      date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!() + +      first_status = +        insert(:note_activity, user: target_user, data_attrs: %{"published" => date1}) + +      second_status = +        insert(:note_activity, user: target_user, data_attrs: %{"published" => date2}) + +      third_status = +        insert(:note_activity, user: target_user, data_attrs: %{"published" => date3}) + +      {:ok, first_report} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "status_ids" => [first_status.id, second_status.id, third_status.id] +        }) + +      {:ok, second_report} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "status_ids" => [first_status.id, second_status.id] +        }) + +      {:ok, third_report} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "status_ids" => [first_status.id] +        }) + +      %{ +        conn: assign(conn, :user, admin), +        first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]), +        second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]), +        third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]), +        first_status_reports: [first_report, second_report, third_report], +        second_status_reports: [first_report, second_report], +        third_status_reports: [first_report], +        target_user: target_user, +        reporter: reporter +      } +    end + +    test "returns reports grouped by status", %{ +      conn: conn, +      first_status: first_status, +      second_status: second_status, +      third_status: third_status, +      first_status_reports: first_status_reports, +      second_status_reports: second_status_reports, +      third_status_reports: third_status_reports, +      target_user: target_user, +      reporter: reporter +    } do +      response = +        conn +        |> get("/api/pleroma/admin/grouped_reports") +        |> json_response(:ok) + +      assert length(response["reports"]) == 3 + +      first_group = +        Enum.find(response["reports"], &(&1["status"]["id"] == first_status.data["id"])) + +      second_group = +        Enum.find(response["reports"], &(&1["status"]["id"] == second_status.data["id"])) + +      third_group = +        Enum.find(response["reports"], &(&1["status"]["id"] == third_status.data["id"])) + +      assert length(first_group["reports"]) == 3 +      assert length(second_group["reports"]) == 2 +      assert length(third_group["reports"]) == 1 + +      assert first_group["date"] == +               Enum.max_by(first_status_reports, fn act -> +                 NaiveDateTime.from_iso8601!(act.data["published"]) +               end).data["published"] + +      assert first_group["status"] == %{ +               "id" => first_status.data["id"], +               "content" => first_status.object.data["content"], +               "published" => first_status.object.data["published"] +             } + +      assert first_group["account"]["id"] == target_user.id + +      assert length(first_group["actors"]) == 1 +      assert hd(first_group["actors"])["id"] == reporter.id + +      assert Enum.map(first_group["reports"], & &1["id"]) -- +               Enum.map(first_status_reports, & &1.id) == [] + +      assert second_group["date"] == +               Enum.max_by(second_status_reports, fn act -> +                 NaiveDateTime.from_iso8601!(act.data["published"]) +               end).data["published"] + +      assert second_group["status"] == %{ +               "id" => second_status.data["id"], +               "content" => second_status.object.data["content"], +               "published" => second_status.object.data["published"] +             } + +      assert second_group["account"]["id"] == target_user.id + +      assert length(second_group["actors"]) == 1 +      assert hd(second_group["actors"])["id"] == reporter.id + +      assert Enum.map(second_group["reports"], & &1["id"]) -- +               Enum.map(second_status_reports, & &1.id) == [] + +      assert third_group["date"] == +               Enum.max_by(third_status_reports, fn act -> +                 NaiveDateTime.from_iso8601!(act.data["published"]) +               end).data["published"] + +      assert third_group["status"] == %{ +               "id" => third_status.data["id"], +               "content" => third_status.object.data["content"], +               "published" => third_status.object.data["published"] +             } + +      assert third_group["account"]["id"] == target_user.id + +      assert length(third_group["actors"]) == 1 +      assert hd(third_group["actors"])["id"] == reporter.id + +      assert Enum.map(third_group["reports"], & &1["id"]) -- +               Enum.map(third_status_reports, & &1.id) == [] +    end +  end +    describe "POST /api/pleroma/admin/reports/:id/respond" do      setup %{conn: conn} do        admin = insert(:user, is_admin: true) @@ -2269,6 +2464,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        Pleroma.Config.put([:instance, :dynamic_configuration], true)      end +    clear_config([:feed, :post_title]) do +      Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"}) +    end +      test "transfer settings to DB and to file", %{conn: conn, admin: admin} do        assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []        conn = get(conn, "/api/pleroma/admin/config/migrate_to_db") diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 8e6fbd7f0..138488d44 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -227,6 +227,33 @@ defmodule Pleroma.Web.CommonAPITest do    end    describe "reactions" do +    test "reacting to a status with an emoji" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) + +      {:ok, reaction, _} = CommonAPI.react_with_emoji(activity.id, user, "👍") + +      assert reaction.data["actor"] == user.ap_id +      assert reaction.data["content"] == "👍" + +      # TODO: test error case. +    end + +    test "unreacting to a status with an emoji" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) +      {:ok, reaction, _} = CommonAPI.react_with_emoji(activity.id, user, "👍") + +      {:ok, unreaction, _} = CommonAPI.unreact_with_emoji(activity.id, user, "👍") + +      assert unreaction.data["type"] == "Undo" +      assert unreaction.data["object"] == reaction.data["id"] +    end +      test "repeating a status" do        user = insert(:user)        other_user = insert(:user) @@ -441,6 +468,35 @@ defmodule Pleroma.Web.CommonAPITest do        assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}      end + +    test "updates state of multiple reports" do +      [reporter, target_user] = insert_pair(:user) +      activity = insert(:note_activity, user: target_user) + +      {:ok, %Activity{id: first_report_id}} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "comment" => "I feel offended", +          "status_ids" => [activity.id] +        }) + +      {:ok, %Activity{id: second_report_id}} = +        CommonAPI.report(reporter, %{ +          "account_id" => target_user.id, +          "comment" => "I feel very offended!", +          "status_ids" => [activity.id] +        }) + +      {:ok, report_ids} = +        CommonAPI.update_report_state([first_report_id, second_report_id], "resolved") + +      first_report = Activity.get_by_id(first_report_id) +      second_report = Activity.get_by_id(second_report_id) + +      assert report_ids -- [first_report_id, second_report_id] == [] +      assert first_report.data["state"] == "resolved" +      assert second_report.data["state"] == "resolved" +    end    end    describe "reblog muting" do diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index a3281b25b..6cc876602 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -84,6 +84,30 @@ defmodule Pleroma.Web.NodeInfoTest do      Pleroma.Config.put([:instance, :safe_dm_mentions], option)    end +  test "it shows if federation is enabled/disabled", %{conn: conn} do +    original = Pleroma.Config.get([:instance, :federating]) + +    Pleroma.Config.put([:instance, :federating], true) + +    response = +      conn +      |> get("/nodeinfo/2.1.json") +      |> json_response(:ok) + +    assert response["metadata"]["federation"]["enabled"] == true + +    Pleroma.Config.put([:instance, :federating], false) + +    response = +      conn +      |> get("/nodeinfo/2.1.json") +      |> json_response(:ok) + +    assert response["metadata"]["federation"]["enabled"] == false + +    Pleroma.Config.put([:instance, :federating], original) +  end +    test "it shows MRF transparency data if enabled", %{conn: conn} do      config = Pleroma.Config.get([:instance, :rewrite_policy])      Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index ad8d79083..beb995cd8 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -469,6 +469,29 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        assert html_response(conn, 200) =~ ~s(type="submit")      end +    test "renders authentication page if user is already authenticated but user request with another client", +         %{ +           app: app, +           conn: conn +         } do +      token = insert(:oauth_token, app_id: app.id) + +      conn = +        conn +        |> put_session(:oauth_token, token.token) +        |> get( +          "/oauth/authorize", +          %{ +            "response_type" => "code", +            "client_id" => "another_client_id", +            "redirect_uri" => OAuthController.default_redirect_uri(app), +            "scope" => "read" +          } +        ) + +      assert html_response(conn, 200) =~ ~s(type="submit") +    end +      test "with existing authentication and non-OOB `redirect_uri`, redirects to app with `token` and `state` params",           %{             app: app, 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 0c83edb56..b1b59beed 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -7,12 +7,72 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do    alias Pleroma.Conversation.Participation    alias Pleroma.Notification +  alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  test "POST /api/v1/pleroma/statuses/:id/react_with_emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) + +    result = +      conn +      |> assign(:user, other_user) +      |> post("/api/v1/pleroma/statuses/#{activity.id}/react_with_emoji", %{"emoji" => "☕"}) + +    assert %{"id" => id} = json_response(result, 200) +    assert to_string(activity.id) == id +  end + +  test "POST /api/v1/pleroma/statuses/:id/unreact_with_emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) +    {:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    result = +      conn +      |> assign(:user, other_user) +      |> post("/api/v1/pleroma/statuses/#{activity.id}/unreact_with_emoji", %{"emoji" => "☕"}) + +    assert %{"id" => id} = json_response(result, 200) +    assert to_string(activity.id) == id + +    object = Object.normalize(activity) + +    assert object.data["reaction_count"] == 0 +  end + +  test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") +      |> json_response(200) + +    assert result == %{} + +    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") +      |> json_response(200) + +    [represented_user] = result["🎅"] +    assert represented_user["id"] == other_user.id +  end +    test "/api/v1/pleroma/conversations/:id", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/web/static_fe/static_fe_controller_test.exs new file mode 100644 index 000000000..2ce8f9fa3 --- /dev/null +++ b/test/web/static_fe/static_fe_controller_test.exs @@ -0,0 +1,210 @@ +defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do +  use Pleroma.Web.ConnCase +  alias Pleroma.Activity +  alias Pleroma.Web.ActivityPub.Transmogrifier +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  clear_config_all([:static_fe, :enabled]) do +    Pleroma.Config.put([:static_fe, :enabled], true) +  end + +  describe "user profile page" do +    test "just the profile as HTML", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/users/#{user.nickname}") + +      assert html_response(conn, 200) =~ user.nickname +    end + +    test "renders json unless there's an html accept header", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/#{user.nickname}") + +      assert json_response(conn, 200) +    end + +    test "404 when user not found", %{conn: conn} do +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/users/limpopo") + +      assert html_response(conn, 404) =~ "not found" +    end + +    test "profile does not include private messages", %{conn: conn} do +      user = insert(:user) +      CommonAPI.post(user, %{"status" => "public"}) +      CommonAPI.post(user, %{"status" => "private", "visibility" => "private"}) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/users/#{user.nickname}") + +      html = html_response(conn, 200) + +      assert html =~ ">public<" +      refute html =~ ">private<" +    end + +    test "pagination", %{conn: conn} do +      user = insert(:user) +      Enum.map(1..30, fn i -> CommonAPI.post(user, %{"status" => "test#{i}"}) end) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/users/#{user.nickname}") + +      html = html_response(conn, 200) + +      assert html =~ ">test30<" +      assert html =~ ">test11<" +      refute html =~ ">test10<" +      refute html =~ ">test1<" +    end + +    test "pagination, page 2", %{conn: conn} do +      user = insert(:user) +      activities = Enum.map(1..30, fn i -> CommonAPI.post(user, %{"status" => "test#{i}"}) end) +      {:ok, a11} = Enum.at(activities, 11) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/users/#{user.nickname}?max_id=#{a11.id}") + +      html = html_response(conn, 200) + +      assert html =~ ">test1<" +      assert html =~ ">test10<" +      refute html =~ ">test20<" +      refute html =~ ">test29<" +    end +  end + +  describe "notice rendering" do +    test "single notice page", %{conn: conn} do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "testing a thing!"}) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/notice/#{activity.id}") + +      html = html_response(conn, 200) +      assert html =~ "<header>" +      assert html =~ user.nickname +      assert html =~ "testing a thing!" +    end + +    test "shows the whole thread", %{conn: conn} do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "space: the final frontier"}) + +      CommonAPI.post(user, %{ +        "status" => "these are the voyages or something", +        "in_reply_to_status_id" => activity.id +      }) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/notice/#{activity.id}") + +      html = html_response(conn, 200) +      assert html =~ "the final frontier" +      assert html =~ "voyages" +    end + +    test "redirect by AP object ID", %{conn: conn} do +      user = insert(:user) + +      {:ok, %Activity{data: %{"object" => object_url}}} = +        CommonAPI.post(user, %{"status" => "beam me up"}) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get(URI.parse(object_url).path) + +      assert html_response(conn, 302) =~ "redirected" +    end + +    test "redirect by activity ID", %{conn: conn} do +      user = insert(:user) + +      {:ok, %Activity{data: %{"id" => id}}} = +        CommonAPI.post(user, %{"status" => "I'm a doctor, not a devops!"}) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get(URI.parse(id).path) + +      assert html_response(conn, 302) =~ "redirected" +    end + +    test "404 when notice not found", %{conn: conn} do +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/notice/88c9c317") + +      assert html_response(conn, 404) =~ "not found" +    end + +    test "404 for private status", %{conn: conn} do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{"status" => "don't show me!", "visibility" => "private"}) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/notice/#{activity.id}") + +      assert html_response(conn, 404) =~ "not found" +    end + +    test "302 for remote cached status", %{conn: conn} do +      user = insert(:user) + +      message = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "to" => user.follower_address, +        "cc" => "https://www.w3.org/ns/activitystreams#Public", +        "type" => "Create", +        "object" => %{ +          "content" => "blah blah blah", +          "type" => "Note", +          "attributedTo" => user.ap_id, +          "inReplyTo" => nil +        }, +        "actor" => user.ap_id +      } + +      assert {:ok, activity} = Transmogrifier.handle_incoming(message) + +      conn = +        conn +        |> put_req_header("accept", "text/html") +        |> get("/notice/#{activity.id}") + +      assert html_response(conn, 302) =~ "redirected" +    end +  end +end | 
