aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/stats_test.exs (renamed from test/stat_test.exs)12
-rw-r--r--test/support/api_spec_helpers.ex57
-rw-r--r--test/support/conn_case.ex36
-rw-r--r--test/web/activity_pub/activity_pub_test.exs570
-rw-r--r--test/web/activity_pub/utils_test.exs5
-rw-r--r--test/web/api_spec/app_operation_test.exs45
-rw-r--r--test/web/api_spec/schema_examples_test.exs43
-rw-r--r--test/web/common_api/common_api_test.exs72
-rw-r--r--test/web/common_api/common_api_utils_test.exs20
-rw-r--r--test/web/mastodon_api/controllers/app_controller_test.exs4
-rw-r--r--test/web/mastodon_api/controllers/custom_emoji_controller_test.exs17
-rw-r--r--test/web/mastodon_api/controllers/domain_block_controller_test.exs28
-rw-r--r--test/web/mastodon_api/controllers/status_controller_test.exs11
13 files changed, 739 insertions, 181 deletions
diff --git a/test/stat_test.exs b/test/stats_test.exs
index bccc1c8d0..c1aeb2c7f 100644
--- a/test/stat_test.exs
+++ b/test/stats_test.exs
@@ -2,11 +2,21 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.StateTest do
+defmodule Pleroma.StatsTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.CommonAPI
+ describe "user count" do
+ test "it ignores internal users" do
+ _user = insert(:user, local: true)
+ _internal = insert(:user, local: true, nickname: nil)
+ _internal = Pleroma.Web.ActivityPub.Relay.get_actor()
+
+ assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data())
+ end
+ end
+
describe "status visibility count" do
test "on new status" do
user = insert(:user)
diff --git a/test/support/api_spec_helpers.ex b/test/support/api_spec_helpers.ex
new file mode 100644
index 000000000..80c69c788
--- /dev/null
+++ b/test/support/api_spec_helpers.ex
@@ -0,0 +1,57 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Tests.ApiSpecHelpers do
+ @moduledoc """
+ OpenAPI spec test helpers
+ """
+
+ import ExUnit.Assertions
+
+ alias OpenApiSpex.Cast.Error
+ alias OpenApiSpex.Reference
+ alias OpenApiSpex.Schema
+
+ def assert_schema(value, schema) do
+ api_spec = Pleroma.Web.ApiSpec.spec()
+
+ case OpenApiSpex.cast_value(value, schema, api_spec) do
+ {:ok, data} ->
+ data
+
+ {:error, errors} ->
+ errors =
+ Enum.map(errors, fn error ->
+ message = Error.message(error)
+ path = Error.path_to_string(error)
+ "#{message} at #{path}"
+ end)
+
+ flunk(
+ "Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{
+ inspect(value)
+ }"
+ )
+ end
+ end
+
+ def resolve_schema(%Schema{} = schema), do: schema
+
+ def resolve_schema(%Reference{} = ref) do
+ schemas = Pleroma.Web.ApiSpec.spec().components.schemas
+ Reference.resolve_schema(ref, schemas)
+ end
+
+ def api_operations do
+ paths = Pleroma.Web.ApiSpec.spec().paths
+
+ Enum.flat_map(paths, fn {_, path_item} ->
+ path_item
+ |> Map.take([:delete, :get, :head, :options, :patch, :post, :put, :trace])
+ |> Map.values()
+ |> Enum.reject(&is_nil/1)
+ |> Enum.uniq()
+ end)
+ end
+end
diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex
index 36ce372c2..8099461cc 100644
--- a/test/support/conn_case.ex
+++ b/test/support/conn_case.ex
@@ -56,6 +56,42 @@ defmodule Pleroma.Web.ConnCase do
[conn: conn]
end
+ defp json_response_and_validate_schema(conn, status \\ nil) do
+ content_type =
+ conn
+ |> Plug.Conn.get_resp_header("content-type")
+ |> List.first()
+ |> String.split(";")
+ |> List.first()
+
+ status = status || conn.status
+
+ %{private: %{open_api_spex: %{operation_id: op_id, operation_lookup: lookup, spec: spec}}} =
+ conn
+
+ schema = lookup[op_id].responses[status].content[content_type].schema
+ json = json_response(conn, status)
+
+ case OpenApiSpex.cast_value(json, schema, spec) do
+ {:ok, _data} ->
+ json
+
+ {:error, errors} ->
+ errors =
+ Enum.map(errors, fn error ->
+ message = OpenApiSpex.Cast.Error.message(error)
+ path = OpenApiSpex.Cast.Error.path_to_string(error)
+ "#{message} at #{path}"
+ end)
+
+ flunk(
+ "Response does not conform to schema of #{op_id} operation: #{
+ Enum.join(errors, "\n")
+ }\n#{inspect(json)}"
+ )
+ end
+ end
+
defp ensure_federating_or_authenticated(conn, url, user) do
initial_setting = Config.get([:instance, :federating])
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 6410df49b..edd7dfb22 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -994,72 +994,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
- describe "like an object" do
- test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
- Config.put([:instance, :federating], true)
- note_activity = insert(:note_activity)
- assert object_activity = Object.normalize(note_activity)
-
- user = insert(:user)
-
- {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
- assert called(Federator.publish(like_activity))
- end
-
- test "returns exist activity if object already liked" do
- note_activity = insert(:note_activity)
- assert object_activity = Object.normalize(note_activity)
-
- user = insert(:user)
-
- {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
-
- {:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
- assert like_activity == like_activity_exist
- end
-
- test "reverts like activity on error" do
- note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
- user = insert(:user)
-
- with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
- assert {:error, :reverted} = ActivityPub.like(user, object)
- end
-
- assert Repo.aggregate(Activity, :count, :id) == 1
- assert Repo.get(Object, object.id) == object
- end
-
- test "adds a like activity to the db" do
- note_activity = insert(:note_activity)
- assert object = Object.normalize(note_activity)
-
- user = insert(:user)
- user_two = insert(:user)
-
- {:ok, like_activity, object} = ActivityPub.like(user, object)
-
- assert like_activity.data["actor"] == user.ap_id
- assert like_activity.data["type"] == "Like"
- assert like_activity.data["object"] == object.data["id"]
- assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
- assert like_activity.data["context"] == object.data["context"]
- assert object.data["like_count"] == 1
- assert object.data["likes"] == [user.ap_id]
-
- # Just return the original activity if the user already liked it.
- {:ok, same_like_activity, object} = ActivityPub.like(user, object)
-
- assert like_activity == same_like_activity
- assert object.data["likes"] == [user.ap_id]
- assert object.data["like_count"] == 1
-
- {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
- assert object.data["like_count"] == 2
- end
- end
-
describe "unliking" do
test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
Config.put([:instance, :federating], true)
@@ -1071,7 +1005,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, object} = ActivityPub.unlike(user, object)
refute called(Federator.publish())
- {:ok, _like_activity, object} = ActivityPub.like(user, object)
+ {:ok, _like_activity} = CommonAPI.favorite(user, note_activity.id)
+ object = Object.get_by_id(object.id)
assert object.data["like_count"] == 1
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
@@ -1082,10 +1017,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "reverts unliking on error" do
note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
user = insert(:user)
- {:ok, like_activity, object} = ActivityPub.like(user, object)
+ {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
+ object = Object.normalize(note_activity)
assert object.data["like_count"] == 1
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
@@ -1106,7 +1041,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, object} = ActivityPub.unlike(user, object)
assert object.data["like_count"] == 0
- {:ok, like_activity, object} = ActivityPub.like(user, object)
+ {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
+
+ object = Object.get_by_id(object.id)
assert object.data["like_count"] == 1
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
@@ -1973,4 +1910,497 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
ActivityPub.move(old_user, new_user)
end
end
+
+ test "doesn't retrieve replies activities with exclude_replies" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"})
+
+ {:ok, _reply} =
+ CommonAPI.post(user, %{"status" => "yeah", "in_reply_to_status_id" => activity.id})
+
+ [result] = ActivityPub.fetch_public_activities(%{"exclude_replies" => "true"})
+
+ assert result.id == activity.id
+
+ assert length(ActivityPub.fetch_public_activities()) == 2
+ end
+
+ describe "replies filtering with public messages" do
+ setup :public_messages
+
+ test "public timeline", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 16
+ end
+
+ test "public timeline with reply_visibility `following`", %{
+ users: %{u1: user},
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4,
+ activities: activities
+ } do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 14
+
+ visible_ids =
+ Map.values(u1) ++ Map.values(u2) ++ Map.values(u4) ++ Map.values(activities) ++ [u3[:r1]]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "public timeline with reply_visibility `self`", %{
+ users: %{u1: user},
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4,
+ activities: activities
+ } do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 10
+ visible_ids = Map.values(u1) ++ [u2[:r1], u3[:r1], u4[:r1]] ++ Map.values(activities)
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 13
+
+ visible_ids =
+ Map.values(u1) ++
+ Map.values(u3) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u2[:r3],
+ u4[:r1],
+ u4[:r2]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline with reply_visibility `following`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 11
+
+ visible_ids =
+ Map.values(u1) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u2[:r3],
+ u3[:r1],
+ u4[:r1],
+ u4[:r2]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline with reply_visibility `self`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 9
+
+ visible_ids =
+ Map.values(u1) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u3[:r1],
+ u4[:r1]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+ end
+
+ describe "replies filtering with private messages" do
+ setup :private_messages
+
+ test "public timeline", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "home timeline", %{users: %{u1: user}} do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 12
+ end
+
+ test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 12
+ end
+
+ test "home timeline with default reply_visibility `self`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 10
+
+ visible_ids =
+ Map.values(u1) ++ Map.values(u4) ++ [u2[:r1], u3[:r1]] ++ Map.values(activities)
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+ end
+
+ defp public_messages(_) do
+ [u1, u2, u3, u4] = insert_list(4, :user)
+ {:ok, u1} = User.follow(u1, u2)
+ {:ok, u2} = User.follow(u2, u1)
+ {:ok, u1} = User.follow(u1, u4)
+ {:ok, u4} = User.follow(u4, u1)
+
+ {:ok, u2} = User.follow(u2, u3)
+ {:ok, u3} = User.follow(u3, u2)
+
+ {:ok, a1} = CommonAPI.post(u1, %{"status" => "Status"})
+
+ {:ok, r1_1} =
+ CommonAPI.post(u2, %{
+ "status" => "@#{u1.nickname} reply from u2 to u1",
+ "in_reply_to_status_id" => a1.id
+ })
+
+ {:ok, r1_2} =
+ CommonAPI.post(u3, %{
+ "status" => "@#{u1.nickname} reply from u3 to u1",
+ "in_reply_to_status_id" => a1.id
+ })
+
+ {:ok, r1_3} =
+ CommonAPI.post(u4, %{
+ "status" => "@#{u1.nickname} reply from u4 to u1",
+ "in_reply_to_status_id" => a1.id
+ })
+
+ {:ok, a2} = CommonAPI.post(u2, %{"status" => "Status"})
+
+ {:ok, r2_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u2.nickname} reply from u1 to u2",
+ "in_reply_to_status_id" => a2.id
+ })
+
+ {:ok, r2_2} =
+ CommonAPI.post(u3, %{
+ "status" => "@#{u2.nickname} reply from u3 to u2",
+ "in_reply_to_status_id" => a2.id
+ })
+
+ {:ok, r2_3} =
+ CommonAPI.post(u4, %{
+ "status" => "@#{u2.nickname} reply from u4 to u2",
+ "in_reply_to_status_id" => a2.id
+ })
+
+ {:ok, a3} = CommonAPI.post(u3, %{"status" => "Status"})
+
+ {:ok, r3_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u3.nickname} reply from u1 to u3",
+ "in_reply_to_status_id" => a3.id
+ })
+
+ {:ok, r3_2} =
+ CommonAPI.post(u2, %{
+ "status" => "@#{u3.nickname} reply from u2 to u3",
+ "in_reply_to_status_id" => a3.id
+ })
+
+ {:ok, r3_3} =
+ CommonAPI.post(u4, %{
+ "status" => "@#{u3.nickname} reply from u4 to u3",
+ "in_reply_to_status_id" => a3.id
+ })
+
+ {:ok, a4} = CommonAPI.post(u4, %{"status" => "Status"})
+
+ {:ok, r4_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u4.nickname} reply from u1 to u4",
+ "in_reply_to_status_id" => a4.id
+ })
+
+ {:ok, r4_2} =
+ CommonAPI.post(u2, %{
+ "status" => "@#{u4.nickname} reply from u2 to u4",
+ "in_reply_to_status_id" => a4.id
+ })
+
+ {:ok, r4_3} =
+ CommonAPI.post(u3, %{
+ "status" => "@#{u4.nickname} reply from u3 to u4",
+ "in_reply_to_status_id" => a4.id
+ })
+
+ {:ok,
+ users: %{u1: u1, u2: u2, u3: u3, u4: u4},
+ activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
+ u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
+ u2: %{r1: r2_1.id, r2: r2_2.id, r3: r2_3.id},
+ u3: %{r1: r3_1.id, r2: r3_2.id, r3: r3_3.id},
+ u4: %{r1: r4_1.id, r2: r4_2.id, r3: r4_3.id}}
+ end
+
+ defp private_messages(_) do
+ [u1, u2, u3, u4] = insert_list(4, :user)
+ {:ok, u1} = User.follow(u1, u2)
+ {:ok, u2} = User.follow(u2, u1)
+ {:ok, u1} = User.follow(u1, u3)
+ {:ok, u3} = User.follow(u3, u1)
+ {:ok, u1} = User.follow(u1, u4)
+ {:ok, u4} = User.follow(u4, u1)
+
+ {:ok, u2} = User.follow(u2, u3)
+ {:ok, u3} = User.follow(u3, u2)
+
+ {:ok, a1} = CommonAPI.post(u1, %{"status" => "Status", "visibility" => "private"})
+
+ {:ok, r1_1} =
+ CommonAPI.post(u2, %{
+ "status" => "@#{u1.nickname} reply from u2 to u1",
+ "in_reply_to_status_id" => a1.id,
+ "visibility" => "private"
+ })
+
+ {:ok, r1_2} =
+ CommonAPI.post(u3, %{
+ "status" => "@#{u1.nickname} reply from u3 to u1",
+ "in_reply_to_status_id" => a1.id,
+ "visibility" => "private"
+ })
+
+ {:ok, r1_3} =
+ CommonAPI.post(u4, %{
+ "status" => "@#{u1.nickname} reply from u4 to u1",
+ "in_reply_to_status_id" => a1.id,
+ "visibility" => "private"
+ })
+
+ {:ok, a2} = CommonAPI.post(u2, %{"status" => "Status", "visibility" => "private"})
+
+ {:ok, r2_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u2.nickname} reply from u1 to u2",
+ "in_reply_to_status_id" => a2.id,
+ "visibility" => "private"
+ })
+
+ {:ok, r2_2} =
+ CommonAPI.post(u3, %{
+ "status" => "@#{u2.nickname} reply from u3 to u2",
+ "in_reply_to_status_id" => a2.id,
+ "visibility" => "private"
+ })
+
+ {:ok, a3} = CommonAPI.post(u3, %{"status" => "Status", "visibility" => "private"})
+
+ {:ok, r3_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u3.nickname} reply from u1 to u3",
+ "in_reply_to_status_id" => a3.id,
+ "visibility" => "private"
+ })
+
+ {:ok, r3_2} =
+ CommonAPI.post(u2, %{
+ "status" => "@#{u3.nickname} reply from u2 to u3",
+ "in_reply_to_status_id" => a3.id,
+ "visibility" => "private"
+ })
+
+ {:ok, a4} = CommonAPI.post(u4, %{"status" => "Status", "visibility" => "private"})
+
+ {:ok, r4_1} =
+ CommonAPI.post(u1, %{
+ "status" => "@#{u4.nickname} reply from u1 to u4",
+ "in_reply_to_status_id" => a4.id,
+ "visibility" => "private"
+ })
+
+ {:ok,
+ users: %{u1: u1, u2: u2, u3: u3, u4: u4},
+ activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
+ u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
+ u2: %{r1: r2_1.id, r2: r2_2.id},
+ u3: %{r1: r3_1.id, r2: r3_2.id},
+ u4: %{r1: r4_1.id}}
+ end
end
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index e913a5148..b0bfed917 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -224,8 +224,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
object = Object.normalize(activity)
{:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
- vote_object = Object.normalize(vote)
- {:ok, _activity, _object} = ActivityPub.like(user, vote_object)
+ {:ok, _activity} = CommonAPI.favorite(user, activity.id)
[fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
assert fetched_vote.id == vote.id
end
@@ -346,7 +345,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
user = insert(:user)
refute Utils.get_existing_like(user.ap_id, object)
- {:ok, like_activity, _object} = ActivityPub.like(user, object)
+ {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
end
diff --git a/test/web/api_spec/app_operation_test.exs b/test/web/api_spec/app_operation_test.exs
deleted file mode 100644
index 5b96abb44..000000000
--- a/test/web/api_spec/app_operation_test.exs
+++ /dev/null
@@ -1,45 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ApiSpec.AppOperationTest do
- use Pleroma.Web.ConnCase, async: true
-
- alias Pleroma.Web.ApiSpec
- alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
- alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
-
- import OpenApiSpex.TestAssertions
- import Pleroma.Factory
-
- test "AppCreateRequest example matches schema" do
- api_spec = ApiSpec.spec()
- schema = AppCreateRequest.schema()
- assert_schema(schema.example, "AppCreateRequest", api_spec)
- end
-
- test "AppCreateResponse example matches schema" do
- api_spec = ApiSpec.spec()
- schema = AppCreateResponse.schema()
- assert_schema(schema.example, "AppCreateResponse", api_spec)
- end
-
- test "AppController produces a AppCreateResponse", %{conn: conn} do
- api_spec = ApiSpec.spec()
- app_attrs = build(:oauth_app)
-
- json =
- conn
- |> put_req_header("content-type", "application/json")
- |> post(
- "/api/v1/apps",
- Jason.encode!(%{
- client_name: app_attrs.client_name,
- redirect_uris: app_attrs.redirect_uris
- })
- )
- |> json_response(200)
-
- assert_schema(json, "AppCreateResponse", api_spec)
- end
-end
diff --git a/test/web/api_spec/schema_examples_test.exs b/test/web/api_spec/schema_examples_test.exs
new file mode 100644
index 000000000..88b6f07cb
--- /dev/null
+++ b/test/web/api_spec/schema_examples_test.exs
@@ -0,0 +1,43 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do
+ use ExUnit.Case, async: true
+ import Pleroma.Tests.ApiSpecHelpers
+
+ @content_type "application/json"
+
+ for operation <- api_operations() do
+ describe operation.operationId <> " Request Body" do
+ if operation.requestBody do
+ @media_type operation.requestBody.content[@content_type]
+ @schema resolve_schema(@media_type.schema)
+
+ if @media_type.example do
+ test "request body media type example matches schema" do
+ assert_schema(@media_type.example, @schema)
+ end
+ end
+
+ if @schema.example do
+ test "request body schema example matches schema" do
+ assert_schema(@schema.example, @schema)
+ end
+ end
+ end
+ end
+
+ for {status, response} <- operation.responses do
+ describe "#{operation.operationId} - #{status} Response" do
+ @schema resolve_schema(response.content[@content_type].schema)
+
+ if @schema.example do
+ test "example matches schema" do
+ assert_schema(@schema.example, @schema)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index e130736ec..1758662b0 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -21,6 +21,60 @@ defmodule Pleroma.Web.CommonAPITest do
setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses])
+ test "favoriting race condition" do
+ user = insert(:user)
+ users_serial = insert_list(10, :user)
+ users = insert_list(10, :user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
+
+ users_serial
+ |> Enum.map(fn user ->
+ CommonAPI.favorite(user, activity.id)
+ end)
+
+ object = Object.get_by_ap_id(activity.data["object"])
+ assert object.data["like_count"] == 10
+
+ users
+ |> Enum.map(fn user ->
+ Task.async(fn ->
+ CommonAPI.favorite(user, activity.id)
+ end)
+ end)
+ |> Enum.map(&Task.await/1)
+
+ object = Object.get_by_ap_id(activity.data["object"])
+ assert object.data["like_count"] == 20
+ end
+
+ test "repeating race condition" do
+ user = insert(:user)
+ users_serial = insert_list(10, :user)
+ users = insert_list(10, :user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
+
+ users_serial
+ |> Enum.map(fn user ->
+ CommonAPI.repeat(activity.id, user)
+ end)
+
+ object = Object.get_by_ap_id(activity.data["object"])
+ assert object.data["announcement_count"] == 10
+
+ users
+ |> Enum.map(fn user ->
+ Task.async(fn ->
+ CommonAPI.repeat(activity.id, user)
+ end)
+ end)
+ |> Enum.map(&Task.await/1)
+
+ object = Object.get_by_ap_id(activity.data["object"])
+ assert object.data["announcement_count"] == 20
+ end
+
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
@@ -256,6 +310,16 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
end
+ test "can't repeat a repeat" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
+
+ {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
+
+ refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
+ end
+
test "repeating a status privately" do
user = insert(:user)
other_user = insert(:user)
@@ -285,8 +349,8 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
- {:ok, %Activity{} = activity, object} = CommonAPI.repeat(activity.id, user)
- {:ok, ^activity, ^object} = CommonAPI.repeat(activity.id, user)
+ {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
+ {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
end
test "favoriting a status twice returns ok, but without the like activity" do
@@ -360,7 +424,9 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
- assert {:ok, ^activity} = CommonAPI.unpin(activity.id, user)
+ id = activity.id
+
+ assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
user = refresh_record(user)
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index b21445fe9..18a3b3b87 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -335,26 +335,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
end
end
- describe "get_by_id_or_ap_id/1" do
- test "get activity by id" do
- activity = insert(:note_activity)
- %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.id)
- assert note.id == activity.id
- end
-
- test "get activity by ap_id" do
- activity = insert(:note_activity)
- %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.data["object"])
- assert note.id == activity.id
- end
-
- test "get activity by object when type isn't `Create` " do
- activity = insert(:like_activity)
- %Pleroma.Activity{} = like = Utils.get_by_id_or_ap_id(activity.id)
- assert like.data["object"] == activity.data["object"]
- end
- end
-
describe "to_master_date/1" do
test "removes microseconds from date (NaiveDateTime)" do
assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z"
diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/web/mastodon_api/controllers/app_controller_test.exs
index e7b11d14e..a0b8b126c 100644
--- a/test/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/web/mastodon_api/controllers/app_controller_test.exs
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
}
- assert expected == json_response(conn, 200)
+ assert expected == json_response_and_validate_schema(conn, 200)
end
test "creates an oauth app", %{conn: conn} do
@@ -55,6 +55,6 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
}
- assert expected == json_response(conn, 200)
+ assert expected == json_response_and_validate_schema(conn, 200)
end
end
diff --git a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs b/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs
index 0b2ffa470..4222556a4 100644
--- a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs
+++ b/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs
@@ -5,15 +5,13 @@
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.ApiSpec
- alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
- alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
import OpenApiSpex.TestAssertions
test "with tags", %{conn: conn} do
assert resp =
conn
|> get("/api/v1/custom_emojis")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert [emoji | _body] = resp
assert Map.has_key?(emoji, "shortcode")
@@ -23,19 +21,6 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
assert Map.has_key?(emoji, "category")
assert Map.has_key?(emoji, "url")
assert Map.has_key?(emoji, "visible_in_picker")
- assert_schema(resp, "CustomEmojisResponse", ApiSpec.spec())
assert_schema(emoji, "CustomEmoji", ApiSpec.spec())
end
-
- test "CustomEmoji example matches schema" do
- api_spec = ApiSpec.spec()
- schema = CustomEmoji.schema()
- assert_schema(schema.example, "CustomEmoji", api_spec)
- end
-
- test "CustomEmojisResponse example matches schema" do
- api_spec = ApiSpec.spec()
- schema = CustomEmojisResponse.schema()
- assert_schema(schema.example, "CustomEmojisResponse", api_spec)
- end
end
diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/web/mastodon_api/controllers/domain_block_controller_test.exs
index d66190c90..01a24afcf 100644
--- a/test/web/mastodon_api/controllers/domain_block_controller_test.exs
+++ b/test/web/mastodon_api/controllers/domain_block_controller_test.exs
@@ -6,11 +6,8 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.User
- alias Pleroma.Web.ApiSpec
- alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
import Pleroma.Factory
- import OpenApiSpex.TestAssertions
test "blocking / unblocking a domain" do
%{user: user, conn: conn} = oauth_access(["write:blocks"])
@@ -21,7 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
|> put_req_header("content-type", "application/json")
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
- assert %{} = json_response(ret_conn, 200)
+ assert %{} == json_response_and_validate_schema(ret_conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
assert User.blocks?(user, other_user)
@@ -30,7 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
|> put_req_header("content-type", "application/json")
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
- assert %{} = json_response(ret_conn, 200)
+ assert %{} == json_response_and_validate_schema(ret_conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
refute User.blocks?(user, other_user)
end
@@ -41,21 +38,10 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
{:ok, user} = User.block_domain(user, "bad.site")
{:ok, user} = User.block_domain(user, "even.worse.site")
- conn =
- conn
- |> assign(:user, user)
- |> get("/api/v1/domain_blocks")
-
- domain_blocks = json_response(conn, 200)
-
- assert "bad.site" in domain_blocks
- assert "even.worse.site" in domain_blocks
- assert_schema(domain_blocks, "DomainBlocksResponse", ApiSpec.spec())
- end
-
- test "DomainBlocksResponse example matches schema" do
- api_spec = ApiSpec.spec()
- schema = DomainBlocksResponse.schema()
- assert_schema(schema.example, "DomainBlocksResponse", api_spec)
+ assert ["even.worse.site", "bad.site"] ==
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/domain_blocks")
+ |> json_response_and_validate_schema(200)
end
end
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
index 162f7b1b2..85068edd0 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -302,6 +302,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert [] == Repo.all(Activity)
end
+ test "ignores nil values", %{conn: conn} do
+ conn =
+ post(conn, "/api/v1/statuses", %{
+ "status" => "not scheduled",
+ "scheduled_at" => nil
+ })
+
+ assert result = json_response(conn, 200)
+ assert Activity.get_by_id(result["id"])
+ end
+
test "creates a scheduled activity with a media attachment", %{user: user, conn: conn} do
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)