diff options
Diffstat (limited to 'test')
104 files changed, 3409 insertions, 776 deletions
diff --git a/test/fixtures/DSCN0010.png b/test/fixtures/DSCN0010.png Binary files differnew file mode 100644 index 000000000..66f2f05f7 --- /dev/null +++ b/test/fixtures/DSCN0010.png diff --git a/test/fixtures/bastianallgeier.json b/test/fixtures/bastianallgeier.json new file mode 100644 index 000000000..6b47e7db9 --- /dev/null +++ b/test/fixtures/bastianallgeier.json @@ -0,0 +1,117 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Curve25519Key": "toot:Curve25519Key", + "Device": "toot:Device", + "Ed25519Key": "toot:Ed25519Key", + "Ed25519Signature": "toot:Ed25519Signature", + "EncryptedMessage": "toot:EncryptedMessage", + "PropertyValue": "schema:PropertyValue", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + }, + "cipherText": "toot:cipherText", + "claim": { + "@id": "toot:claim", + "@type": "@id" + }, + "deviceId": "toot:deviceId", + "devices": { + "@id": "toot:devices", + "@type": "@id" + }, + "discoverable": "toot:discoverable", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "featuredTags": { + "@id": "toot:featuredTags", + "@type": "@id" + }, + "fingerprintKey": { + "@id": "toot:fingerprintKey", + "@type": "@id" + }, + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "identityKey": { + "@id": "toot:identityKey", + "@type": "@id" + }, + "indexable": "toot:indexable", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "memorial": "toot:memorial", + "messageFranking": "toot:messageFranking", + "messageType": "toot:messageType", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "publicKeyBase64": "toot:publicKeyBase64", + "schema": "http://schema.org#", + "suspended": "toot:suspended", + "toot": "http://joinmastodon.org/ns#", + "value": "schema:value" + } + ], + "attachment": [ + { + "name": "Website", + "type": "PropertyValue", + "value": "<a href=\"https://bastianallgeier.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">bastianallgeier.com</span><span class=\"invisible\"></span></a>" + }, + { + "name": "Project", + "type": "PropertyValue", + "value": "<a href=\"https://getkirby.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">getkirby.com</span><span class=\"invisible\"></span></a>" + }, + { + "name": "Github", + "type": "PropertyValue", + "value": "<a href=\"https://github.com/bastianallgeier\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">github.com/bastianallgeier</span><span class=\"invisible\"></span></a>" + } + ], + "devices": "https://mastodon.social/users/bastianallgeier/collections/devices", + "discoverable": true, + "endpoints": { + "sharedInbox": "https://mastodon.social/inbox" + }, + "featured": "https://mastodon.social/users/bastianallgeier/collections/featured", + "featuredTags": "https://mastodon.social/users/bastianallgeier/collections/tags", + "followers": "https://mastodon.social/users/bastianallgeier/followers", + "following": "https://mastodon.social/users/bastianallgeier/following", + "icon": { + "mediaType": "image/jpeg", + "type": "Image", + "url": "https://files.mastodon.social/accounts/avatars/000/007/393/original/0180a20079617c71.jpg" + }, + "id": "https://mastodon.social/users/bastianallgeier", + "image": { + "mediaType": "image/jpeg", + "type": "Image", + "url": "https://files.mastodon.social/accounts/headers/000/007/393/original/13d644ab46d50478.jpeg" + }, + "inbox": "https://mastodon.social/users/bastianallgeier/inbox", + "indexable": false, + "manuallyApprovesFollowers": false, + "memorial": false, + "name": "Bastian Allgeier", + "outbox": "https://mastodon.social/users/bastianallgeier/outbox", + "preferredUsername": "bastianallgeier", + "publicKey": { + "id": "https://mastodon.social/users/bastianallgeier#main-key", + "owner": "https://mastodon.social/users/bastianallgeier", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fz+hpgVztO9z6HUhyzv\nwP++ERBBoIwSLKf1TyIM8bvzGFm2YXaO5uxu1HvumYFTYc3ACr3q4j8VUb7NMxkQ\nlzu4QwPjOFJ43O+fY+HSPORXEDW5fXDGC5DGpox4+i08LxRmx7L6YPRUSUuPN8nI\nWyq1Qsq1zOQrNY/rohMXkBdSXxqC3yIRqvtLt4otCgay/5tMogJWkkS6ZKyFhb9z\nwVVy1fsbV10c9C+SHy4NH26CKaTtpTYLRBMjhTCS8bX8iDSjGIf2aZgYs1ir7gEz\n9wf5CvLiENmVWGwm64t6KSEAkA4NJ1hzgHUZPCjPHZE2SmhO/oHaxokTzqtbbENJ\n1QIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "published": "2016-11-01T00:00:00Z", + "summary": "<p>Designer & developer. Creator of Kirby CMS</p>", + "tag": [], + "type": "Person", + "url": "https://mastodon.social/@bastianallgeier" +} diff --git a/test/fixtures/denniskoch.json b/test/fixtures/denniskoch.json new file mode 100644 index 000000000..7aa4de508 --- /dev/null +++ b/test/fixtures/denniskoch.json @@ -0,0 +1,112 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Curve25519Key": "toot:Curve25519Key", + "Device": "toot:Device", + "Ed25519Key": "toot:Ed25519Key", + "Ed25519Signature": "toot:Ed25519Signature", + "EncryptedMessage": "toot:EncryptedMessage", + "PropertyValue": "schema:PropertyValue", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + }, + "cipherText": "toot:cipherText", + "claim": { + "@id": "toot:claim", + "@type": "@id" + }, + "deviceId": "toot:deviceId", + "devices": { + "@id": "toot:devices", + "@type": "@id" + }, + "discoverable": "toot:discoverable", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "featuredTags": { + "@id": "toot:featuredTags", + "@type": "@id" + }, + "fingerprintKey": { + "@id": "toot:fingerprintKey", + "@type": "@id" + }, + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "identityKey": { + "@id": "toot:identityKey", + "@type": "@id" + }, + "indexable": "toot:indexable", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "memorial": "toot:memorial", + "messageFranking": "toot:messageFranking", + "messageType": "toot:messageType", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "publicKeyBase64": "toot:publicKeyBase64", + "schema": "http://schema.org#", + "suspended": "toot:suspended", + "toot": "http://joinmastodon.org/ns#", + "value": "schema:value" + } + ], + "attachment": [ + { + "name": "GitHub", + "type": "PropertyValue", + "value": "<a href=\"https://github.com/pxlrbt/\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">github.com/pxlrbt/</span><span class=\"invisible\"></span></a>" + }, + { + "name": "Discord", + "type": "PropertyValue", + "value": "pxlrbt#6029" + } + ], + "devices": "https://phpc.social/users/denniskoch/collections/devices", + "discoverable": true, + "endpoints": { + "sharedInbox": "https://phpc.social/inbox" + }, + "featured": "https://phpc.social/users/denniskoch/collections/featured", + "featuredTags": "https://phpc.social/users/denniskoch/collections/tags", + "followers": "https://phpc.social/users/denniskoch/followers", + "following": "https://phpc.social/users/denniskoch/following", + "icon": { + "mediaType": "image/jpeg", + "type": "Image", + "url": "https://media.phpc.social/accounts/avatars/109/364/097/179/042/485/original/6e770c7b3f5ef72d.jpg" + }, + "id": "https://phpc.social/users/denniskoch", + "image": { + "mediaType": "image/jpeg", + "type": "Image", + "url": "https://media.phpc.social/accounts/headers/109/364/097/179/042/485/original/709da24705260c04.jpg" + }, + "inbox": "https://phpc.social/users/denniskoch/inbox", + "indexable": true, + "manuallyApprovesFollowers": false, + "memorial": false, + "name": "Dennis Koch", + "outbox": "https://phpc.social/users/denniskoch/outbox", + "preferredUsername": "denniskoch", + "publicKey": { + "id": "https://phpc.social/users/denniskoch#main-key", + "owner": "https://phpc.social/users/denniskoch", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dmcSlqLj18gPvuslkmt\nQTniZ8ybO4pgvMvPLYtBuTBUjo49vJ/8Sw6jB5zcKb1haqIdny7Rv/vY3kCdCXcP\nloh1I+jthEgqLT8JpZWGwLGwg9piFhrMGADmt3N8du7HfglzuZ8LlVpnZ8feCw7I\nS2ua/ZCxE47mI45Z3ed2kkFYKWopWWqFn2lan/1OyHrcFKtCvaVjRdvo0UUt2tgl\nvyJI4+zN8FnrCbsMtcbI5nSzfJIrOc4LeaGmLJh+0o2rwoOQZc2487XWbeyfhjsq\nPRBpYN7pfHWQDvzQIN075LHTf9zDFsm6+HqY7Zs5rYxr72rvcX7d9JcP6CasIosY\nqwIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "published": "2022-11-18T00:00:00Z", + "summary": "<p>🧑💻 Full Stack Developer<br />🚀 Laravel, Filament, Livewire, Vue, Inertia<br />🌍 Germany</p>", + "tag": [], + "type": "Person", + "url": "https://phpc.social/@denniskoch" +} diff --git a/test/fixtures/receiver_worker_signature_activity.json b/test/fixtures/receiver_worker_signature_activity.json new file mode 100644 index 000000000..3c3fb3fd2 --- /dev/null +++ b/test/fixtures/receiver_worker_signature_activity.json @@ -0,0 +1,62 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "atomUri": "ostatus:atomUri", + "blurhash": "toot:blurhash", + "conversation": "ostatus:conversation", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "ostatus": "http://ostatus.org#", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "votersCount": "toot:votersCount" + } + ], + "atomUri": "https://chaos.social/users/distantnative/statuses/109336635639931467", + "attachment": [ + { + "blurhash": "UAK1zS00OXIUxuMxIUM{?b-:-;W:Di?b%2M{", + "height": 960, + "mediaType": "image/jpeg", + "name": null, + "type": "Document", + "url": "https://assets.chaos.social/media_attachments/files/109/336/634/286/114/657/original/2e6122063d8bfb26.jpeg", + "width": 346 + } + ], + "attributedTo": "https://chaos.social/users/distantnative", + "cc": [ + "https://chaos.social/users/distantnative/followers" + ], + "content": "<p>Favorite piece of anthropology meta discourse.</p>", + "contentMap": { + "en": "<p>Favorite piece of anthropology meta discourse.</p>" + }, + "conversation": "tag:chaos.social,2022-11-13:objectId=71843781:objectType=Conversation", + "id": "https://chaos.social/users/distantnative/statuses/109336635639931467", + "inReplyTo": null, + "inReplyToAtomUri": null, + "published": "2022-11-13T13:04:20Z", + "replies": { + "first": { + "items": [], + "next": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies?only_other_accounts=true&page=true", + "partOf": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies", + "type": "CollectionPage" + }, + "id": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies", + "type": "Collection" + }, + "sensitive": false, + "summary": null, + "tag": [], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note", + "url": "https://chaos.social/@distantnative/109336635639931467" +} diff --git a/test/fixtures/tesla_mock/gleasonator.com_host_meta b/test/fixtures/tesla_mock/gleasonator.com_host_meta new file mode 100644 index 000000000..c1a432519 --- /dev/null +++ b/test/fixtures/tesla_mock/gleasonator.com_host_meta @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> + <Link rel="lrdd" template="https://gleasonator.com/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /> +</XRD>
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/webfinger_spoof.json b/test/fixtures/tesla_mock/webfinger_spoof.json new file mode 100644 index 000000000..7c2a11f69 --- /dev/null +++ b/test/fixtures/tesla_mock/webfinger_spoof.json @@ -0,0 +1,28 @@ +{ + "aliases": [ + "https://gleasonator.com/users/alex", + "https://mitra.social/users/alex" + ], + "links": [ + { + "href": "https://gleasonator.com/users/alex", + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html" + }, + { + "href": "https://gleasonator.com/users/alex", + "rel": "self", + "type": "application/activity+json" + }, + { + "href": "https://gleasonator.com/users/alex", + "rel": "self", + "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" + }, + { + "rel": "http://ostatus.org/schema/1.0/subscribe", + "template": "https://gleasonator.com/ostatus_subscribe?acct={uri}" + } + ], + "subject": "acct:trump@whitehouse.gov" +} diff --git a/test/fixtures/unindexed_fk.sql b/test/fixtures/unindexed_fk.sql new file mode 100644 index 000000000..3b71679cf --- /dev/null +++ b/test/fixtures/unindexed_fk.sql @@ -0,0 +1,27 @@ +-- Unindexed FK -- Missing indexes - For CI + +WITH y AS ( +SELECT +pg_catalog.format('%I', c1.relname) AS referencing_tbl, +pg_catalog.quote_ident(a1.attname) AS referencing_column, +(SELECT pg_get_expr(indpred, indrelid) FROM pg_catalog.pg_index WHERE indrelid = t.conrelid AND indkey[0] = t.conkey[1] AND indpred IS NOT NULL LIMIT 1) partial_statement +FROM pg_catalog.pg_constraint t +JOIN pg_catalog.pg_attribute a1 ON a1.attrelid = t.conrelid AND a1.attnum = t.conkey[1] +JOIN pg_catalog.pg_class c1 ON c1.oid = t.conrelid +JOIN pg_catalog.pg_namespace n1 ON n1.oid = c1.relnamespace +JOIN pg_catalog.pg_class c2 ON c2.oid = t.confrelid +JOIN pg_catalog.pg_namespace n2 ON n2.oid = c2.relnamespace +JOIN pg_catalog.pg_attribute a2 ON a2.attrelid = t.confrelid AND a2.attnum = t.confkey[1] +WHERE t.contype = 'f' +AND NOT EXISTS ( +SELECT 1 +FROM pg_catalog.pg_index i +WHERE i.indrelid = t.conrelid +AND i.indkey[0] = t.conkey[1] +AND indpred IS NULL +) +) +SELECT referencing_tbl || '.' || referencing_column as "column" +FROM y +WHERE (partial_statement IS NULL OR partial_statement <> ('(' || referencing_column || ' IS NOT NULL)')) +ORDER BY 1;
\ No newline at end of file diff --git a/test/fixtures/webfinger/graf-imposter-webfinger.json b/test/fixtures/webfinger/graf-imposter-webfinger.json new file mode 100644 index 000000000..e7010f606 --- /dev/null +++ b/test/fixtures/webfinger/graf-imposter-webfinger.json @@ -0,0 +1,41 @@ +{ + "subject": "acct:graf@poa.st", + "aliases": [ + "https://fba.ryona.agenc/webfingertest" + ], + "links": [ + { + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html", + "href": "https://fba.ryona.agenc/webfingertest" + }, + { + "rel": "self", + "type": "application/activity+json", + "href": "https://fba.ryona.agenc/webfingertest" + }, + { + "rel": "http://ostatus.org/schema/1.0/subscribe", + "template": "https://fba.ryona.agenc/contact/follow?url={uri}" + }, + { + "rel": "http://schemas.google.com/g/2010#updates-from", + "type": "application/atom+xml", + "href": "" + }, + { + "rel": "salmon", + "href": "https://fba.ryona.agenc/salmon/friendica" + }, + { + "rel": "http://microformats.org/profile/hcard", + "type": "text/html", + "href": "https://fba.ryona.agenc/hcard/friendica" + }, + { + "rel": "http://joindiaspora.com/seed_location", + "type": "text/html", + "href": "https://fba.ryona.agenc" + } + ] +} diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index 7b2134129..942cfa83d 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -51,7 +51,6 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do clear_config(:configurable_from_database, true) end - @tag capture_log: true test "config migration refused when deprecated settings are found" do clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"]) assert config_records() == [] diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index fbc939171..a51a3bf3d 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -7,6 +7,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity + alias Pleroma.Bookmark alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -45,28 +46,509 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do end describe "prune_objects" do - test "it prunes old objects from the database" do - insert(:note) + setup do deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - date = + old_insert_date = Timex.now() |> Timex.shift(days: -deadline) |> Timex.to_naive_datetime() |> NaiveDateTime.truncate(:second) - %{id: id} = + %{old_insert_date: old_insert_date} + end + + test "it prunes old objects from the database", %{old_insert_date: old_insert_date} do + insert(:note) + + %{id: note_remote_public_id} = :note |> insert() - |> Ecto.Changeset.change(%{inserted_at: date}) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) |> Repo.update!() + note_remote_non_public = + %{id: note_remote_non_public_id, data: note_remote_non_public_data} = + :note + |> insert() + + note_remote_non_public + |> Ecto.Changeset.change(%{ + updated_at: old_insert_date, + data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) + }) + |> Repo.update!() + + assert length(Repo.all(Object)) == 3 + + Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + + assert length(Repo.all(Object)) == 1 + refute Object.get_by_id(note_remote_public_id) + refute Object.get_by_id(note_remote_non_public_id) + end + + test "it cleans up bookmarks", %{old_insert_date: old_insert_date} do + user = insert(:user) + {:ok, old_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + Repo.one(Object) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, new_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + {:ok, _} = Bookmark.create(user.id, old_object_activity.id) + {:ok, _} = Bookmark.create(user.id, new_object_activity.id) + assert length(Repo.all(Object)) == 2 + assert length(Repo.all(Bookmark)) == 2 Mix.Tasks.Pleroma.Database.run(["prune_objects"]) assert length(Repo.all(Object)) == 1 - refute Object.get_by_id(id) + assert length(Repo.all(Bookmark)) == 1 + refute Bookmark.get(user.id, old_object_activity.id) + end + + test "with the --keep-non-public option it still keeps non-public posts even if they are not local", + %{old_insert_date: old_insert_date} do + insert(:note) + + %{id: note_remote_id} = + :note + |> insert() + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) + |> Repo.update!() + + note_remote_non_public = + %{data: note_remote_non_public_data} = + :note + |> insert() + + note_remote_non_public + |> Ecto.Changeset.change(%{ + updated_at: old_insert_date, + data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) + }) + |> Repo.update!() + + assert length(Repo.all(Object)) == 3 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-non-public"]) + + assert length(Repo.all(Object)) == 2 + refute Object.get_by_id(note_remote_id) + end + + test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local", + %{old_insert_date: old_insert_date} do + # For non-public we only check Create Activities because only these are relevant for threads + # Flags are always non-public, Announces from relays can be non-public... + + remote_user1 = insert(:user, local: false) + remote_user2 = insert(:user, local: false) + + # Old remote non-public reply (should be kept) + {:ok, old_remote_post1_activity} = + CommonAPI.post(remote_user1, %{status: "some thing", local: false}) + + old_remote_post1_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_remote_non_public_reply_activity} = + CommonAPI.post(remote_user2, %{ + status: "some reply", + in_reply_to_status_id: old_remote_post1_activity.id + }) + + old_remote_non_public_reply_activity + |> Ecto.Changeset.change(%{ + local: false, + updated_at: old_insert_date, + data: old_remote_non_public_reply_activity.data |> update_in(["to"], fn _ -> [] end) + }) + |> Repo.update!() + + # Old remote non-public Announce (should be removed) + {:ok, old_remote_post2_activity = %{data: %{"object" => old_remote_post2_id}}} = + CommonAPI.post(remote_user1, %{status: "some thing", local: false}) + + old_remote_post2_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_remote_non_public_repeat_activity} = + CommonAPI.repeat(old_remote_post2_activity.id, remote_user2) + + old_remote_non_public_repeat_activity + |> Ecto.Changeset.change(%{ + local: false, + updated_at: old_insert_date, + data: old_remote_non_public_repeat_activity.data |> update_in(["to"], fn _ -> [] end) + }) + |> Repo.update!() + + assert length(Repo.all(Object)) == 3 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads", "--keep-non-public"]) + + Repo.all(Pleroma.Activity) + assert length(Repo.all(Object)) == 2 + refute Object.get_by_ap_id(old_remote_post2_id) + end + + test "with the --keep-threads option it still keeps non-old threads even with no local interactions" do + remote_user = insert(:user, local: false) + remote_user2 = insert(:user, local: false) + + {:ok, remote_post_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + {:ok, remote_post_reply_activity} = + CommonAPI.post(remote_user2, %{ + status: "some reply", + in_reply_to_status_id: remote_post_activity.id + }) + + remote_post_activity + |> Ecto.Changeset.change(%{local: false}) + |> Repo.update!() + + remote_post_reply_activity + |> Ecto.Changeset.change(%{local: false}) + |> Repo.update!() + + assert length(Repo.all(Object)) == 2 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"]) + + assert length(Repo.all(Object)) == 2 + end + + test "with the --keep-threads option it deletes old threads with no local interaction", %{ + old_insert_date: old_insert_date + } do + remote_user = insert(:user, local: false) + remote_user2 = insert(:user, local: false) + + {:ok, old_remote_post_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + old_remote_post_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_remote_post_reply_activity} = + CommonAPI.post(remote_user2, %{ + status: "some reply", + in_reply_to_status_id: old_remote_post_activity.id + }) + + old_remote_post_reply_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_favourite_activity} = + CommonAPI.favorite(old_remote_post_activity.id, remote_user2) + + old_favourite_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_repeat_activity} = CommonAPI.repeat(old_remote_post_activity.id, remote_user2) + + old_repeat_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + assert length(Repo.all(Object)) == 2 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"]) + + assert length(Repo.all(Object)) == 0 + end + + test "with the --keep-threads option it keeps old threads with local interaction", %{ + old_insert_date: old_insert_date + } do + remote_user = insert(:user, local: false) + local_user = insert(:user, local: true) + + # local reply + {:ok, old_remote_post1_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + old_remote_post1_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_local_post2_reply_activity} = + CommonAPI.post(local_user, %{ + status: "some reply", + in_reply_to_status_id: old_remote_post1_activity.id + }) + + old_local_post2_reply_activity + |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date}) + |> Repo.update!() + + # local Like + {:ok, old_remote_post3_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + old_remote_post3_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_favourite_activity} = CommonAPI.favorite(old_remote_post3_activity.id, local_user) + + old_favourite_activity + |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date}) + |> Repo.update!() + + # local Announce + {:ok, old_remote_post4_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + old_remote_post4_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, old_repeat_activity} = CommonAPI.repeat(old_remote_post4_activity.id, local_user) + + old_repeat_activity + |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date}) + |> Repo.update!() + + assert length(Repo.all(Object)) == 4 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"]) + + assert length(Repo.all(Object)) == 4 + end + + test "with the --keep-threads option it keeps old threads with bookmarked posts", %{ + old_insert_date: old_insert_date + } do + remote_user = insert(:user, local: false) + local_user = insert(:user, local: true) + + {:ok, old_remote_post_activity} = + CommonAPI.post(remote_user, %{status: "some thing", local: false}) + + old_remote_post_activity + |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date}) + |> Repo.update!() + + Pleroma.Bookmark.create(local_user.id, old_remote_post_activity.id) + + assert length(Repo.all(Object)) == 1 + + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"]) + + assert length(Repo.all(Object)) == 1 + end + + test "We don't have unexpected tables which may contain objects that are referenced by activities" do + # We can delete orphaned activities. For that we look for the objects + # they reference in the 'objects', 'activities', and 'users' table. + # If someone adds another table with objects (idk, maybe with separate + # relations, or collections or w/e), then we need to make sure we + # add logic for that in the 'prune_objects' task so that we don't + # wrongly delete their corresponding activities. + # So when someone adds (or removes) a table, this test will fail. + # Either the table contains objects which can be referenced from the + # activities table + # => in that case the prune_objects job should be adapted so we don't + # delete activities who still have the referenced object. + # Or it doesn't contain objects which can be referenced from the activities table + # => in that case you can add/remove the table to/from this (sorted) list. + + assert Repo.query!( + "SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE';" + ).rows + |> Enum.sort() == [ + ["activities"], + ["announcement_read_relationships"], + ["announcements"], + ["apps"], + ["backups"], + ["bookmark_folders"], + ["bookmarks"], + ["chat_message_references"], + ["chats"], + ["config"], + ["conversation_participation_recipient_ships"], + ["conversation_participations"], + ["conversations"], + ["counter_cache"], + ["data_migration_failed_ids"], + ["data_migrations"], + ["deliveries"], + ["filters"], + ["following_relationships"], + ["hashtags"], + ["hashtags_objects"], + ["instances"], + ["lists"], + ["markers"], + ["mfa_tokens"], + ["moderation_log"], + ["notifications"], + ["oauth_authorizations"], + ["oauth_tokens"], + ["oban_jobs"], + ["oban_peers"], + ["objects"], + ["password_reset_tokens"], + ["push_subscriptions"], + ["registrations"], + ["report_notes"], + ["rich_media_card"], + ["rules"], + ["scheduled_activities"], + ["schema_migrations"], + ["thread_mutes"], + # ["user_follows_hashtag"], # not in pleroma + # ["user_frontend_setting_profiles"], # not in pleroma + ["user_invite_tokens"], + ["user_notes"], + ["user_relationships"], + ["users"] + ] + end + + test "it prunes orphaned activities with the --prune-orphaned-activities" do + # Add a remote activity which references an Object + %Object{} |> Map.merge(%{data: %{"id" => "object_for_activity"}}) |> Repo.insert() + + %Activity{} + |> Map.merge(%{ + local: false, + data: %{"id" => "remote_activity_with_object", "object" => "object_for_activity"} + }) + |> Repo.insert() + + # Add a remote activity which references an activity + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_with_activity", + "object" => "remote_activity_with_object" + } + }) + |> Repo.insert() + + # Add a remote activity which references an Actor + %User{} |> Map.merge(%{ap_id: "actor"}) |> Repo.insert() + + %Activity{} + |> Map.merge(%{ + local: false, + data: %{"id" => "remote_activity_with_actor", "object" => "actor"} + }) + |> Repo.insert() + + # Add a remote activity without existing referenced object, activity or actor + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_without_existing_referenced_object", + "object" => "non_existing" + } + }) + |> Repo.insert() + + # Add a local activity without existing referenced object, activity or actor + %Activity{} + |> Map.merge(%{ + local: true, + data: %{"id" => "local_activity_with_actor", "object" => "non_existing"} + }) + |> Repo.insert() + + # The remote activities without existing reference, + # and only the remote activities without existing reference, are deleted + # if, and only if, we provide the --prune-orphaned-activities option + assert length(Repo.all(Activity)) == 5 + Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + assert length(Repo.all(Activity)) == 5 + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--prune-orphaned-activities"]) + activities = Repo.all(Activity) + + assert "remote_activity_without_existing_referenced_object" not in Enum.map( + activities, + fn a -> a.data["id"] end + ) + + assert length(activities) == 4 + end + + test "it prunes orphaned activities with the --prune-orphaned-activities when the objects are referenced from an array" do + %Object{} |> Map.merge(%{data: %{"id" => "existing_object"}}) |> Repo.insert() + %User{} |> Map.merge(%{ap_id: "existing_actor"}) |> Repo.insert() + + # Multiple objects, one object exists (keep) + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_existing_object", + "object" => ["non_ existing_object", "existing_object"] + } + }) + |> Repo.insert() + + # Multiple objects, one actor exists (keep) + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_existing_actor", + "object" => ["non_ existing_object", "existing_actor"] + } + }) + |> Repo.insert() + + # Multiple objects, one activity exists (keep) + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_existing_activity", + "object" => ["non_ existing_object", "remote_activity_existing_actor"] + } + }) + |> Repo.insert() + + # Multiple objects none exist (prune) + %Activity{} + |> Map.merge(%{ + local: false, + data: %{ + "id" => "remote_activity_without_existing_referenced_object", + "object" => ["owo", "whats_this"] + } + }) + |> Repo.insert() + + assert length(Repo.all(Activity)) == 4 + Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + assert length(Repo.all(Activity)) == 4 + Mix.Tasks.Pleroma.Database.run(["prune_objects", "--prune-orphaned-activities"]) + activities = Repo.all(Activity) + assert length(activities) == 3 + + assert "remote_activity_without_existing_referenced_object" not in Enum.map( + activities, + fn a -> a.data["id"] end + ) + + assert length(activities) == 3 end end @@ -104,7 +586,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do {:ok, %{id: id, object: object}} = CommonAPI.post(user, %{status: "test"}) {:ok, %{object: object2}} = CommonAPI.post(user, %{status: "test test"}) - CommonAPI.favorite(user2, id) + CommonAPI.favorite(id, user2) likes = %{ "first" => diff --git a/test/pleroma/activity_test.exs b/test/pleroma/activity_test.exs index 67943d879..62d07b1ee 100644 --- a/test/pleroma/activity_test.exs +++ b/test/pleroma/activity_test.exs @@ -249,7 +249,7 @@ defmodule Pleroma.ActivityTest do {:ok, %{id: id, object: %{data: %{"id" => obj_id}}}} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) - Pleroma.Web.CommonAPI.favorite(another, id) + Pleroma.Web.CommonAPI.favorite(id, another) assert obj_id |> Pleroma.Activity.Queries.by_object_id() diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index e20da1574..d68e4e6fa 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -312,7 +312,7 @@ defmodule Pleroma.ConfigDBTest do test "proxy tuple with domain" do assert ConfigDB.to_elixir_types(%{ "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}] - }) == {:proxy_url, {:socks5, 'domain.com', 1234}} + }) == {:proxy_url, {:socks5, ~c"domain.com", 1234}} end test "proxy tuple with ip" do diff --git a/test/pleroma/gun/connection_pool_test.exs b/test/pleroma/gun/connection_pool_test.exs index e0c9e9904..f3670760d 100644 --- a/test/pleroma/gun/connection_pool_test.exs +++ b/test/pleroma/gun/connection_pool_test.exs @@ -46,7 +46,6 @@ defmodule Pleroma.Gun.ConnectionPoolTest do end end - @tag :erratic test "connection limit is respected with concurrent requests" do clear_config([:connections_pool, :max_connections]) do clear_config([:connections_pool, :max_connections], 1) diff --git a/test/pleroma/http/adapter_helper/gun_test.exs b/test/pleroma/http/adapter_helper/gun_test.exs index d567bc844..568fd6fb3 100644 --- a/test/pleroma/http/adapter_helper/gun_test.exs +++ b/test/pleroma/http/adapter_helper/gun_test.exs @@ -55,23 +55,23 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do uri = URI.parse("https://some-domain.com") opts = Gun.options([receive_conn: false], uri) - assert opts[:proxy] == {'localhost', 8123} + assert opts[:proxy] == {~c"localhost", 8123} end test "parses tuple proxy scheme host and port" do - clear_config([:http, :proxy_url], {:socks, 'localhost', 1234}) + clear_config([:http, :proxy_url], {:socks, ~c"localhost", 1234}) uri = URI.parse("https://some-domain.com") opts = Gun.options([receive_conn: false], uri) - assert opts[:proxy] == {:socks, 'localhost', 1234} + assert opts[:proxy] == {:socks, ~c"localhost", 1234} end test "passed opts have more weight than defaults" do - clear_config([:http, :proxy_url], {:socks5, 'localhost', 1234}) + clear_config([:http, :proxy_url], {:socks5, ~c"localhost", 1234}) uri = URI.parse("https://some-domain.com") - opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri) + opts = Gun.options([receive_conn: false, proxy: {~c"example.com", 4321}], uri) - assert opts[:proxy] == {'example.com', 4321} + assert opts[:proxy] == {~c"example.com", 4321} end end end diff --git a/test/pleroma/http/adapter_helper_test.exs b/test/pleroma/http/adapter_helper_test.exs index e3c78f317..cc0e24167 100644 --- a/test/pleroma/http/adapter_helper_test.exs +++ b/test/pleroma/http/adapter_helper_test.exs @@ -17,12 +17,12 @@ defmodule Pleroma.HTTP.AdapterHelperTest do end test "localhost with port" do - assert AdapterHelper.format_proxy("localhost:8123") == {'localhost', 8123} + assert AdapterHelper.format_proxy("localhost:8123") == {~c"localhost", 8123} end test "tuple" do assert AdapterHelper.format_proxy({:socks4, :localhost, 9050}) == - {:socks4, 'localhost', 9050} + {:socks4, ~c"localhost", 9050} end end end diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs index a0ffddf8d..f499f54ad 100644 --- a/test/pleroma/integration/mastodon_websocket_test.exs +++ b/test/pleroma/integration/mastodon_websocket_test.exs @@ -404,7 +404,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "receives private statuses", %{user: reading_user, token: token} do user = insert(:user) - CommonAPI.follow(reading_user, user) + CommonAPI.follow(user, reading_user) {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") @@ -431,7 +431,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "receives edits", %{user: reading_user, token: token} do user = insert(:user) - CommonAPI.follow(reading_user, user) + CommonAPI.follow(user, reading_user) {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") @@ -440,7 +440,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do assert_receive {:text, _raw_json}, 1_000 - {:ok, _} = CommonAPI.update(user, activity, %{status: "mew mew", visibility: "private"}) + {:ok, _} = CommonAPI.update(activity, user, %{status: "mew mew", visibility: "private"}) assert_receive {:text, raw_json}, 1_000 @@ -459,7 +459,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "receives notifications", %{user: reading_user, token: token} do user = insert(:user) - CommonAPI.follow(reading_user, user) + CommonAPI.follow(user, reading_user) {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") diff --git a/test/pleroma/job_queue_monitor_test.exs b/test/pleroma/job_queue_monitor_test.exs index f2056990f..e2250d7e2 100644 --- a/test/pleroma/job_queue_monitor_test.exs +++ b/test/pleroma/job_queue_monitor_test.exs @@ -28,13 +28,13 @@ defmodule Pleroma.JobQueueMonitorTest do queue: "background", stack: [ {Pleroma.Workers.BackgroundWorker, :perform, 2, - [file: 'lib/pleroma/workers/background_worker.ex', line: 31]}, + [file: ~c"lib/pleroma/workers/background_worker.ex", line: 31]}, {Oban.Queue.Executor, :safe_call, 1, - [file: 'lib/oban/queue/executor.ex', line: 42]}, - {:timer, :tc, 3, [file: 'timer.erl', line: 197]}, - {Oban.Queue.Executor, :call, 2, [file: 'lib/oban/queue/executor.ex', line: 23]}, - {Task.Supervised, :invoke_mfa, 2, [file: 'lib/task/supervised.ex', line: 90]}, - {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]} + [file: ~c"lib/oban/queue/executor.ex", line: 42]}, + {:timer, :tc, 3, [file: ~c"timer.erl", line: 197]}, + {Oban.Queue.Executor, :call, 2, [file: ~c"lib/oban/queue/executor.ex", line: 23]}, + {Task.Supervised, :invoke_mfa, 2, [file: ~c"lib/task/supervised.ex", line: 90]}, + {:proc_lib, :init_p_do_apply, 3, [file: ~c"proc_lib.erl", line: 249]} ], worker: "Pleroma.Workers.BackgroundWorker" }} diff --git a/test/pleroma/migration_helper/notification_backfill_test.exs b/test/pleroma/migration_helper/notification_backfill_test.exs index 6d47bb6a8..2797cfb2c 100644 --- a/test/pleroma/migration_helper/notification_backfill_test.exs +++ b/test/pleroma/migration_helper/notification_backfill_test.exs @@ -21,7 +21,7 @@ defmodule Pleroma.MigrationHelper.NotificationBackfillTest do {:ok, post} = CommonAPI.post(user, %{status: "yeah, @#{other_user.nickname}"}) {:ok, chat} = CommonAPI.post_chat_message(user, other_user, "yo") {:ok, react} = CommonAPI.react_with_emoji(post.id, other_user, "☕") - {:ok, like} = CommonAPI.favorite(other_user, post.id) + {:ok, like} = CommonAPI.favorite(post.id, other_user) {:ok, react_2} = CommonAPI.react_with_emoji(post.id, other_user, "☕") data = diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 392fd53c2..e595c5c53 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -112,6 +112,7 @@ defmodule Pleroma.NotificationTest do {:ok, [notification]} = Notification.create_notifications(status) assert notification.user_id == subscriber.id + assert notification.type == "status" end test "does not create a notification for subscribed users if status is a reply" do @@ -136,6 +137,21 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(subscriber_notifications) end + test "does not create subscriber notification if mentioned" do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, status} = CommonAPI.post(user, %{status: "mentioning @#{subscriber.nickname}"}) + {:ok, [notification] = notifications} = Notification.create_notifications(status) + + assert length(notifications) == 1 + + assert notification.user_id == subscriber.id + assert notification.type == "mention" + end + test "it sends edited notifications to those who repeated a status" do user = insert(:user) repeated_user = insert(:user) @@ -149,7 +165,7 @@ defmodule Pleroma.NotificationTest do {:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user) {:ok, _edit_activity} = - CommonAPI.update(user, activity_one, %{ + CommonAPI.update(activity_one, user, %{ status: "hey @#{other_user.nickname}! mew mew" }) @@ -164,8 +180,8 @@ defmodule Pleroma.NotificationTest do question = insert(:question, user: user1) activity = insert(:question_activity, question: question) - {:ok, _, _} = CommonAPI.vote(user2, question, [0]) - {:ok, _, _} = CommonAPI.vote(user3, question, [1]) + {:ok, _, _} = CommonAPI.vote(question, user2, [0]) + {:ok, _, _} = CommonAPI.vote(question, user3, [1]) {:ok, notifications} = Notification.create_poll_notifications(activity) @@ -193,7 +209,7 @@ defmodule Pleroma.NotificationTest do notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true} ) - CommonAPI.follow(follower, followed) + CommonAPI.follow(followed, follower) {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"}) refute Notification.create_notification(activity, followed) end @@ -206,7 +222,7 @@ defmodule Pleroma.NotificationTest do notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true} ) - CommonAPI.follow(receiver, poster) + CommonAPI.follow(poster, receiver) {:ok, activity} = CommonAPI.post(poster, %{status: "hey @#{receiver.nickname}"}) assert Notification.create_notification(activity, receiver) end @@ -222,7 +238,7 @@ defmodule Pleroma.NotificationTest do user = insert(:user) subscriber = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(subscriber, user) + {:ok, _, _, _} = CommonAPI.follow(user, subscriber) User.subscribe(subscriber, user) {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"}) {:ok, [_notif]} = Notification.create_notifications(status) @@ -279,7 +295,7 @@ defmodule Pleroma.NotificationTest do insert(:filter, user: user, phrase: "tesla", hide: true) {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"}) - {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id) + {:ok, activity_two} = CommonAPI.favorite(activity_one.id, other_user) {:ok, [notification]} = Notification.create_notifications(activity_two) @@ -293,7 +309,7 @@ defmodule Pleroma.NotificationTest do user = insert(:user) followed_user = insert(:user, is_locked: false) - {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) + {:ok, _, _, _activity} = CommonAPI.follow(followed_user, user) assert FollowingRelationship.following?(user, followed_user) assert [notification] = Notification.for_user(followed_user) @@ -308,7 +324,7 @@ defmodule Pleroma.NotificationTest do user = insert(:user) followed_user = insert(:user, is_locked: true) - {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) + {:ok, _, _, _activity} = CommonAPI.follow(followed_user, user) refute FollowingRelationship.following?(user, followed_user) assert [notification] = Notification.for_user(followed_user) @@ -323,19 +339,22 @@ defmodule Pleroma.NotificationTest do |> Repo.preload(:activity) assert %{type: "follow"} = - NotificationView.render("show.json", notification: notification, for: followed_user) + NotificationView.render("show.json", + notification: notification, + for: followed_user + ) end test "it doesn't create a notification for follow-unfollow-follow chains" do user = insert(:user) followed_user = insert(:user, is_locked: false) - {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) + {:ok, _, _, _activity} = CommonAPI.follow(followed_user, user) assert FollowingRelationship.following?(user, followed_user) assert [notification] = Notification.for_user(followed_user) - CommonAPI.unfollow(user, followed_user) - {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user) + CommonAPI.unfollow(followed_user, user) + {:ok, _, _, _activity_dupe} = CommonAPI.follow(followed_user, user) notification_id = notification.id assert [%{id: ^notification_id}] = Notification.for_user(followed_user) @@ -344,7 +363,7 @@ defmodule Pleroma.NotificationTest do test "dismisses the notification on follow request rejection" do user = insert(:user, is_locked: true) follower = insert(:user) - {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user) + {:ok, _, _, _follow_activity} = CommonAPI.follow(user, follower) assert [_notification] = Notification.for_user(user) {:ok, _follower} = CommonAPI.reject_follow_request(follower, user) assert [] = Notification.for_user(user) @@ -449,9 +468,7 @@ defmodule Pleroma.NotificationTest do status: "hey yet again @#{other_user.nickname}!" }) - [_, read_notification] = Notification.set_read_up_to(other_user, n2.id) - - assert read_notification.activity.object + Notification.set_read_up_to(other_user, n2.id) [n3, n2, n1] = Notification.for_user(other_user) @@ -600,7 +617,7 @@ defmodule Pleroma.NotificationTest do status: "hey @#{other_user.nickname}!" }) - {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id) + {:ok, activity_two} = CommonAPI.favorite(activity_one.id, third_user) enabled_receivers = Notification.get_notified_from_activity(activity_two) @@ -676,7 +693,7 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"}) - {:ok, _} = CommonAPI.add_mute(other_user, activity) + {:ok, _} = CommonAPI.add_mute(activity, other_user) {:ok, same_context_activity} = CommonAPI.post(user, %{ @@ -731,7 +748,7 @@ defmodule Pleroma.NotificationTest do {:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user) {:ok, edit_activity} = - CommonAPI.update(user, activity_one, %{ + CommonAPI.update(activity_one, user, %{ status: "hey @#{other_user.nickname}! mew mew" }) @@ -751,7 +768,7 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(Notification.for_user(user)) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) assert length(Notification.for_user(user)) == 1 @@ -768,7 +785,7 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(Notification.for_user(user)) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) assert length(Notification.for_user(user)) == 1 @@ -823,7 +840,7 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(Notification.for_user(user)) - {:error, :not_found} = CommonAPI.favorite(other_user, activity.id) + {:error, :not_found} = CommonAPI.favorite(activity.id, other_user) assert Enum.empty?(Notification.for_user(user)) end @@ -845,22 +862,6 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(Notification.for_user(user)) end - test "replying to a deleted post without tagging does not generate a notification" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "test post"}) - {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user) - - {:ok, _reply_activity} = - CommonAPI.post(other_user, %{ - status: "test reply", - in_reply_to_status_id: activity.id - }) - - assert Enum.empty?(Notification.for_user(user)) - end - test "notifications are deleted if a local user is deleted" do user = insert(:user) other_user = insert(:user) @@ -1089,7 +1090,7 @@ defmodule Pleroma.NotificationTest do another_user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"}) - {:ok, _} = CommonAPI.favorite(another_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, another_user) assert length(Notification.for_user(user)) == 1 end @@ -1100,7 +1101,7 @@ defmodule Pleroma.NotificationTest do insert(:filter, user: followed_user, phrase: "test", hide: true) - {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) + {:ok, _, _, _activity} = CommonAPI.follow(followed_user, user) refute FollowingRelationship.following?(user, followed_user) assert [notification] = Notification.for_user(followed_user) diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index 6f21452a7..6704c18db 100644 --- a/test/pleroma/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -84,7 +84,6 @@ defmodule Pleroma.Object.FetcherTest do :ok end - @tag capture_log: true test "it works when fetching the OP actor errors out" do # Here we simulate a case where the author of the OP can't be read assert {:ok, _} = diff --git a/test/pleroma/object_test.exs b/test/pleroma/object_test.exs index 2025d93e4..48d4d86eb 100644 --- a/test/pleroma/object_test.exs +++ b/test/pleroma/object_test.exs @@ -403,7 +403,7 @@ defmodule Pleroma.ObjectTest do user = insert(:user) activity = Activity.get_create_by_object_ap_id(object.data["id"]) - {:ok, activity} = CommonAPI.favorite(user, activity.id) + {:ok, activity} = CommonAPI.favorite(activity.id, user) object = Object.get_by_ap_id(activity.data["object"]) assert object.data["like_count"] == 1 diff --git a/test/pleroma/resilience_test.exs b/test/pleroma/resilience_test.exs index 9dc5d0dd6..0c4195fa8 100644 --- a/test/pleroma/resilience_test.exs +++ b/test/pleroma/resilience_test.exs @@ -18,7 +18,7 @@ defmodule Pleroma.ResilienceTest do other_user = insert(:user) {:ok, post_one} = CommonAPI.post(user, %{status: "Here is a post"}) - {:ok, like} = CommonAPI.favorite(other_user, post_one.id) + {:ok, like} = CommonAPI.favorite(post_one.id, other_user) %{ user: user, @@ -90,7 +90,7 @@ defmodule Pleroma.ResilienceTest do |> json_response(200) # Favoriting again doesn't hurt - {:ok, _like_two} = CommonAPI.favorite(other_user, post.id) + {:ok, _like_two} = CommonAPI.favorite(post.id, other_user) post = Repo.get(Activity, post.id) diff --git a/test/pleroma/scheduled_activity_test.exs b/test/pleroma/scheduled_activity_test.exs index 4818e8bcf..aaf643cfc 100644 --- a/test/pleroma/scheduled_activity_test.exs +++ b/test/pleroma/scheduled_activity_test.exs @@ -31,8 +31,7 @@ defmodule Pleroma.ScheduledActivityTest do {:ok, sa1} = ScheduledActivity.create(user, attrs) {:ok, sa2} = ScheduledActivity.create(user, attrs) - jobs = - Repo.all(from(j in Oban.Job, where: j.queue == "scheduled_activities", select: j.args)) + jobs = Repo.all(from(j in Oban.Job, where: j.queue == "federator_outgoing", select: j.args)) assert jobs == [%{"activity_id" => sa1.id}, %{"activity_id" => sa2.id}] end diff --git a/test/pleroma/schema_test.exs b/test/pleroma/schema_test.exs new file mode 100644 index 000000000..9bddd2031 --- /dev/null +++ b/test/pleroma/schema_test.exs @@ -0,0 +1,17 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.SchemaTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Repo + + test "No unindexed foreign keys" do + query = File.read!("test/fixtures/unindexed_fk.sql") + + {:ok, result} = Repo.query(query) + + assert Enum.empty?(result.rows) + end +end diff --git a/test/pleroma/search/healthcheck_test.exs b/test/pleroma/search/healthcheck_test.exs new file mode 100644 index 000000000..e7649d949 --- /dev/null +++ b/test/pleroma/search/healthcheck_test.exs @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Search.HealthcheckTest do + use Pleroma.DataCase + + import Tesla.Mock + + alias Pleroma.Search.Healthcheck + + @good1 "http://good1.example.com/healthz" + @good2 "http://good2.example.com/health" + @bad "http://bad.example.com/healthy" + + setup do + mock(fn + %{method: :get, url: @good1} -> + %Tesla.Env{ + status: 200, + body: "" + } + + %{method: :get, url: @good2} -> + %Tesla.Env{ + status: 200, + body: "" + } + + %{method: :get, url: @bad} -> + %Tesla.Env{ + status: 503, + body: "" + } + end) + + :ok + end + + test "true for 200 responses" do + assert Healthcheck.check([@good1]) + assert Healthcheck.check([@good1, @good2]) + end + + test "false if any response is not a 200" do + refute Healthcheck.check([@bad]) + refute Healthcheck.check([@good1, @bad]) + end +end diff --git a/test/pleroma/search/qdrant_search_test.exs b/test/pleroma/search/qdrant_search_test.exs new file mode 100644 index 000000000..47a77a391 --- /dev/null +++ b/test/pleroma/search/qdrant_search_test.exs @@ -0,0 +1,199 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Search.QdrantSearchTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + import Mox + + alias Pleroma.Search.QdrantSearch + alias Pleroma.UnstubbedConfigMock, as: Config + alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.SearchIndexingWorker + + describe "Qdrant search" do + test "returns the correct healthcheck endpoints" do + # No openai healthcheck URL + Config + |> expect(:get, 2, fn + [Pleroma.Search.QdrantSearch, key], nil -> + %{qdrant_url: "https://qdrant.url"}[key] + end) + + [health_endpoint] = QdrantSearch.healthcheck_endpoints() + + assert "https://qdrant.url/healthz" == health_endpoint + + # Set openai healthcheck URL + Config + |> expect(:get, 2, fn + [Pleroma.Search.QdrantSearch, key], nil -> + %{qdrant_url: "https://qdrant.url", openai_healthcheck_url: "https://openai.url/health"}[ + key + ] + end) + + [_, health_endpoint] = QdrantSearch.healthcheck_endpoints() + + assert "https://openai.url/health" == health_endpoint + end + + test "searches for a term by encoding it and sending it to qdrant" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "guys i just don't wanna leave the swamp", + visibility: "public" + }) + + Config + |> expect(:get, 3, fn + [Pleroma.Search, :module], nil -> + QdrantSearch + + [Pleroma.Search.QdrantSearch, key], nil -> + %{ + openai_model: "a_model", + openai_url: "https://openai.url", + qdrant_url: "https://qdrant.url" + }[key] + end) + + Tesla.Mock.mock(fn + %{url: "https://openai.url/v1/embeddings", method: :post} -> + Tesla.Mock.json(%{ + data: [%{embedding: [1, 2, 3]}] + }) + + %{url: "https://qdrant.url/collections/posts/points/search", method: :post, body: body} -> + data = Jason.decode!(body) + refute data["filter"] + + Tesla.Mock.json(%{ + result: [%{"id" => activity.id |> FlakeId.from_string() |> Ecto.UUID.cast!()}] + }) + end) + + results = QdrantSearch.search(nil, "guys i just don't wanna leave the swamp", %{}) + + assert results == [activity] + end + + test "for a given actor, ask for only relevant matches" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "guys i just don't wanna leave the swamp", + visibility: "public" + }) + + Config + |> expect(:get, 3, fn + [Pleroma.Search, :module], nil -> + QdrantSearch + + [Pleroma.Search.QdrantSearch, key], nil -> + %{ + openai_model: "a_model", + openai_url: "https://openai.url", + qdrant_url: "https://qdrant.url" + }[key] + end) + + Tesla.Mock.mock(fn + %{url: "https://openai.url/v1/embeddings", method: :post} -> + Tesla.Mock.json(%{ + data: [%{embedding: [1, 2, 3]}] + }) + + %{url: "https://qdrant.url/collections/posts/points/search", method: :post, body: body} -> + data = Jason.decode!(body) + + assert data["filter"] == %{ + "must" => [%{"key" => "actor", "match" => %{"value" => user.ap_id}}] + } + + Tesla.Mock.json(%{ + result: [%{"id" => activity.id |> FlakeId.from_string() |> Ecto.UUID.cast!()}] + }) + end) + + results = + QdrantSearch.search(nil, "guys i just don't wanna leave the swamp", %{author: user}) + + assert results == [activity] + end + + test "indexes a public post on creation, deletes from the index on deletion" do + user = insert(:user) + + Tesla.Mock.mock(fn + %{method: :post, url: "https://openai.url/v1/embeddings"} -> + send(self(), "posted_to_openai") + + Tesla.Mock.json(%{ + data: [%{embedding: [1, 2, 3]}] + }) + + %{method: :put, url: "https://qdrant.url/collections/posts/points", body: body} -> + send(self(), "posted_to_qdrant") + + data = Jason.decode!(body) + %{"points" => [%{"vector" => vector, "payload" => payload}]} = data + + assert vector == [1, 2, 3] + assert payload["actor"] + assert payload["published_at"] + + Tesla.Mock.json("ok") + + %{method: :post, url: "https://qdrant.url/collections/posts/points/delete"} -> + send(self(), "deleted_from_qdrant") + Tesla.Mock.json("ok") + end) + + Config + |> expect(:get, 6, fn + [Pleroma.Search, :module], nil -> + QdrantSearch + + [Pleroma.Search.QdrantSearch, key], nil -> + %{ + openai_model: "a_model", + openai_url: "https://openai.url", + qdrant_url: "https://qdrant.url" + }[key] + end) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "guys i just don't wanna leave the swamp", + visibility: "public" + }) + + args = %{"op" => "add_to_index", "activity" => activity.id} + + assert_enqueued( + worker: SearchIndexingWorker, + args: args + ) + + assert :ok = perform_job(SearchIndexingWorker, args) + assert_received("posted_to_openai") + assert_received("posted_to_qdrant") + + {:ok, _} = CommonAPI.delete(activity.id, user) + + delete_args = %{"op" => "remove_from_index", "object" => activity.object.id} + assert_enqueued(worker: SearchIndexingWorker, args: delete_args) + assert :ok = perform_job(SearchIndexingWorker, delete_args) + + assert_received("deleted_from_qdrant") + end + end +end diff --git a/test/pleroma/signature_test.exs b/test/pleroma/signature_test.exs index 8edf67a7b..572d7acc3 100644 --- a/test/pleroma/signature_test.exs +++ b/test/pleroma/signature_test.exs @@ -67,6 +67,14 @@ defmodule Pleroma.SignatureTest do end end + describe "get_actor_id/1" do + test "it returns actor id" do + ap_id = "https://mastodon.social/users/lambadalambda" + + assert Signature.get_actor_id(make_fake_conn(ap_id)) == {:ok, ap_id} + end + end + describe "sign/2" do test "it returns signature headers" do user = diff --git a/test/pleroma/stats_test.exs b/test/pleroma/stats_test.exs index 37a085afc..c70603ab9 100644 --- a/test/pleroma/stats_test.exs +++ b/test/pleroma/stats_test.exs @@ -73,8 +73,8 @@ defmodule Pleroma.StatsTest do user = insert(:user) other_user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"}) - _ = CommonAPI.follow(user, other_user) - CommonAPI.favorite(other_user, activity.id) + _ = CommonAPI.follow(other_user, user) + CommonAPI.favorite(activity.id, other_user) CommonAPI.repeat(activity.id, other_user) assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 0} = diff --git a/test/pleroma/upload/filter/exiftool/strip_location_test.exs b/test/pleroma/upload/filter/exiftool/strip_location_test.exs index bcb5f3f60..4dcd4dce3 100644 --- a/test/pleroma/upload/filter/exiftool/strip_location_test.exs +++ b/test/pleroma/upload/filter/exiftool/strip_location_test.exs @@ -9,29 +9,31 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocationTest do test "apply exiftool filter" do assert Pleroma.Utils.command_available?("exiftool") - File.cp!( - "test/fixtures/DSCN0010.jpg", - "test/fixtures/DSCN0010_tmp.jpg" - ) - - upload = %Pleroma.Upload{ - name: "image_with_GPS_data.jpg", - content_type: "image/jpeg", - path: Path.absname("test/fixtures/DSCN0010.jpg"), - tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg") - } - - assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered} - - {exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"]) - {exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"]) - - refute exif_original == exif_filtered - assert String.match?(exif_original, ~r/GPS/) - refute String.match?(exif_filtered, ~r/GPS/) + ~w{jpg png} + |> Enum.map(fn type -> + File.cp!( + "test/fixtures/DSCN0010.#{type}", + "test/fixtures/DSCN0010_tmp.#{type}" + ) + + upload = %Pleroma.Upload{ + name: "image_with_GPS_data.#{type}", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/DSCN0010.#{type}"), + tempfile: Path.absname("test/fixtures/DSCN0010_tmp.#{type}") + } + + assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered} + + {exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.#{type}"]) + {exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.#{type}"]) + + assert String.match?(exif_original, ~r/GPS/) + refute String.match?(exif_filtered, ~r/GPS/) + end) end - test "verify webp, heic, svg files are skipped" do + test "verify webp, heic, svg files are skipped" do uploads = ~w{webp heic svg svg+xml} |> Enum.map(fn type -> diff --git a/test/pleroma/uploaders/ipfs_test.exs b/test/pleroma/uploaders/ipfs_test.exs new file mode 100644 index 000000000..bdf2933ac --- /dev/null +++ b/test/pleroma/uploaders/ipfs_test.exs @@ -0,0 +1,155 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Uploaders.IPFSTest do + use Pleroma.DataCase + + alias Pleroma.Uploaders.IPFS + alias Tesla.Multipart + + import ExUnit.CaptureLog + import Mock + import Mox + + alias Pleroma.UnstubbedConfigMock, as: Config + + describe "get_file/1" do + setup do + Config + |> expect(:get, fn [Pleroma.Upload, :uploader] -> Pleroma.Uploaders.IPFS end) + |> expect(:get, fn [Pleroma.Upload, :base_url] -> nil end) + |> expect(:get, fn [Pleroma.Uploaders.IPFS, :public_endpoint] -> nil end) + + :ok + end + + test "it returns path to ipfs file with cid as subdomain" do + Config + |> expect(:get, fn [Pleroma.Uploaders.IPFS, :get_gateway_url] -> + "https://{CID}.ipfs.mydomain.com" + end) + + assert IPFS.get_file("testcid") == { + :ok, + {:url, "https://testcid.ipfs.mydomain.com"} + } + end + + test "it returns path to ipfs file with cid as path" do + Config + |> expect(:get, fn [Pleroma.Uploaders.IPFS, :get_gateway_url] -> + "https://ipfs.mydomain.com/ipfs/{CID}" + end) + + assert IPFS.get_file("testcid") == { + :ok, + {:url, "https://ipfs.mydomain.com/ipfs/testcid"} + } + end + end + + describe "put_file/1" do + setup do + Config + |> expect(:get, fn [Pleroma.Uploaders.IPFS, :post_gateway_url] -> + "http://localhost:5001" + end) + + file_upload = %Pleroma.Upload{ + name: "image-tet.jpg", + content_type: "image/jpeg", + path: "test_folder/image-tet.jpg", + tempfile: Path.absname("test/instance_static/add/shortcode.png") + } + + mp = + Multipart.new() + |> Multipart.add_content_type_param("charset=utf-8") + |> Multipart.add_file(file_upload.tempfile) + + [file_upload: file_upload, mp: mp] + end + + test "save file", %{file_upload: file_upload} do + with_mock Pleroma.HTTP, + post: fn "http://localhost:5001/api/v0/add", + _mp, + [], + params: ["cid-version": "1"], + pool: :upload -> + {:ok, + %Tesla.Env{ + status: 200, + body: + "{\"Name\":\"image-tet.jpg\",\"Size\":\"5000\", \"Hash\":\"bafybeicrh7ltzx52yxcwrvxxckfmwhqdgsb6qym6dxqm2a4ymsakeshwoi\"}" + }} + end do + assert IPFS.put_file(file_upload) == + {:ok, {:file, "bafybeicrh7ltzx52yxcwrvxxckfmwhqdgsb6qym6dxqm2a4ymsakeshwoi"}} + end + end + + test "returns error", %{file_upload: file_upload} do + with_mock Pleroma.HTTP, + post: fn "http://localhost:5001/api/v0/add", + _mp, + [], + params: ["cid-version": "1"], + pool: :upload -> + {:error, "IPFS Gateway upload failed"} + end do + assert capture_log(fn -> + assert IPFS.put_file(file_upload) == {:error, "IPFS Gateway upload failed"} + end) =~ "Elixir.Pleroma.Uploaders.IPFS: {:error, \"IPFS Gateway upload failed\"}" + end + end + + test "returns error if JSON decode fails", %{file_upload: file_upload} do + with_mock Pleroma.HTTP, [], + post: fn "http://localhost:5001/api/v0/add", + _mp, + [], + params: ["cid-version": "1"], + pool: :upload -> + {:ok, %Tesla.Env{status: 200, body: "invalid"}} + end do + assert capture_log(fn -> + assert IPFS.put_file(file_upload) == {:error, "JSON decode failed"} + end) =~ + "Elixir.Pleroma.Uploaders.IPFS: {:error, %Jason.DecodeError" + end + end + + test "returns error if JSON body doesn't contain Hash key", %{file_upload: file_upload} do + with_mock Pleroma.HTTP, [], + post: fn "http://localhost:5001/api/v0/add", + _mp, + [], + params: ["cid-version": "1"], + pool: :upload -> + {:ok, %Tesla.Env{status: 200, body: "{\"key\": \"value\"}"}} + end do + assert IPFS.put_file(file_upload) == {:error, "JSON doesn't contain Hash key"} + end + end + end + + describe "delete_file/1" do + setup do + Config + |> expect(:get, fn [Pleroma.Uploaders.IPFS, :post_gateway_url] -> + "http://localhost:5001" + end) + + :ok + end + + test_with_mock "deletes file", Pleroma.HTTP, + post: fn "http://localhost:5001/api/v0/files/rm", "", [], params: [arg: "image.jpg"] -> + {:ok, %{status: 204}} + end do + assert :ok = IPFS.delete_file("image.jpg") + end + end +end diff --git a/test/pleroma/user/backup_async_test.exs b/test/pleroma/user/backup_async_test.exs index 76716d684..b0e9413be 100644 --- a/test/pleroma/user/backup_async_test.exs +++ b/test/pleroma/user/backup_async_test.exs @@ -19,7 +19,6 @@ defmodule Pleroma.User.BackupAsyncTest do %{backup: backup} end - @tag capture_log: true test "it handles unrecoverable exceptions", %{backup: backup} do ProcessorMock |> expect(:do_process, fn _, _ -> @@ -34,7 +33,6 @@ defmodule Pleroma.User.BackupAsyncTest do assert backup.state == :failed end - @tag capture_log: true test "it handles timeouts", %{backup: backup} do ProcessorMock |> expect(:do_process, fn _, _ -> diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs index 5503d15bc..d82d1719b 100644 --- a/test/pleroma/user/backup_test.exs +++ b/test/pleroma/user/backup_test.exs @@ -177,18 +177,18 @@ defmodule Pleroma.User.BackupTest do {:ok, %{object: %{data: %{"id" => id3}}} = status3} = CommonAPI.post(user, %{status: "status3"}) - CommonAPI.favorite(user, status1.id) - CommonAPI.favorite(user, status2.id) + CommonAPI.favorite(status1.id, user) + CommonAPI.favorite(status2.id, user) Bookmark.create(user.id, status2.id) Bookmark.create(user.id, status3.id) - CommonAPI.follow(user, other_user) + CommonAPI.follow(other_user, user) assert {:ok, backup} = user |> Backup.new() |> Repo.insert() assert {:ok, path} = Backup.export(backup, self()) assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory]) - assert {:ok, {'actor.json', json}} = :zip.zip_get('actor.json', zipfile) + assert {:ok, {~c"actor.json", json}} = :zip.zip_get(~c"actor.json", zipfile) assert %{ "@context" => [ @@ -213,7 +213,7 @@ defmodule Pleroma.User.BackupTest do "url" => "http://cofe.io/users/cofe" } = Jason.decode!(json) - assert {:ok, {'outbox.json', json}} = :zip.zip_get('outbox.json', zipfile) + assert {:ok, {~c"outbox.json", json}} = :zip.zip_get(~c"outbox.json", zipfile) assert %{ "@context" => "https://www.w3.org/ns/activitystreams", @@ -244,7 +244,7 @@ defmodule Pleroma.User.BackupTest do "type" => "OrderedCollection" } = Jason.decode!(json) - assert {:ok, {'likes.json', json}} = :zip.zip_get('likes.json', zipfile) + assert {:ok, {~c"likes.json", json}} = :zip.zip_get(~c"likes.json", zipfile) assert %{ "@context" => "https://www.w3.org/ns/activitystreams", @@ -254,7 +254,7 @@ defmodule Pleroma.User.BackupTest do "type" => "OrderedCollection" } = Jason.decode!(json) - assert {:ok, {'bookmarks.json', json}} = :zip.zip_get('bookmarks.json', zipfile) + assert {:ok, {~c"bookmarks.json", json}} = :zip.zip_get(~c"bookmarks.json", zipfile) assert %{ "@context" => "https://www.w3.org/ns/activitystreams", @@ -264,7 +264,7 @@ defmodule Pleroma.User.BackupTest do "type" => "OrderedCollection" } = Jason.decode!(json) - assert {:ok, {'following.json', json}} = :zip.zip_get('following.json', zipfile) + assert {:ok, {~c"following.json", json}} = :zip.zip_get(~c"following.json", zipfile) assert %{ "@context" => "https://www.w3.org/ns/activitystreams", @@ -283,7 +283,7 @@ defmodule Pleroma.User.BackupTest do Enum.map(1..120, fn i -> {:ok, status} = CommonAPI.post(user, %{status: "status #{i}"}) - CommonAPI.favorite(user, status.id) + CommonAPI.favorite(status.id, user) Bookmark.create(user.id, status.id) end) @@ -337,8 +337,8 @@ defmodule Pleroma.User.BackupTest do {:ok, status1} = CommonAPI.post(user, %{status: "status1"}) {:ok, status2} = CommonAPI.post(user, %{status: "status2"}) {:ok, status3} = CommonAPI.post(user, %{status: "status3"}) - CommonAPI.favorite(user, status1.id) - CommonAPI.favorite(user, status2.id) + CommonAPI.favorite(status1.id, user) + CommonAPI.favorite(status2.id, user) Bookmark.create(user.id, status2.id) Bookmark.create(user.id, status3.id) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index a93f81659..036ae78fb 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -182,8 +182,8 @@ defmodule Pleroma.UserTest do locked = insert(:user, is_locked: true) follower = insert(:user) - CommonAPI.follow(follower, unlocked) - CommonAPI.follow(follower, locked) + CommonAPI.follow(unlocked, follower) + CommonAPI.follow(locked, follower) assert [] = User.get_follow_requests(unlocked) assert [activity] = User.get_follow_requests(locked) @@ -196,9 +196,9 @@ defmodule Pleroma.UserTest do pending_follower = insert(:user) accepted_follower = insert(:user) - CommonAPI.follow(pending_follower, locked) - CommonAPI.follow(pending_follower, locked) - CommonAPI.follow(accepted_follower, locked) + CommonAPI.follow(locked, pending_follower) + CommonAPI.follow(locked, pending_follower) + CommonAPI.follow(locked, accepted_follower) Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept) @@ -209,7 +209,7 @@ defmodule Pleroma.UserTest do locked = insert(:user, is_locked: true) pending_follower = insert(:user, %{is_active: false}) - CommonAPI.follow(pending_follower, locked) + CommonAPI.follow(locked, pending_follower) refute pending_follower.is_active assert [] = User.get_follow_requests(locked) @@ -219,7 +219,7 @@ defmodule Pleroma.UserTest do followed = insert(:user, is_locked: true) follower = insert(:user) - CommonAPI.follow(follower, followed) + CommonAPI.follow(followed, follower) assert [_activity] = User.get_follow_requests(followed) {:ok, _user_relationship} = User.block(followed, follower) @@ -877,109 +877,19 @@ defmodule Pleroma.UserTest do setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true) test "for mastodon" do - Tesla.Mock.mock(fn - %{url: "https://example.com/.well-known/host-meta"} -> - %Tesla.Env{ - status: 302, - headers: [{"location", "https://sub.example.com/.well-known/host-meta"}] - } - - %{url: "https://sub.example.com/.well-known/host-meta"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/masto-host-meta.xml" - |> File.read!() - |> String.replace("{{domain}}", "sub.example.com") - } - - %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/masto-webfinger.json" - |> File.read!() - |> String.replace("{{nickname}}", "a") - |> String.replace("{{domain}}", "example.com") - |> String.replace("{{subdomain}}", "sub.example.com"), - headers: [{"content-type", "application/jrd+json"}] - } - - %{url: "https://sub.example.com/users/a"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/masto-user.json" - |> File.read!() - |> String.replace("{{nickname}}", "a") - |> String.replace("{{domain}}", "sub.example.com"), - headers: [{"content-type", "application/activity+json"}] - } - - %{url: "https://sub.example.com/users/a/collections/featured"} -> - %Tesla.Env{ - status: 200, - body: - File.read!("test/fixtures/users_mock/masto_featured.json") - |> String.replace("{{domain}}", "sub.example.com") - |> String.replace("{{nickname}}", "a"), - headers: [{"content-type", "application/activity+json"}] - } - end) - - ap_id = "a@example.com" + ap_id = "a@mastodon.example" {:ok, fetched_user} = User.get_or_fetch(ap_id) - assert fetched_user.ap_id == "https://sub.example.com/users/a" - assert fetched_user.nickname == "a@example.com" + assert fetched_user.ap_id == "https://sub.mastodon.example/users/a" + assert fetched_user.nickname == "a@mastodon.example" end test "for pleroma" do - Tesla.Mock.mock(fn - %{url: "https://example.com/.well-known/host-meta"} -> - %Tesla.Env{ - status: 302, - headers: [{"location", "https://sub.example.com/.well-known/host-meta"}] - } - - %{url: "https://sub.example.com/.well-known/host-meta"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/pleroma-host-meta.xml" - |> File.read!() - |> String.replace("{{domain}}", "sub.example.com") - } - - %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/pleroma-webfinger.json" - |> File.read!() - |> String.replace("{{nickname}}", "a") - |> String.replace("{{domain}}", "example.com") - |> String.replace("{{subdomain}}", "sub.example.com"), - headers: [{"content-type", "application/jrd+json"}] - } - - %{url: "https://sub.example.com/users/a"} -> - %Tesla.Env{ - status: 200, - body: - "test/fixtures/webfinger/pleroma-user.json" - |> File.read!() - |> String.replace("{{nickname}}", "a") - |> String.replace("{{domain}}", "sub.example.com"), - headers: [{"content-type", "application/activity+json"}] - } - end) - - ap_id = "a@example.com" + ap_id = "a@pleroma.example" {:ok, fetched_user} = User.get_or_fetch(ap_id) - assert fetched_user.ap_id == "https://sub.example.com/users/a" - assert fetched_user.nickname == "a@example.com" + assert fetched_user.ap_id == "https://sub.pleroma.example/users/a" + assert fetched_user.nickname == "a@pleroma.example" end end @@ -1016,7 +926,6 @@ defmodule Pleroma.UserTest do assert user == fetched_user end - @tag capture_log: true test "returns nil if no user could be fetched" do {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent@social.heldscal.la") assert fetched_user == "not found nonexistent@social.heldscal.la" @@ -1043,9 +952,16 @@ defmodule Pleroma.UserTest do {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin") - assert user.inbox + # Oban job was generated to refresh the stale user + assert_enqueued(worker: "Pleroma.Workers.UserRefreshWorker", args: %{"ap_id" => user.ap_id}) + + # Run job to refresh the user; just capture its output instead of fetching it again + assert {:ok, updated_user} = + perform_job(Pleroma.Workers.UserRefreshWorker, %{"ap_id" => user.ap_id}) + + assert updated_user.inbox - refute user.last_refreshed_at == orig_user.last_refreshed_at + refute updated_user.last_refreshed_at == orig_user.last_refreshed_at end test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do @@ -1073,7 +989,6 @@ defmodule Pleroma.UserTest do assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org" end - @tag capture_log: true test "it returns the old user if stale, but unfetchable" do a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800) @@ -1611,7 +1526,7 @@ defmodule Pleroma.UserTest do assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark) - assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] == + assert [%{activity | thread_muted?: CommonAPI.thread_muted?(activity, user2)}] == ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{ user: user2 }) @@ -1776,8 +1691,8 @@ defmodule Pleroma.UserTest do object_two = insert(:note, user: follower) activity_two = insert(:note_activity, user: follower, note: object_two) - {:ok, like} = CommonAPI.favorite(user, activity_two.id) - {:ok, like_two} = CommonAPI.favorite(follower, activity.id) + {:ok, like} = CommonAPI.favorite(activity_two.id, user) + {:ok, like_two} = CommonAPI.favorite(activity.id, follower) {:ok, repeat} = CommonAPI.repeat(activity_two.id, user) {:ok, job} = User.delete(user) @@ -2894,6 +2809,20 @@ defmodule Pleroma.UserTest do end end + describe "get_familiar_followers/3" do + test "returns familiar followers for a pair of users" do + user1 = insert(:user) + %{id: id2} = user2 = insert(:user) + user3 = insert(:user) + _user4 = insert(:user) + + User.follow(user1, user2) + User.follow(user2, user3) + + assert [%{id: ^id2}] = User.get_familiar_followers(user3, user1) + end + end + describe "account endorsements" do test "it pins people" do user = insert(:user) diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index ec4c04c62..6aae61835 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -573,7 +573,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Activity.get_by_ap_id(data["id"]) end - @tag capture_log: true test "it inserts an incoming activity into the database" <> "even if we can't fetch the user but have it in our db", %{conn: conn} do @@ -657,7 +656,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert_receive {:mix_shell, :info, ["https://relay.mastodon.host/actor"]} end - @tag capture_log: true test "without valid signature, " <> "it only accepts Create activities and requires enabled federation", %{conn: conn} do @@ -1080,7 +1078,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Instances.reachable?(sender_host) end - @tag capture_log: true test "it removes all follower collections but actor's", %{conn: conn} do [actor, recipient] = insert_pair(:user) @@ -1143,7 +1140,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert json_response(ret_conn, 200) end - @tag capture_log: true test "forwarded report", %{conn: conn} do admin = insert(:user, is_admin: true) actor = insert(:user, local: false) @@ -1219,7 +1215,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do ) end - @tag capture_log: true test "forwarded report from mastodon", %{conn: conn} do admin = insert(:user, is_admin: true) actor = insert(:user, local: false) @@ -1229,7 +1224,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do note = insert(:note_activity, user: reported_user) - Pleroma.Web.CommonAPI.favorite(another, note.id) + Pleroma.Web.CommonAPI.favorite(note.id, another) mock_json_body = "test/fixtures/mastodon/application_actor.json" @@ -1407,7 +1402,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert question = Object.normalize(activity, fetch: false) - {:ok, [activity], _object} = CommonAPI.vote(voter, question, [1]) + {:ok, [activity], _object} = CommonAPI.vote(question, voter, [1]) assert outbox_get = conn @@ -1752,7 +1747,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do %{conn: conn} do user = insert(:user, hide_followers: true) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) result = conn @@ -1848,7 +1843,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do %{conn: conn} do user = insert(:user, hide_follows: true) other_user = insert(:user) - {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, user, _other_user, _activity} = CommonAPI.follow(other_user, user) result = conn diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 524294385..b4f6fb68a 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -291,9 +291,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do body: featured_data, headers: [{"content-type", "application/activity+json"}] } - end) - Tesla.Mock.mock_global(fn %{ method: :get, url: ^object_url @@ -306,7 +304,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end) {:ok, user} = ActivityPub.make_user_from_ap_id(ap_id) - Process.sleep(50) + + assert_enqueued( + worker: Pleroma.Workers.RemoteFetcherWorker, + args: %{ + "op" => "fetch_remote", + "id" => object_url, + "depth" => 1 + } + ) + + # wait for oban + Pleroma.Tests.ObanHelpers.perform_all() assert user.featured_address == featured_url assert Map.has_key?(user.pinned_objects, object_url) @@ -368,9 +377,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do body: featured_data, headers: [{"content-type", "application/activity+json"}] } - end) - Tesla.Mock.mock_global(fn %{ method: :get, url: ^object_url @@ -383,7 +390,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end) {:ok, user} = ActivityPub.make_user_from_ap_id(ap_id) - Process.sleep(50) + + assert_enqueued( + worker: Pleroma.Workers.RemoteFetcherWorker, + args: %{ + "op" => "fetch_remote", + "id" => object_url, + "depth" => 1 + } + ) + + # wait for oban + Pleroma.Tests.ObanHelpers.perform_all() assert user.featured_address == featured_url assert Map.has_key?(user.pinned_objects, object_url) @@ -1020,7 +1038,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do refute activity in activities followed_user = insert(:user) - CommonAPI.follow(user, followed_user) + CommonAPI.follow(followed_user, user) {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user) activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) @@ -1153,7 +1171,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do note_two = insert(:note, data: %{"context" => "suya.."}) activity_two = insert(:note_activity, note: note_two) - {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) + {:ok, _activity_two} = CommonAPI.add_mute(activity_two, user) assert [_activity_one] = ActivityPub.fetch_activities([], %{muting_user: user}) end @@ -1164,7 +1182,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do note_two = insert(:note, data: %{"context" => "suya.."}) activity_two = insert(:note_activity, note: note_two) - {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) + {:ok, _activity_two} = CommonAPI.add_mute(activity_two, user) assert [_activity_two, _activity_one] = ActivityPub.fetch_activities([], %{muting_user: user, with_muted: true}) @@ -1340,7 +1358,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do activity = insert(:note_activity) user = insert(:user) booster = insert(:user) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) + {:ok, _reblog_mute} = CommonAPI.hide_reblogs(booster, user) {:ok, activity} = CommonAPI.repeat(activity.id, booster) @@ -1353,8 +1371,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do activity = insert(:note_activity) user = insert(:user) booster = insert(:user) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) - {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster) + {:ok, _reblog_mute} = CommonAPI.hide_reblogs(booster, user) + {:ok, _reblog_mute} = CommonAPI.show_reblogs(booster, user) {:ok, activity} = CommonAPI.repeat(activity.id, booster) @@ -1434,7 +1452,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do follower = insert(:user) followed = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do assert {:error, :reverted} = ActivityPub.unfollow(follower, followed) @@ -1451,7 +1469,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do follower = insert(:user) followed = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) {:ok, activity} = ActivityPub.unfollow(follower, followed) assert activity.data["type"] == "Undo" @@ -1468,7 +1486,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do follower = insert(:user) followed = insert(:user, %{is_locked: true}) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) {:ok, activity} = ActivityPub.unfollow(follower, followed) assert activity.data["type"] == "Undo" @@ -1836,14 +1854,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do {:ok, a4} = CommonAPI.post(user2, %{status: "Agent Smith "}) {:ok, a5} = CommonAPI.post(user1, %{status: "Red or Blue "}) - {:ok, _} = CommonAPI.favorite(user, a4.id) - {:ok, _} = CommonAPI.favorite(other_user, a3.id) - {:ok, _} = CommonAPI.favorite(user, a3.id) - {:ok, _} = CommonAPI.favorite(other_user, a5.id) - {:ok, _} = CommonAPI.favorite(user, a5.id) - {:ok, _} = CommonAPI.favorite(other_user, a4.id) - {:ok, _} = CommonAPI.favorite(user, a1.id) - {:ok, _} = CommonAPI.favorite(other_user, a1.id) + {:ok, _} = CommonAPI.favorite(a4.id, user) + {:ok, _} = CommonAPI.favorite(a3.id, other_user) + {:ok, _} = CommonAPI.favorite(a3.id, user) + {:ok, _} = CommonAPI.favorite(a5.id, other_user) + {:ok, _} = CommonAPI.favorite(a5.id, user) + {:ok, _} = CommonAPI.favorite(a4.id, other_user) + {:ok, _} = CommonAPI.favorite(a1.id, user) + {:ok, _} = CommonAPI.favorite(a1.id, other_user) result = ActivityPub.fetch_favourites(user) assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id] @@ -2687,7 +2705,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert user.name == " " end - @tag capture_log: true test "pin_data_from_featured_collection will ignore unsupported values" do assert %{} == ActivityPub.pin_data_from_featured_collection(%{ diff --git a/test/pleroma/web/activity_pub/mrf/anti_mention_spam_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_mention_spam_policy_test.exs new file mode 100644 index 000000000..63947858c --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/anti_mention_spam_policy_test.exs @@ -0,0 +1,65 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.AntiMentionSpamPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.Web.ActivityPub.MRF.AntiMentionSpamPolicy + + test "it allows posts without mentions" do + user = insert(:user, local: false) + assert user.note_count == 0 + + message = %{ + "type" => "Create", + "actor" => user.ap_id + } + + {:ok, _message} = AntiMentionSpamPolicy.filter(message) + end + + test "it allows posts from users with followers, posts, and age" do + user = + insert(:user, + local: false, + follower_count: 1, + note_count: 1, + inserted_at: ~N[1970-01-01 00:00:00] + ) + + message = %{ + "type" => "Create", + "actor" => user.ap_id + } + + {:ok, _message} = AntiMentionSpamPolicy.filter(message) + end + + test "it allows posts from local users" do + user = insert(:user, local: true) + + message = %{ + "type" => "Create", + "actor" => user.ap_id + } + + {:ok, _message} = AntiMentionSpamPolicy.filter(message) + end + + test "it rejects posts with mentions from users without followers" do + user = insert(:user, local: false, follower_count: 0) + + message = %{ + "type" => "Create", + "actor" => user.ap_id, + "object" => %{ + "to" => ["https://pleroma.soykaf.com/users/1"], + "cc" => ["https://pleroma.soykaf.com/users/1"], + "actor" => user.ap_id + } + } + + {:reject, _message} = AntiMentionSpamPolicy.filter(message) + end +end diff --git a/test/pleroma/web/activity_pub/mrf/nsfw_api_policy_test.exs b/test/pleroma/web/activity_pub/mrf/nsfw_api_policy_test.exs new file mode 100644 index 000000000..0beb9c2cb --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/nsfw_api_policy_test.exs @@ -0,0 +1,267 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.NsfwApiPolicyTest do + use Pleroma.DataCase + + import ExUnit.CaptureLog + import Pleroma.Factory + + alias Pleroma.Constants + alias Pleroma.Web.ActivityPub.MRF.NsfwApiPolicy + + require Pleroma.Constants + + @policy :mrf_nsfw_api + + @sfw_url "https://kittens.co/kitty.gif" + @nsfw_url "https://b00bies.com/nsfw.jpg" + @timeout_url "http://time.out/i.jpg" + + setup_all do + clear_config(@policy, + url: "http://127.0.0.1:5000/", + threshold: 0.7, + mark_sensitive: true, + unlist: false, + reject: false + ) + end + + setup do + Tesla.Mock.mock(fn + # NSFW URL + %{method: :get, url: "http://127.0.0.1:5000/?url=#{@nsfw_url}"} -> + %Tesla.Env{status: 200, body: ~s({"score":0.99772077798843384,"url":"#{@nsfw_url}"})} + + # SFW URL + %{method: :get, url: "http://127.0.0.1:5000/?url=#{@sfw_url}"} -> + %Tesla.Env{status: 200, body: ~s({"score":0.00011714912398019806,"url":"#{@sfw_url}"})} + + # Timeout URL + %{method: :get, url: "http://127.0.0.1:5000/?url=#{@timeout_url}"} -> + {:error, :timeout} + + # Fallback URL + %{method: :get, url: "http://127.0.0.1:5000/?url=" <> url} -> + body = + ~s({"error_code":500,"error_reason":"[Errno -2] Name or service not known","url":"#{url}"}) + + %Tesla.Env{status: 500, body: body} + end) + + :ok + end + + describe "build_request_url/1" do + test "it works" do + expected = "http://127.0.0.1:5000/?url=https://b00bies.com/nsfw.jpg" + assert NsfwApiPolicy.build_request_url(@nsfw_url) == expected + end + + test "it adds a trailing slash" do + clear_config([@policy, :url], "http://localhost:5000") + + expected = "http://localhost:5000/?url=https://b00bies.com/nsfw.jpg" + assert NsfwApiPolicy.build_request_url(@nsfw_url) == expected + end + + test "it adds a trailing slash preserving the path" do + clear_config([@policy, :url], "http://localhost:5000/nsfw_api") + + expected = "http://localhost:5000/nsfw_api/?url=https://b00bies.com/nsfw.jpg" + assert NsfwApiPolicy.build_request_url(@nsfw_url) == expected + end + end + + describe "parse_url/1" do + test "returns decoded JSON from the API server" do + expected = %{"score" => 0.99772077798843384, "url" => @nsfw_url} + assert NsfwApiPolicy.parse_url(@nsfw_url) == {:ok, expected} + end + + test "warns when the API server fails" do + expected = "[NsfwApiPolicy]: The API server failed. Skipping." + assert capture_log(fn -> NsfwApiPolicy.parse_url(@timeout_url) end) =~ expected + end + + test "returns {:error, _} tuple when the API server fails" do + capture_log(fn -> + assert {:error, _} = NsfwApiPolicy.parse_url(@timeout_url) + end) + end + end + + describe "check_url_nsfw/1" do + test "returns {:nsfw, _} tuple" do + expected = {:nsfw, %{url: @nsfw_url, score: 0.99772077798843384, threshold: 0.7}} + assert NsfwApiPolicy.check_url_nsfw(@nsfw_url) == expected + end + + test "returns {:sfw, _} tuple" do + expected = {:sfw, %{url: @sfw_url, score: 0.00011714912398019806, threshold: 0.7}} + assert NsfwApiPolicy.check_url_nsfw(@sfw_url) == expected + end + + test "returns {:sfw, _} on failure" do + expected = {:sfw, %{url: @timeout_url, score: nil, threshold: 0.7}} + + capture_log(fn -> + assert NsfwApiPolicy.check_url_nsfw(@timeout_url) == expected + end) + end + + test "works with map URL" do + expected = {:nsfw, %{url: @nsfw_url, score: 0.99772077798843384, threshold: 0.7}} + assert NsfwApiPolicy.check_url_nsfw(%{"href" => @nsfw_url}) == expected + end + end + + describe "check_attachment_nsfw/1" do + test "returns {:nsfw, _} if any items are NSFW" do + attachment = %{"url" => [%{"href" => @nsfw_url}, @nsfw_url, @sfw_url]} + assert NsfwApiPolicy.check_attachment_nsfw(attachment) == {:nsfw, attachment} + end + + test "returns {:sfw, _} if all items are SFW" do + attachment = %{"url" => [%{"href" => @sfw_url}, @sfw_url, @sfw_url]} + assert NsfwApiPolicy.check_attachment_nsfw(attachment) == {:sfw, attachment} + end + + test "works with binary URL" do + attachment = %{"url" => @nsfw_url} + assert NsfwApiPolicy.check_attachment_nsfw(attachment) == {:nsfw, attachment} + end + end + + describe "check_object_nsfw/1" do + test "returns {:nsfw, _} if any items are NSFW" do + object = %{"attachment" => [%{"url" => [%{"href" => @nsfw_url}, @sfw_url]}]} + assert NsfwApiPolicy.check_object_nsfw(object) == {:nsfw, object} + end + + test "returns {:sfw, _} if all items are SFW" do + object = %{"attachment" => [%{"url" => [%{"href" => @sfw_url}, @sfw_url]}]} + assert NsfwApiPolicy.check_object_nsfw(object) == {:sfw, object} + end + + test "works with embedded object" do + object = %{"object" => %{"attachment" => [%{"url" => [%{"href" => @nsfw_url}, @sfw_url]}]}} + assert NsfwApiPolicy.check_object_nsfw(object) == {:nsfw, object} + end + end + + describe "unlist/1" do + test "unlist addressing" do + user = insert(:user) + + object = %{ + "to" => [Constants.as_public()], + "cc" => [user.follower_address, "https://hello.world/users/alex"], + "actor" => user.ap_id + } + + expected = %{ + "to" => [user.follower_address], + "cc" => [Constants.as_public(), "https://hello.world/users/alex"], + "actor" => user.ap_id + } + + assert NsfwApiPolicy.unlist(object) == expected + end + + test "raise if user isn't found" do + object = %{ + "to" => [Constants.as_public()], + "cc" => [], + "actor" => "https://hello.world/users/alex" + } + + assert_raise(RuntimeError, fn -> + NsfwApiPolicy.unlist(object) + end) + end + end + + describe "mark_sensitive/1" do + test "adds nsfw tag and marks sensitive" do + object = %{"tag" => ["yolo"]} + expected = %{"tag" => ["yolo", "nsfw"], "sensitive" => true} + assert NsfwApiPolicy.mark_sensitive(object) == expected + end + + test "works with embedded object" do + object = %{"object" => %{"tag" => ["yolo"]}} + expected = %{"object" => %{"tag" => ["yolo", "nsfw"], "sensitive" => true}} + assert NsfwApiPolicy.mark_sensitive(object) == expected + end + end + + describe "filter/1" do + setup do + user = insert(:user) + + nsfw_object = %{ + "to" => [Constants.as_public()], + "cc" => [user.follower_address], + "actor" => user.ap_id, + "attachment" => [%{"url" => @nsfw_url}] + } + + sfw_object = %{ + "to" => [Constants.as_public()], + "cc" => [user.follower_address], + "actor" => user.ap_id, + "attachment" => [%{"url" => @sfw_url}] + } + + %{user: user, nsfw_object: nsfw_object, sfw_object: sfw_object} + end + + test "passes SFW object through", %{sfw_object: object} do + {:ok, _} = NsfwApiPolicy.filter(object) + end + + test "passes NSFW object through when actions are disabled", %{nsfw_object: object} do + clear_config([@policy, :mark_sensitive], false) + clear_config([@policy, :unlist], false) + clear_config([@policy, :reject], false) + {:ok, _} = NsfwApiPolicy.filter(object) + end + + test "passes NSFW object through when :threshold is 1", %{nsfw_object: object} do + clear_config([@policy, :reject], true) + clear_config([@policy, :threshold], 1) + {:ok, _} = NsfwApiPolicy.filter(object) + end + + test "rejects SFW object through when :threshold is 0", %{sfw_object: object} do + clear_config([@policy, :reject], true) + clear_config([@policy, :threshold], 0) + {:reject, _} = NsfwApiPolicy.filter(object) + end + + test "rejects NSFW when :reject is enabled", %{nsfw_object: object} do + clear_config([@policy, :reject], true) + {:reject, _} = NsfwApiPolicy.filter(object) + end + + test "passes NSFW through when :reject is disabled", %{nsfw_object: object} do + clear_config([@policy, :reject], false) + {:ok, _} = NsfwApiPolicy.filter(object) + end + + test "unlists NSFW when :unlist is enabled", %{user: user, nsfw_object: object} do + clear_config([@policy, :unlist], true) + {:ok, object} = NsfwApiPolicy.filter(object) + assert object["to"] == [user.follower_address] + end + + test "passes NSFW through when :unlist is disabled", %{nsfw_object: object} do + clear_config([@policy, :unlist], false) + {:ok, object} = NsfwApiPolicy.filter(object) + assert object["to"] == [Constants.as_public()] + end + end +end diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 57fc00af5..1a51b7d30 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -318,7 +318,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do following_user = insert(:user) non_following_user = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(following_user, actor) + {:ok, _, _, _} = CommonAPI.follow(actor, following_user) activity = %{ "actor" => actor.ap_id, diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index 3ead73792..25548e3da 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -65,7 +65,6 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do refute MRF.subdomain_match?(regexes, "example.com") end - @tag capture_log: true test "logs sensible error on accidental wildcard" do assert_raise Regex.CompileError, fn -> assert capture_log(MRF.subdomains_regex(["*unsafe.tld"])) =~ diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index 511637e1d..b711d8e91 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -43,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest setup do user = insert(:user) {:ok, activity} = Pleroma.Web.CommonAPI.post(user, %{status: "mew mew :dinosaur:"}) - {:ok, edit} = Pleroma.Web.CommonAPI.update(user, activity, %{status: "edited :blank:"}) + {:ok, edit} = Pleroma.Web.CommonAPI.update(activity, user, %{status: "edited :blank:"}) {:ok, %{"object" => external_rep}} = Pleroma.Web.ActivityPub.Transmogrifier.prepare_outgoing(edit.data) diff --git a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs index a615c1d9a..6627fa6db 100644 --- a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs @@ -27,19 +27,22 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do end test "works with honkerific attachments" do - attachment = %{ + honk = %{ "mediaType" => "", - "name" => "", - "summary" => "298p3RG7j27tfsZ9RQ.jpg", + "summary" => "Select your spirit chonk", + "name" => "298p3RG7j27tfsZ9RQ.jpg", "type" => "Document", "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" } assert {:ok, attachment} = - AttachmentValidator.cast_and_validate(attachment) + honk + |> AttachmentValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) assert attachment.mediaType == "application/octet-stream" + assert attachment.summary == "Select your spirit chonk" + assert attachment.name == "298p3RG7j27tfsZ9RQ.jpg" end test "works with an unknown but valid mime type" do diff --git a/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs index ebc181a6d..620173119 100644 --- a/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs @@ -94,7 +94,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do user: user, post_activity: post_activity } do - _like = CommonAPI.favorite(user, post_activity.id) + _like = CommonAPI.favorite(post_activity.id, user) refute LikeValidator.cast_and_validate(valid_like).valid? end diff --git a/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs index db95b8e3c..589b70ac7 100644 --- a/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoHandlingTest do setup do user = insert(:user) {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - {:ok, like} = CommonAPI.favorite(user, post_activity.id) + {:ok, like} = CommonAPI.favorite(post_activity.id, user) {:ok, valid_like_undo, []} = Builder.undo(user, like) %{user: user, like: like, valid_like_undo: valid_like_undo} diff --git a/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs index a09dbf5c6..c88339d14 100644 --- a/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs @@ -132,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do setup do user = insert(:user) {:ok, activity} = Pleroma.Web.CommonAPI.post(user, %{status: "mew mew :dinosaur:"}) - {:ok, edit} = Pleroma.Web.CommonAPI.update(user, activity, %{status: "edited :blank:"}) + {:ok, edit} = Pleroma.Web.CommonAPI.update(activity, user, %{status: "edited :blank:"}) {:ok, external_rep} = Pleroma.Web.ActivityPub.Transmogrifier.prepare_outgoing(edit.data) %{external_rep: external_rep} end diff --git a/test/pleroma/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs index 870f1f77a..6f48a0227 100644 --- a/test/pleroma/web/activity_pub/publisher_test.exs +++ b/test/pleroma/web/activity_pub/publisher_test.exs @@ -216,7 +216,6 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do refute called(Instances.set_reachable(inbox)) end - @tag capture_log: true test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code", Instances, [:passthrough], @@ -224,7 +223,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do actor = insert(:user) inbox = "http://404.site/users/nick1/inbox" - assert {:discard, _} = + assert {:cancel, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) assert called(Instances.set_unreachable(inbox)) diff --git a/test/pleroma/web/activity_pub/relay_test.exs b/test/pleroma/web/activity_pub/relay_test.exs index ec9b0f09a..7c45593ed 100644 --- a/test/pleroma/web/activity_pub/relay_test.exs +++ b/test/pleroma/web/activity_pub/relay_test.exs @@ -53,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do test "returns activity" do user = insert(:user) service_actor = Relay.get_actor() - CommonAPI.follow(service_actor, user) + CommonAPI.follow(user, service_actor) assert "#{user.ap_id}/followers" in User.following(service_actor) assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id) assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" @@ -74,7 +74,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do end) service_actor = Relay.get_actor() - CommonAPI.follow(service_actor, user) + CommonAPI.follow(user, service_actor) assert "#{user.ap_id}/followers" in User.following(service_actor) assert Pleroma.Repo.get_by( @@ -113,7 +113,6 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do assert Relay.publish(activity) == {:error, "Not implemented"} end - @tag capture_log: true test "returns error when activity not public" do activity = insert(:direct_note_activity) assert Relay.publish(activity) == {:error, false} diff --git a/test/pleroma/web/activity_pub/side_effects/delete_test.exs b/test/pleroma/web/activity_pub/side_effects/delete_test.exs index 9a2703c4c..637007b7e 100644 --- a/test/pleroma/web/activity_pub/side_effects/delete_test.exs +++ b/test/pleroma/web/activity_pub/side_effects/delete_test.exs @@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects.DeleteTest do {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"}) {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op}) - {:ok, favorite} = CommonAPI.favorite(user, post.id) + {:ok, favorite} = CommonAPI.favorite(post.id, user) object = Object.normalize(post, fetch: false) {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index 7af50e12c..68922e536 100644 --- a/test/pleroma/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -516,10 +516,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do poster = insert(:user) user = insert(:user) {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) - {:ok, like} = CommonAPI.favorite(user, post.id) + {:ok, like} = CommonAPI.favorite(post.id, user) {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍") {:ok, announce} = CommonAPI.repeat(post.id, user) - {:ok, block} = CommonAPI.block(user, poster) + {:ok, block} = CommonAPI.block(poster, user) {:ok, undo_data, _meta} = Builder.undo(user, like) {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true) @@ -834,7 +834,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do user = insert(:user) followed = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, user) {:ok, reject_data, []} = Builder.reject(followed, follow_activity) {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true) @@ -965,7 +965,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do group: group, poster: poster } do - {:ok, _} = CommonAPI.block(group, poster) + {:ok, _} = CommonAPI.block(poster, group) create_activity_data = make_create.([group]) {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) diff --git a/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs index 968fd4ede..4209a24a7 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs @@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do {:ok, follower, followed} = User.follow(follower, followed) assert User.following?(follower, followed) == true - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") @@ -48,7 +48,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do follower = insert(:user) followed = insert(:user, is_locked: true) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") diff --git a/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs index 9521cc0ab..f55f42c10 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs @@ -83,7 +83,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do assert(Activity.get_create_by_object_ap_id(data["object"])) end - @tag capture_log: true test "it works for incoming announces with an existing activity" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) @@ -136,7 +135,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do assert object.data["content"] == "this is a private toot" end - @tag capture_log: true test "it rejects incoming announces with an inlined activity from another origin" do Tesla.Mock.mock(fn %{method: :get} -> %Tesla.Env{status: 404, body: ""} diff --git a/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs index 4a7ff5158..300151fb2 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs @@ -86,7 +86,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do assert match?({:error, _}, Transmogrifier.handle_incoming(data)) end - @tag capture_log: true test "it works for incoming user deletes" do %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin") diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs new file mode 100644 index 000000000..c632c199c --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs @@ -0,0 +1,14 @@ +defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Web.ActivityPub.Transmogrifier + + test "it encodes the id to be a valid url" do + name = "hanapog" + url = "https://misskey.local.live/emojis/hana pog.png" + + tag = Transmogrifier.build_emoji_tag({name, url}) + + assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png" + end +end diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index dc1483288..fd7a3c772 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -56,7 +56,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert activity == returned_activity end - @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") @@ -104,7 +103,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do end end - @tag capture_log: true test "it does not crash if the object in inReplyTo can't be fetched" do data = File.read!("test/fixtures/mastodon-post-activity.json") @@ -581,7 +579,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert modified_object["inReplyTo"] == [] end - @tag capture_log: true test "returns modified object when allowed incoming reply", %{data: data} do object_with_reply = Map.put( @@ -767,7 +764,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do assert modified.data["context"] == object.data["id"] end - @tag capture_log: true test "the reply note uses its parent's ID when context is missing and reply is unreachable" do insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8") diff --git a/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs index 11562422d..225898e85 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do followed = insert(:user, is_locked: true) {:ok, follower, followed} = User.follow(follower, followed) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) + {:ok, _, _, follow_activity} = CommonAPI.follow(followed, follower) assert User.following?(follower, followed) == true diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index 8fbcf15f1..ebf70b3e6 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -353,7 +353,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "everybody do the dinosaur :dinosaur:"}) - {:ok, update} = CommonAPI.update(user, activity, %{status: "mew mew :blank:"}) + {:ok, update} = CommonAPI.update(activity, user, %{status: "mew mew :blank:"}) {:ok, prepared} = Transmogrifier.prepare_outgoing(update.data) @@ -554,7 +554,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do end) =~ "Unsupported URI scheme" end - @tag capture_log: true test "returns {:ok, %Object{}} for success case" do assert {:ok, %Object{}} = Transmogrifier.get_obj_helper( diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs index b7c4417a8..45fef154e 100644 --- a/test/pleroma/web/activity_pub/utils_test.exs +++ b/test/pleroma/web/activity_pub/utils_test.exs @@ -215,7 +215,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do }) object = Object.normalize(activity, fetch: false) - {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1]) + {:ok, votes, object} = CommonAPI.vote(object, other_user, [0, 1]) assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes) end @@ -233,8 +233,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do }) object = Object.normalize(activity, fetch: false) - {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0]) - {:ok, _activity} = CommonAPI.favorite(user, activity.id) + {:ok, [vote], object} = CommonAPI.vote(object, other_user, [0]) + {:ok, _activity} = CommonAPI.favorite(activity.id, user) [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object) assert fetched_vote.id == vote.id end @@ -245,8 +245,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do user = insert(:user, is_locked: true) follower = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower) data = follow_activity_two.data @@ -267,8 +267,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do user = insert(:user) follower = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower) {:ok, follow_activity_two} = Utils.update_follow_state_for_all(follow_activity_two, "reject") @@ -283,8 +283,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do user = insert(:user, is_locked: true) follower = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower) data = follow_activity_two.data @@ -369,7 +369,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do user = insert(:user) refute Utils.get_existing_like(user.ap_id, object) - {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id) + {:ok, like_activity} = CommonAPI.favorite(note_activity.id, user) assert ^like_activity = Utils.get_existing_like(user.ap_id, object) end @@ -396,9 +396,9 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do user1 = insert(:user) user2 = insert(:user) - assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) - assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) - assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2) + assert {:ok, %Activity{} = _} = CommonAPI.block(user2, user1) + assert {:ok, %Activity{} = _} = CommonAPI.block(user2, user1) + assert {:ok, %Activity{} = activity} = CommonAPI.block(user2, user1) assert Utils.fetch_latest_block(user1, user2) == activity end @@ -560,7 +560,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do target_account = insert(:user) {:ok, activity} = CommonAPI.post(posting_account, %{status: "foobar"}) - {:ok, like} = CommonAPI.favorite(target_account, activity.id) + {:ok, like} = CommonAPI.favorite(activity.id, target_account) context = Utils.generate_context_id() content = "foobar" diff --git a/test/pleroma/web/activity_pub/views/object_view_test.exs b/test/pleroma/web/activity_pub/views/object_view_test.exs index d94878e31..14258795f 100644 --- a/test/pleroma/web/activity_pub/views/object_view_test.exs +++ b/test/pleroma/web/activity_pub/views/object_view_test.exs @@ -59,7 +59,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do object = Object.normalize(note, fetch: false) user = insert(:user) - {:ok, like_activity} = CommonAPI.favorite(user, note.id) + {:ok, like_activity} = CommonAPI.favorite(note.id, user) result = ObjectView.render("object.json", %{object: like_activity}) diff --git a/test/pleroma/web/activity_pub/views/user_view_test.exs b/test/pleroma/web/activity_pub/views/user_view_test.exs index c75149dab..c94f8a2bc 100644 --- a/test/pleroma/web/activity_pub/views/user_view_test.exs +++ b/test/pleroma/web/activity_pub/views/user_view_test.exs @@ -138,7 +138,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "sets totalItems to zero when followers are hidden" do user = insert(:user) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) user = Map.merge(user, %{hide_followers_count: true, hide_followers: true}) refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems") @@ -147,7 +147,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "sets correct totalItems when followers are hidden but the follower counter is not" do user = insert(:user) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) user = Map.merge(user, %{hide_followers_count: false, hide_followers: true}) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) @@ -158,7 +158,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "sets totalItems to zero when follows are hidden" do user = insert(:user) other_user = insert(:user) - {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, user, _other_user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) user = Map.merge(user, %{hide_follows_count: true, hide_follows: true}) assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user}) @@ -167,7 +167,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "sets correct totalItems when follows are hidden but the follow counter is not" do user = insert(:user) other_user = insert(:user) - {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, user, _other_user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) user = Map.merge(user, %{hide_follows_count: false, hide_follows: true}) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index 734aca752..dc12155f5 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -194,7 +194,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do setup do: clear_config(:configurable_from_database, true) - @tag capture_log: true test "create new config setting in db", %{conn: conn} do ueberauth = Application.get_env(:ueberauth, Ueberauth) on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) @@ -316,7 +315,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} end - @tag capture_log: true test "save configs setting without explicit key", %{conn: conn} do adapter = Application.get_env(:http, :adapter) send_user_agent = Application.get_env(:http, :send_user_agent) @@ -611,52 +609,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do ] end - test "saving full setting if value is in full_key_update list", %{conn: conn} do - backends = Application.get_env(:logger, :backends) - on_exit(fn -> Application.put_env(:logger, :backends, backends) end) - - insert(:config, - group: :logger, - key: :backends, - value: [] - ) - - Pleroma.Config.TransferTask.load_and_update_env([], false) - - assert Application.get_env(:logger, :backends) == [] - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":logger", - key: ":backends", - value: [":console"] - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":logger", - "key" => ":backends", - "value" => [ - ":console" - ], - "db" => [":backends"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:logger, :backends) == [ - :console - ] - end - test "saving full setting if value is not keyword", %{conn: conn} do insert(:config, group: :tesla, @@ -1229,7 +1181,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert ":proxy_url" in db end - @tag capture_log: true test "doesn't set keys not in the whitelist", %{conn: conn} do clear_config(:database_config_whitelist, [ {:pleroma, :key1}, diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index 8edfda54c..c8495c477 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -69,8 +69,8 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do # Create some activities to check they got deleted later follower = insert(:user) {:ok, _} = CommonAPI.post(user, %{status: "test"}) - {:ok, _, _, _} = CommonAPI.follow(user, follower) {:ok, _, _, _} = CommonAPI.follow(follower, user) + {:ok, _, _, _} = CommonAPI.follow(user, follower) user = Repo.get(User, user.id) assert user.note_count == 1 assert user.follower_count == 1 diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index 58cd1fd42..b6fba6999 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -13,6 +13,7 @@ defmodule Pleroma.Web.CommonAPITest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.Rule + alias Pleroma.Tests.ObanHelpers alias Pleroma.UnstubbedConfigMock, as: ConfigMock alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -22,7 +23,7 @@ defmodule Pleroma.Web.CommonAPITest do alias Pleroma.Web.CommonAPI alias Pleroma.Workers.PollWorker - import Ecto.Query, only: [from: 2] + import Ecto.Query, only: [from: 2, where: 3] import Mock import Mox import Pleroma.Factory @@ -79,8 +80,8 @@ defmodule Pleroma.Web.CommonAPITest do setup do blocker = insert(:user) blocked = insert(:user, local: false) - CommonAPI.follow(blocker, blocked) CommonAPI.follow(blocked, blocker) + CommonAPI.follow(blocker, blocked) CommonAPI.accept_follow_request(blocker, blocked) CommonAPI.accept_follow_request(blocked, blocked) %{blocker: blocker, blocked: blocked} @@ -94,7 +95,7 @@ defmodule Pleroma.Web.CommonAPITest do assert User.get_follow_state(blocker, blocked) == :follow_accept refute is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked)) - assert {:ok, block} = CommonAPI.block(blocker, blocked) + assert {:ok, block} = CommonAPI.block(blocked, blocker) assert block.local assert User.blocks?(blocker, blocked) @@ -119,7 +120,7 @@ defmodule Pleroma.Web.CommonAPITest do with_mock Pleroma.Web.Federator, publish: fn _ -> nil end do - assert {:ok, block} = CommonAPI.block(blocker, blocked) + assert {:ok, block} = CommonAPI.block(blocked, blocker) assert block.local assert User.blocks?(blocker, blocked) @@ -323,7 +324,7 @@ defmodule Pleroma.Web.CommonAPITest do User.block(blocker, blocked) assert User.blocks?(blocker, blocked) - assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked) + assert {:ok, :no_activity} == CommonAPI.unblock(blocked, blocker) refute User.blocks?(blocker, blocked) end end @@ -453,7 +454,7 @@ defmodule Pleroma.Web.CommonAPITest do users_serial |> Enum.map(fn user -> - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) end) object = Object.get_by_ap_id(activity.data["object"]) @@ -462,7 +463,7 @@ defmodule Pleroma.Web.CommonAPITest do users |> Enum.map(fn user -> Task.async(fn -> - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) end) end) |> Enum.map(&Task.await/1) @@ -954,7 +955,7 @@ defmodule Pleroma.Web.CommonAPITest do test "author can repeat own private statuses" do author = insert(:user) follower = insert(:user) - CommonAPI.follow(follower, author) + CommonAPI.follow(author, follower) {:ok, activity} = CommonAPI.post(author, %{status: "cofe", visibility: "private"}) @@ -973,7 +974,7 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"}) - {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id) + {:ok, %Activity{data: data}} = CommonAPI.favorite(post_activity.id, user) assert data["type"] == "Like" assert data["actor"] == user.ap_id assert data["object"] == post_activity.data["object"] @@ -993,8 +994,8 @@ defmodule Pleroma.Web.CommonAPITest do other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id) - assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id) + {:ok, %Activity{}} = CommonAPI.favorite(activity.id, user) + assert {:ok, :already_liked} = CommonAPI.favorite(activity.id, user) end end @@ -1148,7 +1149,7 @@ defmodule Pleroma.Web.CommonAPITest do } ) - {:ok, favorite_activity} = CommonAPI.favorite(friend2, activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(activity.id, friend2) {:ok, repeat_activity} = CommonAPI.repeat(activity.id, friend1) assert Repo.aggregate( @@ -1171,8 +1172,8 @@ defmodule Pleroma.Web.CommonAPITest do n.type == "mention" && n.activity_id == reply_activity.id end) - {:ok, _} = CommonAPI.add_mute(author, activity) - assert CommonAPI.thread_muted?(author, activity) + {:ok, _} = CommonAPI.add_mute(activity, author) + assert CommonAPI.thread_muted?(activity, author) assert Repo.aggregate( from(n in Notification, where: n.seen == false and n.user_id == ^friend1.id), @@ -1196,13 +1197,13 @@ defmodule Pleroma.Web.CommonAPITest do end test "add mute", %{user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - assert CommonAPI.thread_muted?(user, activity) + {:ok, _} = CommonAPI.add_mute(activity, user) + assert CommonAPI.thread_muted?(activity, user) end test "add expiring mute", %{user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity, %{expires_in: 60}) - assert CommonAPI.thread_muted?(user, activity) + {:ok, _} = CommonAPI.add_mute(activity, user, %{expires_in: 60}) + assert CommonAPI.thread_muted?(activity, user) worker = Pleroma.Workers.MuteExpireWorker args = %{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id} @@ -1213,24 +1214,24 @@ defmodule Pleroma.Web.CommonAPITest do ) assert :ok = perform_job(worker, args) - refute CommonAPI.thread_muted?(user, activity) + refute CommonAPI.thread_muted?(activity, user) end test "remove mute", %{user: user, activity: activity} do - CommonAPI.add_mute(user, activity) - {:ok, _} = CommonAPI.remove_mute(user, activity) - refute CommonAPI.thread_muted?(user, activity) + CommonAPI.add_mute(activity, user) + {:ok, _} = CommonAPI.remove_mute(activity, user) + refute CommonAPI.thread_muted?(activity, user) end test "remove mute by ids", %{user: user, activity: activity} do - CommonAPI.add_mute(user, activity) - {:ok, _} = CommonAPI.remove_mute(user.id, activity.id) - refute CommonAPI.thread_muted?(user, activity) + CommonAPI.add_mute(activity, user) + {:ok, _} = CommonAPI.remove_mute(activity.id, user.id) + refute CommonAPI.thread_muted?(activity, user) end test "check that mutes can't be duplicate", %{user: user, activity: activity} do - CommonAPI.add_mute(user, activity) - {:error, _} = CommonAPI.add_mute(user, activity) + CommonAPI.add_mute(activity, user) + {:error, _} = CommonAPI.add_mute(activity, user) end end @@ -1403,14 +1404,14 @@ defmodule Pleroma.Web.CommonAPITest do end test "add a reblog mute", %{muter: muter, muted: muted} do - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted) + {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muted, muter) assert User.showing_reblogs?(muter, muted) == false end test "remove a reblog mute", %{muter: muter, muted: muted} do - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted) - {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted) + {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muted, muter) + {:ok, _reblog_mute} = CommonAPI.show_reblogs(muted, muter) assert User.showing_reblogs?(muter, muted) == true end @@ -1419,7 +1420,7 @@ defmodule Pleroma.Web.CommonAPITest do describe "follow/2" do test "directly follows a non-locked local user" do [follower, followed] = insert_pair(:user) - {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + {:ok, follower, followed, _} = CommonAPI.follow(followed, follower) assert User.following?(follower, followed) end @@ -1428,24 +1429,24 @@ defmodule Pleroma.Web.CommonAPITest do describe "unfollow/2" do test "also unsubscribes a user" do [follower, followed] = insert_pair(:user) - {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + {:ok, follower, followed, _} = CommonAPI.follow(followed, follower) {:ok, _subscription} = User.subscribe(follower, followed) assert User.subscribed_to?(follower, followed) - {:ok, follower} = CommonAPI.unfollow(follower, followed) + {:ok, follower} = CommonAPI.unfollow(followed, follower) refute User.subscribed_to?(follower, followed) end test "also unpins a user" do [follower, followed] = insert_pair(:user) - {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + {:ok, follower, followed, _} = CommonAPI.follow(followed, follower) {:ok, _endorsement} = User.endorse(follower, followed) assert User.endorses?(follower, followed) - {:ok, follower} = CommonAPI.unfollow(follower, followed) + {:ok, follower} = CommonAPI.unfollow(followed, follower) refute User.endorses?(follower, followed) end @@ -1455,10 +1456,10 @@ defmodule Pleroma.Web.CommonAPITest do followed = insert(:user, is_locked: true) assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = - CommonAPI.follow(follower, followed) + CommonAPI.follow(followed, follower) assert User.get_follow_state(follower, followed) == :follow_pending - assert {:ok, follower} = CommonAPI.unfollow(follower, followed) + assert {:ok, follower} = CommonAPI.unfollow(followed, follower) assert User.get_follow_state(follower, followed) == nil assert %{id: ^activity_id, data: %{"state" => "cancelled"}} = @@ -1477,10 +1478,10 @@ defmodule Pleroma.Web.CommonAPITest do followed = insert(:user, is_locked: true, local: false) assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = - CommonAPI.follow(follower, followed) + CommonAPI.follow(followed, follower) assert User.get_follow_state(follower, followed) == :follow_pending - assert {:ok, follower} = CommonAPI.unfollow(follower, followed) + assert {:ok, follower} = CommonAPI.unfollow(followed, follower) assert User.get_follow_state(follower, followed) == nil assert %{id: ^activity_id, data: %{"state" => "cancelled"}} = @@ -1501,9 +1502,9 @@ defmodule Pleroma.Web.CommonAPITest do follower = insert(:user) follower_two = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_three} = CommonAPI.follow(user, follower_two) assert follow_activity.data["state"] == "pending" assert follow_activity_two.data["state"] == "pending" @@ -1521,9 +1522,9 @@ defmodule Pleroma.Web.CommonAPITest do follower = insert(:user) follower_two = insert(:user) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(user, follower) + {:ok, _, _, follow_activity_three} = CommonAPI.follow(user, follower_two) assert follow_activity.data["state"] == "pending" assert follow_activity_two.data["state"] == "pending" @@ -1558,9 +1559,9 @@ defmodule Pleroma.Web.CommonAPITest do object = Object.normalize(activity, fetch: false) - {:ok, _, object} = CommonAPI.vote(other_user, object, [0]) + {:ok, _, object} = CommonAPI.vote(object, other_user, [0]) - assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1]) + assert {:error, "Already voted"} == CommonAPI.vote(object, other_user, [1]) end end @@ -1694,7 +1695,7 @@ defmodule Pleroma.Web.CommonAPITest do with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} = - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) assert Visibility.local_public?(activity) refute called(Pleroma.Web.Federator.publish(activity)) @@ -1707,7 +1708,7 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) - {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id) + {:ok, %Activity{}} = CommonAPI.favorite(activity.id, user) with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user) @@ -1752,7 +1753,7 @@ defmodule Pleroma.Web.CommonAPITest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1"}) - {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"}) + {:ok, updated} = CommonAPI.update(activity, user, %{status: "updated 2"}) updated_object = Object.normalize(updated) assert updated_object.data["content"] == "updated 2" @@ -1766,7 +1767,7 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1", visibility: "private"}) - {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"}) + {:ok, updated} = CommonAPI.update(activity, user, %{status: "updated 2"}) updated_object = Object.normalize(updated) assert updated_object.data["content"] == "updated 2" @@ -1783,7 +1784,7 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"}) - {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"}) + {:ok, updated} = CommonAPI.update(activity, user, %{status: "updated 2 :#{emoji2}:"}) updated_object = Object.normalize(updated) assert updated_object.data["content"] == "updated 2 :#{emoji2}:" @@ -1802,7 +1803,7 @@ defmodule Pleroma.Web.CommonAPITest do with_mock Pleroma.Web.Federator, publish: fn _p -> nil end do - {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"}) + {:ok, updated} = CommonAPI.update(activity, user, %{status: "updated 2 :#{emoji2}:"}) assert updated.data["object"]["content"] == "updated 2 :#{emoji2}:" assert %{^emoji2 => _} = updated.data["object"]["emoji"] @@ -1846,7 +1847,7 @@ defmodule Pleroma.Web.CommonAPITest do assert reply.object.data["emoji"]["remoteemoji"] == remote_emoji_uri {:ok, edit} = - CommonAPI.update(user, reply, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"}) + CommonAPI.update(reply, user, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"}) edited_note = Pleroma.Object.normalize(edit) @@ -1862,7 +1863,7 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "updated 1"}) assert Object.normalize(activity).data["summary"] == "mewmew 1" - {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"}) + {:ok, updated} = CommonAPI.update(activity, user, %{status: "updated 2"}) updated_object = Object.normalize(updated) assert updated_object.data["content"] == "mewmew 2" @@ -1913,11 +1914,224 @@ defmodule Pleroma.Web.CommonAPITest do end test "it does not boost if group is blocking poster", %{poster: poster, group: group} do - {:ok, _} = CommonAPI.block(group, poster) + {:ok, _} = CommonAPI.block(poster, group) {:ok, post} = CommonAPI.post(poster, %{status: "hey @#{group.nickname}"}) announces = get_announces_of_object(post.object) assert [] = announces end end + + describe "Oban jobs are cancelled" do + setup do + clear_config([:instance, :federating], true) + + local_user = insert(:user) + + remote_one = + insert(:user, %{ + local: false, + nickname: "nick1@domain.com", + ap_id: "https://domain.com/users/nick1", + inbox: "https://domain.com/users/nick1/inbox", + shared_inbox: "https://domain.com/inbox" + }) + + remote_two = + insert(:user, %{ + local: false, + nickname: "nick2@example.com", + ap_id: "https://example.com/users/nick2", + inbox: "https://example.com/users/nick2/inbox", + shared_inbox: "https://example.com/inbox" + }) + + %{local_user: local_user, remote_one: remote_one, remote_two: remote_two} + end + + test "when deleting posts", %{ + local_user: local_user, + remote_one: remote_one, + remote_two: remote_two + } do + {:ok, _, _} = Pleroma.User.follow(remote_one, local_user) + {:ok, _, _} = Pleroma.User.follow(remote_two, local_user) + + {:ok, %{data: %{"id" => ap_id}} = activity} = + CommonAPI.post(local_user, %{status: "Happy Friday everyone!"}) + + # Generate the publish_one jobs + ObanHelpers.perform_all() + + publish_one_jobs = + all_enqueued() + |> Enum.filter(fn job -> + match?( + %{ + state: "available", + queue: "federator_outgoing", + worker: "Pleroma.Workers.PublisherWorker", + args: %{"op" => "publish_one", "params" => %{"id" => ^ap_id}} + }, + job + ) + end) + + assert length(publish_one_jobs) == 2 + + # The delete should have triggered cancelling the publish_one jobs + assert {:ok, _delete} = CommonAPI.delete(activity.id, local_user) + + # all_enqueued/1 will not return cancelled jobs + cancelled_jobs = + Oban.Job + |> where([j], j.worker == "Pleroma.Workers.PublisherWorker") + |> where([j], j.state == "cancelled") + |> where([j], j.args["op"] == "publish_one") + |> where([j], j.args["params"]["id"] == ^ap_id) + |> Pleroma.Repo.all() + + assert length(cancelled_jobs) == 2 + end + + test "when unfavoriting posts", %{ + local_user: local_user, + remote_one: remote_user + } do + {:ok, activity} = + CommonAPI.post(remote_user, %{status: "I like turtles!"}) + + {:ok, %{data: %{"id" => ap_id}} = _favorite} = + CommonAPI.favorite(activity.id, local_user) + + # Generate the publish_one jobs + ObanHelpers.perform_all() + + publish_one_jobs = + all_enqueued() + |> Enum.filter(fn job -> + match?( + %{ + state: "available", + queue: "federator_outgoing", + worker: "Pleroma.Workers.PublisherWorker", + args: %{"op" => "publish_one", "params" => %{"id" => ^ap_id}} + }, + job + ) + end) + + assert length(publish_one_jobs) == 1 + + # The unfavorite should have triggered cancelling the publish_one jobs + assert {:ok, _unfavorite} = CommonAPI.unfavorite(activity.id, local_user) + + # all_enqueued/1 will not return cancelled jobs + cancelled_jobs = + Oban.Job + |> where([j], j.worker == "Pleroma.Workers.PublisherWorker") + |> where([j], j.state == "cancelled") + |> where([j], j.args["op"] == "publish_one") + |> where([j], j.args["params"]["id"] == ^ap_id) + |> Pleroma.Repo.all() + + assert length(cancelled_jobs) == 1 + end + + test "when unboosting posts", %{ + local_user: local_user, + remote_one: remote_one, + remote_two: remote_two + } do + {:ok, _, _} = Pleroma.User.follow(remote_one, local_user) + {:ok, _, _} = Pleroma.User.follow(remote_two, local_user) + + {:ok, activity} = + CommonAPI.post(remote_one, %{status: "This is an unpleasant post"}) + + {:ok, %{data: %{"id" => ap_id}} = _repeat} = + CommonAPI.repeat(activity.id, local_user) + + # Generate the publish_one jobs + ObanHelpers.perform_all() + + publish_one_jobs = + all_enqueued() + |> Enum.filter(fn job -> + match?( + %{ + state: "available", + queue: "federator_outgoing", + worker: "Pleroma.Workers.PublisherWorker", + args: %{"op" => "publish_one", "params" => %{"id" => ^ap_id}} + }, + job + ) + end) + + assert length(publish_one_jobs) == 2 + + # The unrepeat should have triggered cancelling the publish_one jobs + assert {:ok, _unfavorite} = CommonAPI.unrepeat(activity.id, local_user) + + # all_enqueued/1 will not return cancelled jobs + cancelled_jobs = + Oban.Job + |> where([j], j.worker == "Pleroma.Workers.PublisherWorker") + |> where([j], j.state == "cancelled") + |> where([j], j.args["op"] == "publish_one") + |> where([j], j.args["params"]["id"] == ^ap_id) + |> Pleroma.Repo.all() + + assert length(cancelled_jobs) == 2 + end + + test "when unreacting to posts", %{ + local_user: local_user, + remote_one: remote_one, + remote_two: remote_two + } do + {:ok, _, _} = Pleroma.User.follow(remote_one, local_user) + {:ok, _, _} = Pleroma.User.follow(remote_two, local_user) + + {:ok, activity} = + CommonAPI.post(remote_one, %{status: "Gang gang!!!!"}) + + {:ok, %{data: %{"id" => ap_id}} = _react} = + CommonAPI.react_with_emoji(activity.id, local_user, "👍") + + # Generate the publish_one jobs + ObanHelpers.perform_all() + + publish_one_jobs = + all_enqueued() + |> Enum.filter(fn job -> + match?( + %{ + state: "available", + queue: "federator_outgoing", + worker: "Pleroma.Workers.PublisherWorker", + args: %{"op" => "publish_one", "params" => %{"id" => ^ap_id}} + }, + job + ) + end) + + assert length(publish_one_jobs) == 2 + + # The unreact should have triggered cancelling the publish_one jobs + assert {:ok, _unreact} = CommonAPI.unreact_with_emoji(activity.id, local_user, "👍") + + # all_enqueued/1 will not return cancelled jobs + cancelled_jobs = + Oban.Job + |> where([j], j.worker == "Pleroma.Workers.PublisherWorker") + |> where([j], j.state == "cancelled") + |> where([j], j.args["op"] == "publish_one") + |> where([j], j.args["params"]["id"] == ^ap_id) + |> Pleroma.Repo.all() + + assert length(cancelled_jobs) == 2 + end + end end diff --git a/test/pleroma/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs index 58ab8f137..7d196b228 100644 --- a/test/pleroma/web/feed/tag_controller_test.exs +++ b/test/pleroma/web/feed/tag_controller_test.exs @@ -55,11 +55,11 @@ defmodule Pleroma.Web.Feed.TagControllerTest do xml = parse(response) - assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart' + assert xpath(xml, ~x"//feed/title/text()") == ~c"#pleromaart" assert xpath(xml, ~x"//feed/entry/title/text()"l) == [ - '42 This is :moominmamm...', - 'yeah #PleromaArt' + ~c"42 This is :moominmamm...", + ~c"yeah #PleromaArt" ] assert xpath(xml, ~x"//feed/entry/author/name/text()"ls) == [user.nickname, user.nickname] @@ -73,10 +73,10 @@ defmodule Pleroma.Web.Feed.TagControllerTest do resp = response(conn, 200) xml = parse(resp) - assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart' + assert xpath(xml, ~x"//feed/title/text()") == ~c"#pleromaart" assert xpath(xml, ~x"//feed/entry/title/text()"l) == [ - 'yeah #PleromaArt' + ~c"yeah #PleromaArt" ] end @@ -120,20 +120,20 @@ defmodule Pleroma.Web.Feed.TagControllerTest do |> response(200) xml = parse(response) - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' + assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart" assert xpath(xml, ~x"//channel/description/text()"s) == "These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse." assert xpath(xml, ~x"//channel/link/text()") == - '#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss' + ~c"#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss" assert xpath(xml, ~x"//channel/webfeeds:logo/text()") == - '#{Pleroma.Web.Endpoint.url()}/static/logo.svg' + ~c"#{Pleroma.Web.Endpoint.url()}/static/logo.svg" assert xpath(xml, ~x"//channel/item/title/text()"l) == [ - '42 This is :moominmamm...', - 'yeah #PleromaArt' + ~c"42 This is :moominmamm...", + ~c"yeah #PleromaArt" ] assert xpath(xml, ~x"//channel/item/pubDate/text()"sl) == [ @@ -160,7 +160,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do |> response(200) xml = parse(response) - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' + assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart" assert xpath(xml, ~x"//channel/description/text()"s) == "These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse." @@ -174,10 +174,10 @@ defmodule Pleroma.Web.Feed.TagControllerTest do resp = response(conn, 200) xml = parse(resp) - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' + assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart" assert xpath(xml, ~x"//channel/item/title/text()"l) == [ - 'yeah #PleromaArt' + ~c"yeah #PleromaArt" ] end diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs index d3c4108de..1c17d47b4 100644 --- a/test/pleroma/web/feed/user_controller_test.exs +++ b/test/pleroma/web/feed/user_controller_test.exs @@ -88,7 +88,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as'] + assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"] assert resp =~ FeedView.escape(object.data["content"]) assert resp =~ FeedView.escape(object.data["summary"]) assert resp =~ FeedView.escape(object.data["context"]) @@ -104,7 +104,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['2hu & as'] + assert activity_titles == [~c"2hu & as"] end test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do @@ -119,7 +119,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as'] + assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"] assert resp =~ FeedView.escape(object.data["content"]) assert resp =~ FeedView.escape(object.data["summary"]) assert resp =~ FeedView.escape(object.data["context"]) @@ -135,7 +135,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['2hu & as'] + assert activity_titles == [~c"2hu & as"] end test "returns 404 for a missing feed", %{conn: conn} do @@ -167,7 +167,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.xpath(~x"//entry/title/text()"l) |> Enum.sort() - assert activity_titles == ['public', 'unlisted'] + assert activity_titles == [~c"public", ~c"unlisted"] end test "returns 404 when the user is remote", %{conn: conn} do @@ -208,7 +208,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as'] + assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"] assert resp =~ FeedView.escape(object.data["content"]) assert resp =~ FeedView.escape(object.data["summary"]) assert resp =~ FeedView.escape(object.data["context"]) diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index aa7726a9c..54f6818bd 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -1120,7 +1120,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> json_response_and_validate_schema(200) # Follow the user, then the pinned status can be seen - CommonAPI.follow(reader, user) + CommonAPI.follow(user, reader) ObanHelpers.perform_all() assert [%{"id" => ^activity_id, "pinned" => true}] = @@ -2118,7 +2118,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "pin account", %{user: user, conn: conn} do %{id: id1} = other_user1 = insert(:user) - CommonAPI.follow(user, other_user1) + CommonAPI.follow(other_user1, user) assert %{"id" => ^id1, "endorsed" => true} = conn @@ -2136,7 +2136,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "unpin account", %{user: user, conn: conn} do %{id: id1} = other_user1 = insert(:user) - CommonAPI.follow(user, other_user1) + CommonAPI.follow(other_user1, user) User.endorse(user, other_user1) assert %{"id" => ^id1, "endorsed" => false} = @@ -2156,8 +2156,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do %{id: id1} = other_user1 = insert(:user) %{id: id2} = other_user2 = insert(:user) - CommonAPI.follow(user, other_user1) - CommonAPI.follow(user, other_user2) + CommonAPI.follow(other_user1, user) + CommonAPI.follow(other_user2, user) conn |> put_req_header("content-type", "application/json") @@ -2172,13 +2172,62 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end end + describe "familiar followers" do + setup do: oauth_access(["read:follows"]) + + test "fetch user familiar followers", %{user: user, conn: conn} do + %{id: id1} = other_user1 = insert(:user) + %{id: id2} = other_user2 = insert(:user) + _ = insert(:user) + + User.follow(user, other_user1) + User.follow(other_user1, other_user2) + + assert [%{"accounts" => [%{"id" => ^id1}], "id" => ^id2}] = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/accounts/familiar_followers?id[]=#{id2}") + |> json_response_and_validate_schema(200) + end + + test "returns empty array if followers are hidden", %{user: user, conn: conn} do + other_user1 = insert(:user, hide_follows: true) + %{id: id2} = other_user2 = insert(:user) + _ = insert(:user) + + User.follow(user, other_user1) + User.follow(other_user1, other_user2) + + assert [%{"accounts" => [], "id" => ^id2}] = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/accounts/familiar_followers?id[]=#{id2}") + |> json_response_and_validate_schema(200) + end + + test "it respects hide_followers", %{user: user, conn: conn} do + other_user1 = insert(:user) + %{id: id2} = other_user2 = insert(:user, hide_followers: true) + _ = insert(:user) + + User.follow(user, other_user1) + User.follow(other_user1, other_user2) + + assert [%{"accounts" => [], "id" => ^id2}] = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/accounts/familiar_followers?id[]=#{id2}") + |> json_response_and_validate_schema(200) + end + end + describe "remove from followers" do setup do: oauth_access(["follow"]) test "removing user from followers", %{conn: conn, user: user} do %{id: other_user_id} = other_user = insert(:user) - CommonAPI.follow(other_user, user) + CommonAPI.follow(user, other_user) assert %{"id" => ^other_user_id, "followed_by" => false} = conn @@ -2191,7 +2240,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "removing remote user from followers", %{conn: conn, user: user} do %{id: other_user_id} = other_user = insert(:user, local: false) - CommonAPI.follow(other_user, user) + CommonAPI.follow(user, other_user) assert User.following?(other_user, user) diff --git a/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs index ff01b549c..b7c7ccae0 100644 --- a/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -20,7 +20,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do test "/api/v1/follow_requests works", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, _activity} = CommonAPI.follow(user, other_user) {:ok, other_user, user} = User.follow(other_user, user, :follow_pending) assert User.following?(other_user, user) == false @@ -34,7 +34,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, _activity} = CommonAPI.follow(user, other_user) {:ok, other_user, user} = User.follow(other_user, user, :follow_pending) user = User.get_cached_by_id(user.id) @@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do test "/api/v1/follow_requests/:id/reject works", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, _activity} = CommonAPI.follow(user, other_user) user = User.get_cached_by_id(user.id) diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs index b92fd8afa..4adbaa640 100644 --- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs @@ -76,6 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do end test "/api/v2/media, upload_limit", %{conn: conn, user: user} do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) desc = "Description of the binary" upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8 diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 350b935d7..8fc22dde1 100644 --- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -148,7 +148,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do %{user: user, conn: conn} = oauth_access(["read:notifications"]) blocker = insert(:user) - {:ok, _} = CommonAPI.block(blocker, user) + {:ok, _} = CommonAPI.block(user, blocker) {:ok, activity} = CommonAPI.post(blocker, %{status: "hi @#{user.nickname}"}) {:ok, [_notification]} = Notification.create_notifications(activity) @@ -326,10 +326,10 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do {:ok, private_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "private"}) - {:ok, _} = CommonAPI.favorite(user, public_activity.id) - {:ok, _} = CommonAPI.favorite(user, direct_activity.id) - {:ok, _} = CommonAPI.favorite(user, unlisted_activity.id) - {:ok, _} = CommonAPI.favorite(user, private_activity.id) + {:ok, _} = CommonAPI.favorite(public_activity.id, user) + {:ok, _} = CommonAPI.favorite(direct_activity.id, user) + {:ok, _} = CommonAPI.favorite(unlisted_activity.id, user) + {:ok, _} = CommonAPI.favorite(private_activity.id, user) activity_ids = conn @@ -414,7 +414,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do in_reply_to_status_id: activity.id }) - {:ok, _favorite} = CommonAPI.favorite(user, reply.id) + {:ok, _favorite} = CommonAPI.favorite(reply.id, user) activity_ids = conn @@ -432,9 +432,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, other_user) mention_notification_id = get_notification_id_by_activity(mention_activity) favorite_notification_id = get_notification_id_by_activity(favorite_activity) @@ -470,9 +470,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, other_user) mention_notification_id = get_notification_id_by_activity(mention_activity) favorite_notification_id = get_notification_id_by_activity(favorite_activity) @@ -517,9 +517,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do {:ok, _activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, _activity} = CommonAPI.favorite(other_user, create_activity.id) + {:ok, _activity} = CommonAPI.favorite(create_activity.id, other_user) {:ok, _activity} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + {:ok, _, _, follow_activity} = CommonAPI.follow(user, other_user) follow_notification_id = get_notification_id_by_activity(follow_activity) @@ -578,7 +578,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do %{user: user, conn: conn} = oauth_access(["read:notifications"]) user2 = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _, _, _} = CommonAPI.follow(user2, user) {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) ret_conn = get(conn, "/api/v1/notifications") @@ -596,7 +596,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do %{user: user, conn: conn} = oauth_access(["read:notifications"]) user2 = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _, _, _} = CommonAPI.follow(user2, user) {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) ret_conn = get(conn, "/api/v1/notifications") @@ -614,7 +614,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do %{user: user, conn: conn} = oauth_access(["read:notifications"]) user2 = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _, _, _} = CommonAPI.follow(user2, user) {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) ret_conn = get(conn, "/api/v1/notifications") diff --git a/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs index 632242221..2d6b2aee2 100644 --- a/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do + use Oban.Testing, repo: Pleroma.Repo use Pleroma.Web.ConnCase, async: true alias Pleroma.Repo @@ -78,7 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do } ) - job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) + job = Repo.one(from(j in Oban.Job, where: j.queue == "federator_outgoing")) assert job.args == %{"activity_id" => scheduled_activity.id} assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(scheduled_at) @@ -124,9 +125,11 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do } ) - job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) - - assert job.args == %{"activity_id" => scheduled_activity.id} + assert_enqueued( + worker: Pleroma.Workers.ScheduledActivityWorker, + args: %{"activity_id" => scheduled_activity.id}, + queue: :federator_outgoing + ) res_conn = conn @@ -135,7 +138,11 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do assert %{} = json_response_and_validate_schema(res_conn, 200) refute Repo.get(ScheduledActivity, scheduled_activity.id) - refute Repo.get(Oban.Job, job.id) + + refute_enqueued( + worker: Pleroma.Workers.ScheduledActivityWorker, + args: %{"activity_id" => scheduled_activity.id} + ) res_conn = conn diff --git a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs index ad4144da4..d38767c96 100644 --- a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs @@ -130,7 +130,6 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do assert [] = results["statuses"] end - @tag capture_log: true test "constructs hashtags from search query", %{conn: conn} do results = conn diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index 80c1ed099..904bf1471 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -235,6 +235,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do assert Activity.get_in_reply_to_activity(activity).id == replied_to.id end + test "replying to a deleted status", %{user: user, conn: conn} do + {:ok, status} = CommonAPI.post(user, %{status: "cofe"}) + {:ok, _deleted_status} = CommonAPI.delete(status.id, user) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => status.id}) + |> json_response_and_validate_schema(422) + end + test "replying to a direct message with visibility other than direct", %{ user: user, conn: conn @@ -1346,7 +1356,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do user1 = insert(:user) user2 = insert(:user) user3 = insert(:user) - {:ok, _} = CommonAPI.favorite(user2, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, user2) {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) {:ok, reblog_activity1} = CommonAPI.repeat(activity.id, user1) {:ok, _} = CommonAPI.repeat(activity.id, user2) @@ -1473,7 +1483,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "unfavorites a status and returns it", %{user: user, conn: conn} do activity = insert(:note_activity) - {:ok, _} = CommonAPI.favorite(user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, user) conn = conn @@ -1761,7 +1771,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) + {:ok, _} = CommonAPI.add_mute(activity, user) conn = conn @@ -1774,7 +1784,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end test "unmute conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) + {:ok, _} = CommonAPI.add_mute(activity, user) id_str = to_string(activity.id) @@ -1849,7 +1859,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "returns users who have favorited the status", %{conn: conn, activity: activity} do other_user = insert(:user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) response = conn @@ -1880,7 +1890,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do other_user = insert(:user) {:ok, _user_relationship} = User.block(user, other_user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) response = conn @@ -1892,7 +1902,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "does not fail on an unauthenticated request", %{activity: activity} do other_user = insert(:user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) response = build_conn() @@ -1912,7 +1922,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do visibility: "direct" }) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) favourited_by_url = "/api/v1/statuses/#{activity.id}/favourited_by" @@ -1943,7 +1953,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do clear_config([:instance, :show_reactions], false) other_user = insert(:user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, other_user) response = conn @@ -2086,9 +2096,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do {:ok, second_post} = CommonAPI.post(other_user, %{status: "bla"}) {:ok, third_post} = CommonAPI.post(other_user, %{status: "bla"}) - {:ok, _first_favorite} = CommonAPI.favorite(user, third_post.id) - {:ok, _second_favorite} = CommonAPI.favorite(user, first_post.id) - {:ok, third_favorite} = CommonAPI.favorite(user, second_post.id) + {:ok, _first_favorite} = CommonAPI.favorite(third_post.id, user) + {:ok, _second_favorite} = CommonAPI.favorite(first_post.id, user) + {:ok, third_favorite} = CommonAPI.favorite(second_post.id, user) result = conn @@ -2124,7 +2134,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do {:ok, _} = CommonAPI.post(other_user, %{status: "bla"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "trees are happy"}) - {:ok, last_like} = CommonAPI.favorite(user, activity.id) + {:ok, last_like} = CommonAPI.favorite(activity.id, user) first_conn = get(conn, "/api/v1/favourites") @@ -2140,7 +2150,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do status: "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful." }) - {:ok, _} = CommonAPI.favorite(user, second_activity.id) + {:ok, _} = CommonAPI.favorite(second_activity.id, user) second_conn = get(conn, "/api/v1/favourites?since_id=#{last_like.id}") diff --git a/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs index c0f3d5a2a..01c3384e7 100644 --- a/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs @@ -47,7 +47,7 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do test "returns v2 suggestions excluding blocked accounts", %{conn: conn, user: blocker} do blocked = insert(:user, is_suggested: true) - {:ok, _} = CommonAPI.block(blocker, blocked) + {:ok, _} = CommonAPI.block(blocked, blocker) res = conn @@ -59,7 +59,7 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do test "returns v2 suggestions excluding followed accounts", %{conn: conn, user: follower} do followed = insert(:user, is_suggested: true) - {:ok, _, _, _} = CommonAPI.follow(follower, followed) + {:ok, _, _, _} = CommonAPI.follow(followed, follower) res = conn diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index c120dd53c..4d646509c 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -152,7 +152,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do end describe "public" do - @tag capture_log: true test "the public timeline", %{conn: conn} do user = insert(:user) @@ -791,7 +790,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do describe "hashtag" do setup do: oauth_access(["n/a"]) - @tag capture_log: true test "hashtag timeline", %{conn: conn} do following = insert(:user) diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 8dcdaf447..f0711fa0d 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -436,7 +436,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do {:ok, other_user, user} = User.follow(other_user, user) {:ok, _subscription} = User.subscribe(user, other_user) {:ok, _user_relationships} = User.mute(user, other_user, %{notifications: true}) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, other_user) + {:ok, _reblog_mute} = CommonAPI.hide_reblogs(other_user, user) expected = Map.merge( @@ -493,7 +493,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do user = insert(:user) other_user = insert(:user, is_locked: true) - {:ok, user, other_user, _} = CommonAPI.follow(user, other_user) + {:ok, user, other_user, _} = CommonAPI.follow(other_user, user) user = User.get_cached_by_id(user.id) other_user = User.get_cached_by_id(other_user.id) @@ -547,8 +547,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do }) other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, user, other_user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{ followers_count: 0, @@ -560,8 +560,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do test "shows when follows/followers are hidden" do user = insert(:user, hide_followers: true, hide_follows: true) other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, user, other_user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{ followers_count: 1, @@ -573,11 +573,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do test "shows actual follower/following count to the account owner" do user = insert(:user, hide_followers: true, hide_follows: true) other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, user, other_user, _activity} = CommonAPI.follow(other_user, user) assert User.following?(user, other_user) assert Pleroma.FollowingRelationship.follower_count(other_user) == 1 - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{ followers_count: 1, @@ -684,7 +684,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{follow_requests_count: 0} = AccountView.render("show.json", %{user: user, for: user}) @@ -696,7 +696,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{locked: true, follow_requests_count: 1} = AccountView.render("show.json", %{user: user, for: user}) @@ -708,7 +708,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) - {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{locked: true, follow_requests_count: 1} = AccountView.render("show.json", %{user: user, for: user}) @@ -725,7 +725,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) - {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, other_user, user, _activity} = CommonAPI.follow(user, other_user) assert %{locked: true, follow_requests_count: 1} = AccountView.render("show.json", %{user: user, for: user}) @@ -742,7 +742,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(user, other_user) {:ok, user} = User.update_and_set_cache(user, %{is_locked: false}) diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs index 47425d2a9..fae672871 100644 --- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs @@ -93,7 +93,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do user = insert(:user) another_user = insert(:user) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(create_activity.id, another_user) {:ok, [notification]} = Notification.create_notifications(favorite_activity) create_activity = Activity.get_by_id(create_activity.id) @@ -132,7 +132,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do test "Follow notification" do follower = insert(:user) followed = insert(:user) - {:ok, follower, followed, _activity} = CommonAPI.follow(follower, followed) + {:ok, follower, followed, _activity} = CommonAPI.follow(followed, follower) notification = Notification |> Repo.one() |> Repo.preload(:activity) expected = %{ @@ -290,7 +290,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do {:ok, activity} = CommonAPI.post(user, %{status: "mew"}) {:ok, _} = CommonAPI.repeat(activity.id, repeat_user) - {:ok, update} = CommonAPI.update(user, activity, %{status: "mew mew"}) + {:ok, update} = CommonAPI.update(activity, user, %{status: "mew mew"}) user = Pleroma.User.get_by_ap_id(user.ap_id) activity = Pleroma.Activity.normalize(activity) @@ -316,7 +316,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do {:ok, _} = Pleroma.UserRelationship.create_mute(user, another_user) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(create_activity.id, another_user) {:ok, [notification]} = Notification.create_notifications(favorite_activity) create_activity = Activity.get_by_id(create_activity.id) @@ -331,4 +331,31 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do test_notifications_rendering([notification], user, [expected]) end + + test "Subscribed status notification" do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, activity} = CommonAPI.post(user, %{status: "hi"}) + {:ok, [notification]} = Notification.create_notifications(activity) + + user = User.get_cached_by_id(user.id) + + expected = %{ + id: to_string(notification.id), + pleroma: %{is_seen: false, is_muted: false}, + type: "status", + account: + AccountView.render("show.json", %{ + user: user, + for: subscriber + }), + status: StatusView.render("show.json", %{activity: activity, for: subscriber}), + created_at: Utils.to_masto_date(notification.inserted_at) + } + + test_notifications_rendering([notification], subscriber, [expected]) + end end diff --git a/test/pleroma/web/mastodon_api/views/poll_view_test.exs b/test/pleroma/web/mastodon_api/views/poll_view_test.exs index 3aa73c224..6de001421 100644 --- a/test/pleroma/web/mastodon_api/views/poll_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/poll_view_test.exs @@ -74,7 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do object = Object.normalize(activity, fetch: false) - {:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1]) + {:ok, _votes, object} = CommonAPI.vote(object, voter, [0, 1]) assert match?( %{ @@ -119,7 +119,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do object = Object.normalize(activity, fetch: false) - {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2]) + {:ok, _, object} = CommonAPI.vote(object, other_user, [1, 2]) result = PollView.render("show.json", %{object: object, for: other_user}) diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index 8278724d9..0ff43ada4 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -201,7 +201,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) end - @tag capture_log: true test "returns a temporary ap_id based user for activities missing db users" do user = insert(:user) @@ -389,7 +388,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do assert status.pleroma.thread_muted == false - {:ok, activity} = CommonAPI.add_mute(user, activity) + {:ok, activity} = CommonAPI.add_mute(activity, user) status = StatusView.render("show.json", %{activity: activity, for: user}) @@ -467,7 +466,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do # Create a public post quoting the private post quote_private = - insert(:note_activity, note: insert(:note, data: %{"quoteUrl" => private_object.data["id"]})) + insert(:note_activity, + note: insert(:note, data: %{"quoteUrl" => private_object.data["id"]}) + ) status = StatusView.render("show.json", %{activity: quote_private}) @@ -478,7 +479,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do # After following the user, the quote is rendered follower = insert(:user) - CommonAPI.follow(follower, user) + CommonAPI.follow(user, follower) status = StatusView.render("show.json", %{activity: quote_private, for: follower}) assert status.pleroma.quote.id == to_string(private.id) @@ -591,45 +592,78 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do assert mention.url == recipient.ap_id end - test "attachments" do - object = %{ - "type" => "Image", - "url" => [ - %{ - "mediaType" => "image/png", - "href" => "someurl", - "width" => 200, - "height" => 100 - } - ], - "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn", - "uuid" => 6 - } + describe "attachments" do + test "Complete Mastodon style" do + object = %{ + "type" => "Image", + "url" => [ + %{ + "mediaType" => "image/png", + "href" => "someurl", + "width" => 200, + "height" => 100 + } + ], + "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn", + "uuid" => 6 + } - expected = %{ - id: "1638338801", - type: "image", - url: "someurl", - remote_url: "someurl", - preview_url: "someurl", - text_url: "someurl", - description: nil, - pleroma: %{mime_type: "image/png"}, - meta: %{original: %{width: 200, height: 100, aspect: 2}}, - blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn" - } + expected = %{ + id: "1638338801", + type: "image", + url: "someurl", + remote_url: "someurl", + preview_url: "someurl", + text_url: "someurl", + description: nil, + pleroma: %{mime_type: "image/png"}, + meta: %{original: %{width: 200, height: 100, aspect: 2}}, + blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn" + } - api_spec = Pleroma.Web.ApiSpec.spec() + api_spec = Pleroma.Web.ApiSpec.spec() - assert expected == StatusView.render("attachment.json", %{attachment: object}) - assert_schema(expected, "Attachment", api_spec) + assert expected == StatusView.render("attachment.json", %{attachment: object}) + assert_schema(expected, "Attachment", api_spec) - # If theres a "id", use that instead of the generated one - object = Map.put(object, "id", 2) - result = StatusView.render("attachment.json", %{attachment: object}) + # If theres a "id", use that instead of the generated one + object = Map.put(object, "id", 2) + result = StatusView.render("attachment.json", %{attachment: object}) - assert %{id: "2"} = result - assert_schema(result, "Attachment", api_spec) + assert %{id: "2"} = result + assert_schema(result, "Attachment", api_spec) + end + + test "Honkerific" do + object = %{ + "type" => "Image", + "url" => [ + %{ + "mediaType" => "image/png", + "href" => "someurl" + } + ], + "name" => "fool.jpeg", + "summary" => "they have played us for absolute fools." + } + + expected = %{ + blurhash: nil, + description: "they have played us for absolute fools.", + id: "1638338801", + pleroma: %{mime_type: "image/png", name: "fool.jpeg"}, + preview_url: "someurl", + remote_url: "someurl", + text_url: "someurl", + type: "image", + url: "someurl" + } + + api_spec = Pleroma.Web.ApiSpec.spec() + + assert expected == StatusView.render("attachment.json", %{attachment: object}) + assert_schema(expected, "Attachment", api_spec) + end end test "put the url advertised in the Activity in to the url attribute" do @@ -904,7 +938,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do status = StatusView.render("show.json", activity: post) refute status.edited_at - {:ok, _} = CommonAPI.update(poster, post, %{status: "mew mew"}) + {:ok, _} = CommonAPI.update(post, poster, %{status: "mew mew"}) edited = Pleroma.Activity.normalize(post) status = StatusView.render("show.json", activity: edited) diff --git a/test/pleroma/web/metadata/utils_test.exs b/test/pleroma/web/metadata/utils_test.exs index 3daf852fb..f986d3fd5 100644 --- a/test/pleroma/web/metadata/utils_test.exs +++ b/test/pleroma/web/metadata/utils_test.exs @@ -8,7 +8,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do alias Pleroma.Web.Metadata.Utils describe "scrub_html_and_truncate/1" do - test "it returns content text without encode HTML if summary is nil" do + test "it returns content text without HTML if summary is nil" do user = insert(:user) note = @@ -17,14 +17,14 @@ defmodule Pleroma.Web.Metadata.UtilsTest do "actor" => user.ap_id, "id" => "https://pleroma.gov/objects/whatever", "summary" => nil, - "content" => "Pleroma's really cool!" + "content" => "Pleroma's really cool!<br>" } }) assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!" end - test "it returns context text without encode HTML if summary is empty" do + test "it returns content text without HTML if summary is empty" do user = insert(:user) note = @@ -33,14 +33,14 @@ defmodule Pleroma.Web.Metadata.UtilsTest do "actor" => user.ap_id, "id" => "https://pleroma.gov/objects/whatever", "summary" => "", - "content" => "Pleroma's really cool!" + "content" => "Pleroma's really cool!<br>" } }) assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!" end - test "it returns summary text without encode HTML if summary is filled" do + test "it returns summary text without HTML if summary is filled" do user = insert(:user) note = @@ -48,7 +48,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do data: %{ "actor" => user.ap_id, "id" => "https://pleroma.gov/objects/whatever", - "summary" => "Public service announcement on caffeine consumption", + "summary" => "Public service announcement on caffeine consumption<br>", "content" => "cofe" } }) @@ -57,6 +57,22 @@ defmodule Pleroma.Web.Metadata.UtilsTest do "Public service announcement on caffeine consumption" end + test "it returns empty string if summary and content are absent" do + user = insert(:user) + + note = + insert(:note, %{ + data: %{ + "actor" => user.ap_id, + "id" => "https://pleroma.gov/objects/whatever", + "content" => nil, + "summary" => nil + } + }) + + assert Utils.scrub_html_and_truncate(note) == "" + end + test "it does not return old content after editing" do user = insert(:user) @@ -65,7 +81,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do object = Pleroma.Object.normalize(activity) assert Utils.scrub_html_and_truncate(object) == "mew mew #def" - {:ok, update} = Pleroma.Web.CommonAPI.update(user, activity, %{status: "mew mew #abc"}) + {:ok, update} = Pleroma.Web.CommonAPI.update(activity, user, %{status: "mew mew #abc"}) update = Pleroma.Activity.normalize(update) object = Pleroma.Object.normalize(update) assert Utils.scrub_html_and_truncate(object) == "mew mew #abc" diff --git a/test/pleroma/web/o_auth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs index 5ab8236b5..07ce2eed8 100644 --- a/test/pleroma/web/o_auth/ldap_authorization_test.exs +++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs @@ -71,7 +71,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do equalityMatch: fn _type, _value -> :ok end, wholeSubtree: fn -> :ok end, search: fn _connection, _options -> - {:ok, {:eldap_search_result, [{:eldap_entry, '', []}], []}} + {:ok, {:eldap_search_result, [{:eldap_entry, ~c"", []}], []}} end, close: fn _connection -> send(self(), :close_connection) diff --git a/test/pleroma/web/o_status/o_status_controller_test.exs b/test/pleroma/web/o_status/o_status_controller_test.exs index 3e8fcd956..5387ec94e 100644 --- a/test/pleroma/web/o_status/o_status_controller_test.exs +++ b/test/pleroma/web/o_status/o_status_controller_test.exs @@ -186,7 +186,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do user = insert(:user) - {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id) + {:ok, like_activity} = CommonAPI.favorite(note_activity.id, user) assert like_activity.data["type"] == "Like" diff --git a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs index 8f000760f..61880e2c0 100644 --- a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs @@ -78,7 +78,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do user: user } do [activity | _] = insert_pair(:note_activity) - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) response = conn @@ -95,7 +95,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do user: user } do activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) response = build_conn() @@ -115,7 +115,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do visibility: "direct" }) - CommonAPI.favorite(user, direct.id) + CommonAPI.favorite(direct.id, user) for u <- [user, current_user] do response = @@ -148,7 +148,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do visibility: "direct" }) - CommonAPI.favorite(user, direct.id) + CommonAPI.favorite(direct.id, user) response = conn @@ -165,7 +165,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do activities = insert_list(10, :note_activity) Enum.each(activities, fn activity -> - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) end) third_activity = Enum.at(activities, 2) @@ -190,7 +190,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do 7 |> insert_list(:note_activity) |> Enum.each(fn activity -> - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) end) response = @@ -222,7 +222,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do test "returns 403 error when user has hidden own favorites", %{conn: conn} do user = insert(:user, hide_favorites: true) activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") @@ -232,7 +232,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do test "hides favorites for new users by default", %{conn: conn} do user = insert(:user) activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) + CommonAPI.favorite(activity.id, user) assert user.hide_favorites conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") @@ -286,8 +286,8 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do %{id: id2} = user2 = insert(:user) %{id: id3} = user3 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.follow(user1, user3) + CommonAPI.follow(user2, user1) + CommonAPI.follow(user3, user1) User.endorse(user1, user2) User.endorse(user1, user3) @@ -324,9 +324,9 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do user3 = insert(:user) - CommonAPI.follow(user, user1) - CommonAPI.follow(user, user2) - CommonAPI.follow(user, user3) + CommonAPI.follow(user1, user) + CommonAPI.follow(user2, user) + CommonAPI.follow(user3, user) [%{"id" => ^id1}] = conn @@ -350,8 +350,8 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do show_birthday: true }) - CommonAPI.follow(user, user1) - CommonAPI.follow(user, user2) + CommonAPI.follow(user1, user) + CommonAPI.follow(user2, user) [%{"id" => ^id2}] = conn diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs index 92334487c..10dcf0e62 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -159,8 +159,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do {:ok, arch} = :zip.unzip(resp, [:memory]) - assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) - assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) + assert Enum.find(arch, fn {n, _} -> n == ~c"pack.json" end) + assert Enum.find(arch, fn {n, _} -> n == ~c"blank.png" end) end test "non existing pack", %{conn: conn} do @@ -454,7 +454,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do method: :get, url: "https://nonshared-pack" } -> - {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) + {:ok, {~c"empty.zip", empty_arch}} = :zip.zip(~c"empty.zip", [], [:memory]) text(empty_arch) end) diff --git a/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs index b8c7964f9..036cbf176 100644 --- a/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs @@ -21,13 +21,11 @@ defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do {:ok, [notification1]} = Notification.create_notifications(activity1) {:ok, [notification2]} = Notification.create_notifications(activity2) - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/notifications/read", %{id: notification1.id}) - |> json_response_and_validate_schema(:ok) + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/notifications/read", %{id: notification1.id}) + |> json_response_and_validate_schema(:ok) - assert %{"pleroma" => %{"is_seen" => true}} = response assert Repo.get(Notification, notification1.id).seen refute Repo.get(Notification, notification2.id).seen end @@ -40,14 +38,17 @@ defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3}) - [response1, response2] = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/notifications/read", %{max_id: notification2.id}) - |> json_response_and_validate_schema(:ok) + refute Repo.get(Notification, notification1.id).seen + refute Repo.get(Notification, notification2.id).seen + refute Repo.get(Notification, notification3.id).seen + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/notifications/read", %{max_id: notification2.id}) + |> json_response_and_validate_schema(:ok) + + [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3}) - assert %{"pleroma" => %{"is_seen" => true}} = response1 - assert %{"pleroma" => %{"is_seen" => true}} = response2 assert Repo.get(Notification, notification1.id).seen assert Repo.get(Notification, notification2.id).seen refute Repo.get(Notification, notification3.id).seen diff --git a/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs index f17add774..c78c03aba 100644 --- a/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs +++ b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do alias Pleroma.Chat alias Pleroma.Chat.MessageReference alias Pleroma.Object + alias Pleroma.Tests.ObanHelpers alias Pleroma.UnstubbedConfigMock, as: ConfigMock alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -70,6 +71,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do media_id: upload.id ) + ObanHelpers.perform_all() + object = Object.normalize(activity, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index c79170382..11a351a41 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -3,14 +3,52 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Plug.Conn + import Mox + + setup do + base_config = Pleroma.Config.get([:http_security]) + %{base_config: base_config} + end + + defp mock_config(config, additional \\ %{}) do + Pleroma.StaticStubbedConfigMock + |> stub(:get, fn + [:http_security, key] -> config[key] + key -> additional[key] + end) + end + describe "http security enabled" do - setup do: clear_config([:http_security, :enabled], true) + setup %{base_config: base_config} do + %{base_config: Keyword.put(base_config, :enabled, true)} + end + + test "it does not contain unsafe-eval", %{conn: conn, base_config: base_config} do + mock_config(base_config) + + conn = get(conn, "/api/v1/instance") + [header] = Conn.get_resp_header(conn, "content-security-policy") + refute header =~ ~r/unsafe-eval/ + end + + test "with allow_unsafe_eval set, it does contain it", %{conn: conn, base_config: base_config} do + base_config = + base_config + |> Keyword.put(:allow_unsafe_eval, true) + + mock_config(base_config) + + conn = get(conn, "/api/v1/instance") + [header] = Conn.get_resp_header(conn, "content-security-policy") + assert header =~ ~r/unsafe-eval/ + end - test "it sends CSP headers when enabled", %{conn: conn} do + test "it sends CSP headers when enabled", %{conn: conn, base_config: base_config} do + mock_config(base_config) conn = get(conn, "/api/v1/instance") refute Conn.get_resp_header(conn, "x-xss-protection") == [] @@ -22,8 +60,10 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do refute Conn.get_resp_header(conn, "content-security-policy") == [] end - test "it sends STS headers when enabled", %{conn: conn} do - clear_config([:http_security, :sts], true) + test "it sends STS headers when enabled", %{conn: conn, base_config: base_config} do + base_config + |> Keyword.put(:sts, true) + |> mock_config() conn = get(conn, "/api/v1/instance") @@ -31,8 +71,10 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do refute Conn.get_resp_header(conn, "expect-ct") == [] end - test "it does not send STS headers when disabled", %{conn: conn} do - clear_config([:http_security, :sts], false) + test "it does not send STS headers when disabled", %{conn: conn, base_config: base_config} do + base_config + |> Keyword.put(:sts, false) + |> mock_config() conn = get(conn, "/api/v1/instance") @@ -40,19 +82,30 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do assert Conn.get_resp_header(conn, "expect-ct") == [] end - test "referrer-policy header reflects configured value", %{conn: conn} do - resp = get(conn, "/api/v1/instance") + test "referrer-policy header reflects configured value", %{ + conn: conn, + base_config: base_config + } do + mock_config(base_config) + resp = get(conn, "/api/v1/instance") assert Conn.get_resp_header(resp, "referrer-policy") == ["same-origin"] - clear_config([:http_security, :referrer_policy], "no-referrer") + base_config + |> Keyword.put(:referrer_policy, "no-referrer") + |> mock_config resp = get(conn, "/api/v1/instance") assert Conn.get_resp_header(resp, "referrer-policy") == ["no-referrer"] end - test "it sends `report-to` & `report-uri` CSP response headers", %{conn: conn} do + test "it sends `report-to` & `report-uri` CSP response headers", %{ + conn: conn, + base_config: base_config + } do + mock_config(base_config) + conn = get(conn, "/api/v1/instance") [csp] = Conn.get_resp_header(conn, "content-security-policy") @@ -65,7 +118,11 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do "{\"endpoints\":[{\"url\":\"https://endpoint.com\"}],\"group\":\"csp-endpoint\",\"max-age\":10886400}" end - test "default values for img-src and media-src with disabled media proxy", %{conn: conn} do + test "default values for img-src and media-src with disabled media proxy", %{ + conn: conn, + base_config: base_config + } do + mock_config(base_config) conn = get(conn, "/api/v1/instance") [csp] = Conn.get_resp_header(conn, "content-security-policy") @@ -73,60 +130,129 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do assert csp =~ "img-src 'self' data: blob: https:;" end - test "it sets the Service-Worker-Allowed header", %{conn: conn} do - clear_config([:http_security, :enabled], true) - clear_config([:frontends, :primary], %{"name" => "fedi-fe", "ref" => "develop"}) - - clear_config([:frontends, :available], %{ - "fedi-fe" => %{ - "name" => "fedi-fe", - "custom-http-headers" => [{"service-worker-allowed", "/"}] - } - }) - + test "it sets the Service-Worker-Allowed header", %{conn: conn, base_config: base_config} do + base_config + |> Keyword.put(:enabled, true) + + additional_config = + %{} + |> Map.put([:frontends, :primary], %{"name" => "fedi-fe", "ref" => "develop"}) + |> Map.put( + [:frontends, :available], + %{ + "fedi-fe" => %{ + "name" => "fedi-fe", + "custom-http-headers" => [{"service-worker-allowed", "/"}] + } + } + ) + + mock_config(base_config, additional_config) conn = get(conn, "/api/v1/instance") assert Conn.get_resp_header(conn, "service-worker-allowed") == ["/"] end end describe "img-src and media-src" do - setup do - clear_config([:http_security, :enabled], true) - clear_config([:media_proxy, :enabled], true) - clear_config([:media_proxy, :proxy_opts, :redirect_on_failure], false) + setup %{base_config: base_config} do + base_config = + base_config + |> Keyword.put(:enabled, true) + + additional_config = + %{} + |> Map.put([:media_proxy, :enabled], true) + |> Map.put([:media_proxy, :proxy_opts, :redirect_on_failure], false) + |> Map.put([:media_proxy, :whitelist], []) + + %{base_config: base_config, additional_config: additional_config} end - test "media_proxy with base_url", %{conn: conn} do + test "media_proxy with base_url", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do url = "https://example.com" - clear_config([:media_proxy, :base_url], url) + + additional_config = + additional_config + |> Map.put([:media_proxy, :base_url], url) + + mock_config(base_config, additional_config) + assert_media_img_src(conn, url) end - test "upload with base url", %{conn: conn} do + test "upload with base url", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do url = "https://example2.com" - clear_config([Pleroma.Upload, :base_url], url) + + additional_config = + additional_config + |> Map.put([Pleroma.Upload, :base_url], url) + + mock_config(base_config, additional_config) + assert_media_img_src(conn, url) end - test "with S3 public endpoint", %{conn: conn} do + test "with S3 public endpoint", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do url = "https://example3.com" - clear_config([Pleroma.Uploaders.S3, :public_endpoint], url) + + additional_config = + additional_config + |> Map.put([Pleroma.Uploaders.S3, :public_endpoint], url) + + mock_config(base_config, additional_config) assert_media_img_src(conn, url) end - test "with captcha endpoint", %{conn: conn} do - clear_config([Pleroma.Captcha.Mock, :endpoint], "https://captcha.com") + test "with captcha endpoint", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do + additional_config = + additional_config + |> Map.put([Pleroma.Captcha.Mock, :endpoint], "https://captcha.com") + |> Map.put([Pleroma.Captcha, :method], Pleroma.Captcha.Mock) + + mock_config(base_config, additional_config) assert_media_img_src(conn, "https://captcha.com") end - test "with media_proxy whitelist", %{conn: conn} do - clear_config([:media_proxy, :whitelist], ["https://example6.com", "https://example7.com"]) + test "with media_proxy whitelist", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do + additional_config = + additional_config + |> Map.put([:media_proxy, :whitelist], ["https://example6.com", "https://example7.com"]) + + mock_config(base_config, additional_config) assert_media_img_src(conn, "https://example7.com https://example6.com") end # TODO: delete after removing support bare domains for media proxy whitelist - test "with media_proxy bare domains whitelist (deprecated)", %{conn: conn} do - clear_config([:media_proxy, :whitelist], ["example4.com", "example5.com"]) + test "with media_proxy bare domains whitelist (deprecated)", %{ + conn: conn, + base_config: base_config, + additional_config: additional_config + } do + additional_config = + additional_config + |> Map.put([:media_proxy, :whitelist], ["example4.com", "example5.com"]) + + mock_config(base_config, additional_config) assert_media_img_src(conn, "example5.com example4.com") end end @@ -138,8 +264,10 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do assert csp =~ "img-src 'self' data: blob: #{url};" end - test "it does not send CSP headers when disabled", %{conn: conn} do - clear_config([:http_security, :enabled], false) + test "it does not send CSP headers when disabled", %{conn: conn, base_config: base_config} do + base_config + |> Keyword.put(:enabled, false) + |> mock_config conn = get(conn, "/api/v1/instance") diff --git a/test/pleroma/web/plugs/http_signature_plug_test.exs b/test/pleroma/web/plugs/http_signature_plug_test.exs index 2d8fba3cd..9d07270bb 100644 --- a/test/pleroma/web/plugs/http_signature_plug_test.exs +++ b/test/pleroma/web/plugs/http_signature_plug_test.exs @@ -3,77 +3,89 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.StaticStubbedConfigMock, as: ConfigMock + alias Pleroma.StubbedHTTPSignaturesMock, as: HTTPSignaturesMock alias Pleroma.Web.Plugs.HTTPSignaturePlug - import Plug.Conn + import Mox import Phoenix.Controller, only: [put_format: 2] - import Mock + import Plug.Conn - test "it call HTTPSignatures to check validity if the actor sighed it" do + test "it calls HTTPSignatures to check validity if the actor signed it" do params = %{"actor" => "http://mastodon.example.org/users/admin"} conn = build_conn(:get, "/doesntmattter", params) - with_mock HTTPSignatures, validate_conn: fn _ -> true end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> put_format("activity+json") - |> HTTPSignaturePlug.call(%{}) + HTTPSignaturesMock + |> expect(:validate_conn, fn _ -> true end) - assert conn.assigns.valid_signature == true - assert conn.halted == false - assert called(HTTPSignatures.validate_conn(:_)) - end + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> put_format("activity+json") + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false end describe "requires a signature when `authorized_fetch_mode` is enabled" do setup do - clear_config([:activitypub, :authorized_fetch_mode], true) - params = %{"actor" => "http://mastodon.example.org/users/admin"} conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json") [conn: conn] end - test "when signature header is present", %{conn: conn} do - with_mock HTTPSignatures, validate_conn: fn _ -> false end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> HTTPSignaturePlug.call(%{}) - - assert conn.assigns.valid_signature == false - assert conn.halted == true - assert conn.status == 401 - assert conn.state == :sent - assert conn.resp_body == "Request not signed" - assert called(HTTPSignatures.validate_conn(:_)) - end - - with_mock HTTPSignatures, validate_conn: fn _ -> true end do - conn = - conn - |> put_req_header( - "signature", - "keyId=\"http://mastodon.example.org/users/admin#main-key" - ) - |> HTTPSignaturePlug.call(%{}) - - assert conn.assigns.valid_signature == true - assert conn.halted == false - assert called(HTTPSignatures.validate_conn(:_)) - end + test "when signature header is present", %{conn: orig_conn} do + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + |> expect(:get, fn [:activitypub, :authorized_fetch_mode_exceptions], [] -> [] end) + + HTTPSignaturesMock + |> expect(:validate_conn, 2, fn _ -> false end) + + conn = + orig_conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == false + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + + HTTPSignaturesMock + |> expect(:validate_conn, fn _ -> true end) + + conn = + orig_conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false end test "halts the connection when `signature` header is not present", %{conn: conn} do + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + |> expect(:get, fn [:activitypub, :authorized_fetch_mode_exceptions], [] -> [] end) + conn = HTTPSignaturePlug.call(conn, %{}) assert conn.assigns[:valid_signature] == nil assert conn.halted == true @@ -81,5 +93,73 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do assert conn.state == :sent assert conn.resp_body == "Request not signed" end + + test "exempts specific IPs from `authorized_fetch_mode_exceptions`", %{conn: conn} do + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + |> expect(:get, fn [:activitypub, :authorized_fetch_mode_exceptions], [] -> + ["192.168.0.0/24"] + end) + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + + HTTPSignaturesMock + |> expect(:validate_conn, 2, fn _ -> false end) + + conn = + conn + |> Map.put(:remote_ip, {192, 168, 0, 1}) + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.remote_ip == {192, 168, 0, 1} + assert conn.halted == false + end + end + + test "rejects requests from `rejected_instances` when `authorized_fetch_mode` is enabled" do + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + |> expect(:get, fn [:instance, :rejected_instances] -> + [{"mastodon.example.org", "no reason"}] + end) + + HTTPSignaturesMock + |> expect(:validate_conn, fn _ -> true end) + + conn = + build_conn(:get, "/doesntmattter", %{"actor" => "http://mastodon.example.org/users/admin"}) + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> put_format("activity+json") + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == true + + ConfigMock + |> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end) + |> expect(:get, fn [:instance, :rejected_instances] -> + [{"mastodon.example.org", "no reason"}] + end) + + HTTPSignaturesMock + |> expect(:validate_conn, fn _ -> true end) + + conn = + build_conn(:get, "/doesntmattter", %{"actor" => "http://allowed.example.org/users/admin"}) + |> put_req_header( + "signature", + "keyId=\"http://allowed.example.org/users/admin#main-key" + ) + |> put_format("activity+json") + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false end end diff --git a/test/pleroma/web/push/impl_test.exs b/test/pleroma/web/push/impl_test.exs index 3ceea3d71..ffc38dc80 100644 --- a/test/pleroma/web/push/impl_test.exs +++ b/test/pleroma/web/push/impl_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Push.ImplTest do use Pleroma.DataCase, async: true + import ExUnit.CaptureLog import Mox import Pleroma.Factory @@ -32,17 +33,6 @@ defmodule Pleroma.Web.Push.ImplTest do :ok end - @sub %{ - endpoint: "https://example.com/example/1234", - keys: %{ - auth: "8eDyX_uCN0XRhSbY5hs7Hg==", - p256dh: - "BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA=" - } - } - @api_key "BASgACIHpN1GYgzSRp" - @message "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." - test "performs sending notifications" do user = insert(:user) user2 = insert(:user) @@ -68,39 +58,65 @@ defmodule Pleroma.Web.Push.ImplTest do type: "mention" ) - assert Impl.perform(notif) == {:ok, [:ok, :ok]} - end - - @tag capture_log: true - test "returns error if notif does not match " do - assert Impl.perform(%{}) == {:error, :unknown_type} + Impl.build(notif) + |> Enum.each(fn push -> assert match?(:ok, Impl.deliver(push)) end) end - test "successful message sending" do - assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok + test "returns error if notification activity type does not match" do + assert capture_log(fn -> + assert Impl.build(%{}) == [] + end) =~ "WebPush: unknown activity type" end - @tag capture_log: true test "fail message sending" do - assert Impl.push_message( - @message, - Map.merge(@sub, %{endpoint: "https://example.com/example/bad"}), - @api_key, - %Subscription{} - ) == :error + user = insert(:user) + + insert(:push_subscription, + user: user, + endpoint: "https://example.com/example/bad", + data: %{alerts: %{"follow" => true}} + ) + + other_user = insert(:user) + {:ok, _, _, activity} = CommonAPI.follow(other_user, user) + + notif = + insert(:notification, + user: user, + activity: activity, + type: "follow" + ) + + [push] = Impl.build(notif) + + assert Impl.deliver(push) == :error end test "delete subscription if result send message between 400..500" do - subscription = insert(:push_subscription) + user = insert(:user) - assert Impl.push_message( - @message, - Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}), - @api_key, - subscription - ) == :ok + bad_subscription = + insert(:push_subscription, + user: user, + endpoint: "https://example.com/example/not_found", + data: %{alerts: %{"follow" => true}} + ) - refute Pleroma.Repo.get(Subscription, subscription.id) + other_user = insert(:user) + {:ok, _, _, activity} = CommonAPI.follow(other_user, user) + + notif = + insert(:notification, + user: user, + activity: activity, + type: "follow" + ) + + [push] = Impl.build(notif) + + assert Impl.deliver(push) == :ok + + refute Pleroma.Repo.get(Subscription, bad_subscription.id) end test "deletes subscription when token has been deleted" do @@ -129,7 +145,7 @@ defmodule Pleroma.Web.Push.ImplTest do user, object ) == - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." + "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis." assert Impl.format_title(%{activity: activity, type: "mention"}) == "New Mention" @@ -138,7 +154,7 @@ defmodule Pleroma.Web.Push.ImplTest do test "renders title and body for follow activity" do user = insert(:user, nickname: "Bob") other_user = insert(:user) - {:ok, _, _, activity} = CommonAPI.follow(user, other_user) + {:ok, _, _, activity} = CommonAPI.follow(other_user, user) object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: activity, type: "follow"}, user, object) == @@ -161,7 +177,7 @@ defmodule Pleroma.Web.Push.ImplTest do object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: announce_activity}, user, object) == - "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." + "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis." assert Impl.format_title(%{activity: announce_activity, type: "reblog"}) == "New Repeat" @@ -176,7 +192,7 @@ defmodule Pleroma.Web.Push.ImplTest do "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." }) - {:ok, activity} = CommonAPI.favorite(user, activity.id) + {:ok, activity} = CommonAPI.favorite(activity.id, user) object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: activity, type: "favourite"}, user, object) == @@ -209,7 +225,7 @@ defmodule Pleroma.Web.Push.ImplTest do {:ok, activity} = CommonAPI.post(user, %{status: "lorem ipsum"}) - {:ok, activity} = CommonAPI.update(user, activity, %{status: "edited status"}) + {:ok, activity} = CommonAPI.update(activity, user, %{status: "edited status"}) object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: activity, type: "update"}, user, object) == @@ -232,6 +248,29 @@ defmodule Pleroma.Web.Push.ImplTest do "New Direct Message" end + test "renders poll notification" do + user = insert(:user) + question = insert(:question, user: user) + activity = insert(:question_activity, question: question) + + {:ok, [notification]} = Notification.create_poll_notifications(activity) + + expected_title = "Poll Results" + + expected_body = + """ + Which flavor of ice cream do you prefer? + + ○ chocolate + ○ vanilla + """ + |> String.trim_trailing("\n") + + content = Impl.build_content(notification, user, question) + + assert match?(%{title: ^expected_title, body: ^expected_body}, content) + end + describe "build_content/3" do test "builds content for chat messages" do user = insert(:user) @@ -312,7 +351,7 @@ defmodule Pleroma.Web.Push.ImplTest do body: "New Mention" } - {:ok, activity} = CommonAPI.favorite(user, activity.id) + {:ok, activity} = CommonAPI.favorite(activity.id, user) notif = insert(:notification, user: user2, activity: activity, type: "favourite") @@ -328,7 +367,10 @@ defmodule Pleroma.Web.Push.ImplTest do user = insert(:user, nickname: "Bob") user2 = - insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: false}) + insert(:user, + nickname: "Rob", + notification_settings: %{hide_notification_contents: false} + ) {:ok, activity} = CommonAPI.post(user, %{ @@ -344,7 +386,7 @@ defmodule Pleroma.Web.Push.ImplTest do assert Impl.build_content(notif, actor, object) == %{ body: - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...", + "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis.", title: "New Direct Message" } @@ -362,11 +404,11 @@ defmodule Pleroma.Web.Push.ImplTest do assert Impl.build_content(notif, actor, object) == %{ body: - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...", + "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis.", title: "New Mention" } - {:ok, activity} = CommonAPI.favorite(user, activity.id) + {:ok, activity} = CommonAPI.favorite(activity.id, user) notif = insert(:notification, user: user2, activity: activity, type: "favourite") @@ -379,4 +421,23 @@ defmodule Pleroma.Web.Push.ImplTest do } end end + + test "build/1 notification payload body starts with nickname of actor the notification originated from" do + user = insert(:user, nickname: "Bob") + user2 = insert(:user, nickname: "Tom") + insert(:push_subscription, user: user2, data: %{alerts: %{"mention" => true}}) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "@Tom Hey are you okay?" + }) + + {:ok, [notification]} = Notification.create_notifications(activity) + + [push] = Impl.build(notification) + + {:ok, payload} = Jason.decode(push.payload) + + assert String.starts_with?(payload["body"], "@Bob:") + end end diff --git a/test/pleroma/web/rich_media/backfill_test.exs b/test/pleroma/web/rich_media/backfill_test.exs new file mode 100644 index 000000000..6d221fcf5 --- /dev/null +++ b/test/pleroma/web/rich_media/backfill_test.exs @@ -0,0 +1,26 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.RichMedia.BackfillTest do + use Pleroma.DataCase + + alias Pleroma.Web.RichMedia.Backfill + alias Pleroma.Web.RichMedia.Card + + import Mox + + setup_all do: clear_config([:rich_media, :enabled], true) + + test "sets a negative cache entry for an error" do + url = "https://bad.example.com/" + url_hash = Card.url_to_hash(url) + + Tesla.Mock.mock(fn %{url: ^url} -> :error end) + + Pleroma.CachexMock + |> expect(:put, fn :rich_media_cache, ^url_hash, :error, ttl: _ -> {:ok, true} end) + + Backfill.run(%{"url" => url}) + end +end diff --git a/test/pleroma/web/rich_media/card_test.exs b/test/pleroma/web/rich_media/card_test.exs index 516ac9951..387defc8c 100644 --- a/test/pleroma/web/rich_media/card_test.exs +++ b/test/pleroma/web/rich_media/card_test.exs @@ -3,11 +3,14 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RichMedia.CardTest do + use Oban.Testing, repo: Pleroma.Repo use Pleroma.DataCase, async: true + alias Pleroma.Tests.ObanHelpers alias Pleroma.UnstubbedConfigMock, as: ConfigMock alias Pleroma.Web.CommonAPI alias Pleroma.Web.RichMedia.Card + alias Pleroma.Workers.RichMediaWorker import Mox import Pleroma.Factory @@ -36,6 +39,16 @@ defmodule Pleroma.Web.RichMedia.CardTest do content_type: "text/markdown" }) + Pleroma.Web.ActivityPub.ActivityPubMock + |> expect(:stream_out, fn ^activity -> nil end) + + assert_enqueued( + worker: RichMediaWorker, + args: %{"url" => url, "activity_id" => activity.id} + ) + + ObanHelpers.perform_all() + assert %Card{url_hash: ^url_hash, fields: _} = Card.get_by_activity(activity) end @@ -50,18 +63,20 @@ defmodule Pleroma.Web.RichMedia.CardTest do # Force a backfill Card.get_by_activity(activity) + ObanHelpers.perform_all() assert match?( %Card{url_hash: ^original_url_hash, fields: _}, Card.get_by_activity(activity) ) - {:ok, _} = CommonAPI.update(user, activity, %{status: "I like this site #{updated_url}"}) + {:ok, _} = CommonAPI.update(activity, user, %{status: "I like this site #{updated_url}"}) activity = Pleroma.Activity.get_by_id(activity.id) # Force a backfill Card.get_by_activity(activity) + ObanHelpers.perform_all() assert match?( %Card{url_hash: ^updated_url_hash, fields: _}, diff --git a/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs index cd8be8675..e02dd437a 100644 --- a/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs +++ b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs @@ -4,12 +4,14 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do use Pleroma.DataCase, async: false - use Oban.Testing, repo: Pleroma.Repo + use Oban.Testing, repo: Pleroma.Repo, testing: :inline import Mox + alias Pleroma.Tests.ObanHelpers alias Pleroma.UnstubbedConfigMock, as: ConfigMock alias Pleroma.Web.RichMedia.Card + alias Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl setup do ConfigMock @@ -73,15 +75,31 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do Card.get_or_backfill_by_url(url) - assert_enqueued(worker: Pleroma.Workers.RichMediaExpirationWorker, args: %{"url" => url}) + # Find the backfill job + expected_job = + [ + worker: "Pleroma.Workers.RichMediaWorker", + args: %{"op" => "backfill", "url" => url} + ] - [%Oban.Job{scheduled_at: scheduled_at}] = all_enqueued() + assert_enqueued(expected_job) + + # Run it manually + ObanHelpers.perform_all() + + [%Oban.Job{scheduled_at: scheduled_at} | _] = all_enqueued() timestamp_dt = Timex.parse!(timestamp, "{ISO:Basic:Z}") assert DateTime.diff(scheduled_at, timestamp_dt) == valid_till end + test "AWS URL for an image without expiration works" do + og_data = %{"image" => "https://amazonaws.com/image.png"} + + assert is_nil(AwsSignedUrl.ttl(og_data, "")) + end + defp construct_s3_url(timestamp, valid_till) do "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{timestamp}&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host" end diff --git a/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs b/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs index 770968d47..6805e786d 100644 --- a/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs +++ b/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.OpengraphTest do import Mox + alias Pleroma.Tests.ObanHelpers alias Pleroma.UnstubbedConfigMock, as: ConfigMock alias Pleroma.Web.RichMedia.Card @@ -36,6 +37,21 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.OpengraphTest do Card.get_or_backfill_by_url(url) - assert_enqueued(worker: Pleroma.Workers.RichMediaExpirationWorker, args: %{"url" => url}) + # Find the backfill job + expected_job = + [ + worker: "Pleroma.Workers.RichMediaWorker", + args: %{"op" => "backfill", "url" => url} + ] + + assert_enqueued(expected_job) + + # Run it manually + ObanHelpers.perform_all() + + assert_enqueued( + worker: Pleroma.Workers.RichMediaWorker, + args: %{"op" => "expire", "url" => url} + ) end end diff --git a/test/pleroma/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs index 3fcb5c808..8fd75b57a 100644 --- a/test/pleroma/web/rich_media/parser_test.exs +++ b/test/pleroma/web/rich_media/parser_test.exs @@ -13,12 +13,14 @@ defmodule Pleroma.Web.RichMedia.ParserTest do mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) end + setup_all do: clear_config([:rich_media, :enabled], true) + test "returns error when no metadata present" do assert {:error, _} = Parser.parse("https://example.com/empty") end test "doesn't just add a title" do - assert {:error, {:invalid_metadata, _}} = Parser.parse("https://example.com/non-ogp") + assert {:error, :invalid_metadata} = Parser.parse("https://example.com/non-ogp") end test "parses ogp" do @@ -94,7 +96,7 @@ defmodule Pleroma.Web.RichMedia.ParserTest do end test "returns error if getting page was not successful" do - assert {:error, :overload} = Parser.parse("https://example.com/error") + assert {:error, :get} = Parser.parse("https://example.com/error") end test "does a HEAD request to check if the body is too large" do @@ -102,17 +104,17 @@ defmodule Pleroma.Web.RichMedia.ParserTest do end test "does a HEAD request to check if the body is html" do - assert {:error, {:content_type, _}} = Parser.parse("https://example.com/pdf-file") + assert {:error, :content_type} = Parser.parse("https://example.com/pdf-file") end test "refuses to crawl incomplete URLs" do url = "example.com/ogp" - assert :error == Parser.parse(url) + assert {:error, :validate} == Parser.parse(url) end test "refuses to crawl malformed URLs" do url = "example.com[]/ogp" - assert :error == Parser.parse(url) + assert {:error, :validate} == Parser.parse(url) end test "refuses to crawl URLs of private network from posts" do @@ -124,7 +126,13 @@ defmodule Pleroma.Web.RichMedia.ParserTest do "https://pleroma.local/notice/9kCP7V" ] |> Enum.each(fn url -> - assert :error == Parser.parse(url) + assert {:error, :validate} == Parser.parse(url) end) end + + test "returns error when disabled" do + clear_config([:rich_media, :enabled], false) + + assert match?({:error, :rich_media_disabled}, Parser.parse("https://example.com/ogp")) + end end diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index d85358fd4..262ff11d2 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -418,7 +418,7 @@ defmodule Pleroma.Web.StreamerTest do Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, activity} = CommonAPI.post(user, %{status: ":("}) - {:ok, _} = CommonAPI.favorite(blocked, activity.id) + {:ok, _} = CommonAPI.favorite(activity.id, blocked) refute_receive _ end @@ -430,11 +430,11 @@ defmodule Pleroma.Web.StreamerTest do user2 = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - {:ok, _} = CommonAPI.add_mute(user, activity) + {:ok, _} = CommonAPI.add_mute(activity, user) Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2) refute_receive _ assert Streamer.filtered_by_user?(user, favorite_activity) @@ -448,7 +448,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2) assert_receive {:render_with_user, _, "notification.json", notif, _} assert notif.activity.id == favorite_activity.id @@ -464,7 +464,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, user} = User.block_domain(user, "hecking-lewd-place.com") {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) + {:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2) refute_receive _ assert Streamer.filtered_by_user?(user, favorite_activity) @@ -477,7 +477,7 @@ defmodule Pleroma.Web.StreamerTest do user2 = insert(:user) Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) - {:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user) + {:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user, user2) assert_receive {:render_with_user, _, "notification.json", notif, _} assert notif.activity.id == follow_activity.id @@ -493,7 +493,7 @@ defmodule Pleroma.Web.StreamerTest do other_user_id = other_user.id Streamer.get_topic_and_add_socket("user", user, oauth_token) - {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(user, other_user) + {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(other_user, user) assert_receive {:text, event} @@ -536,12 +536,12 @@ defmodule Pleroma.Web.StreamerTest do test "it streams edits in the 'user' stream", %{user: user, token: oauth_token} do sender = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, sender) + {:ok, _, _, _} = CommonAPI.follow(sender, user) {:ok, activity} = CommonAPI.post(sender, %{status: "hey"}) Streamer.get_topic_and_add_socket("user", user, oauth_token) - {:ok, edited} = CommonAPI.update(sender, activity, %{status: "mew mew"}) + {:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"}) create = Pleroma.Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) assert_receive {:render_with_user, _, "status_update.json", ^create, _} @@ -552,7 +552,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) Streamer.get_topic_and_add_socket("user", user, oauth_token) - {:ok, edited} = CommonAPI.update(user, activity, %{status: "mew mew"}) + {:ok, edited} = CommonAPI.update(activity, user, %{status: "mew mew"}) create = Pleroma.Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) assert_receive {:render_with_user, _, "status_update.json", ^create, _} @@ -608,7 +608,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, activity} = CommonAPI.post(sender, %{status: "hey"}) assert_receive {:text, _} - {:ok, edited} = CommonAPI.update(sender, activity, %{status: "mew mew"}) + {:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"}) edited = Pleroma.Activity.normalize(edited) @@ -627,7 +627,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, activity} = CommonAPI.post(sender, %{status: "hey"}) assert_receive {:text, _} - {:ok, edited} = CommonAPI.update(sender, activity, %{status: "mew mew"}) + {:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"}) edited = Pleroma.Activity.normalize(edited) @@ -638,7 +638,7 @@ defmodule Pleroma.Web.StreamerTest do assert %{"id" => ^activity_id} = Jason.decode!(payload) refute Streamer.filtered_by_user?(sender, edited) - {:ok, edited} = CommonAPI.update(sender, activity, %{status: "mew mew 2"}) + {:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew 2"}) edited = Pleroma.Activity.normalize(edited) @@ -826,8 +826,8 @@ defmodule Pleroma.Web.StreamerTest do test "it filters muted reblogs", %{user: user1, token: user1_token} do user2 = insert(:user) user3 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) + CommonAPI.follow(user2, user1) + CommonAPI.hide_reblogs(user2, user1) {:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"}) @@ -842,8 +842,8 @@ defmodule Pleroma.Web.StreamerTest do token: user1_token } do user2 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) + CommonAPI.follow(user2, user1) + CommonAPI.hide_reblogs(user2, user1) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) Streamer.get_topic_and_add_socket("user", user1, user1_token) @@ -858,12 +858,12 @@ defmodule Pleroma.Web.StreamerTest do token: user1_token } do user2 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) + CommonAPI.follow(user2, user1) + CommonAPI.hide_reblogs(user2, user1) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) Streamer.get_topic_and_add_socket("user", user1, user1_token) - {:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id) + {:ok, _favorite_activity} = CommonAPI.favorite(create_activity.id, user2) assert_receive {:render_with_user, _, "notification.json", notif, _} refute Streamer.filtered_by_user?(user1, notif) @@ -876,9 +876,9 @@ defmodule Pleroma.Web.StreamerTest do %{user: user2, token: user2_token} = oauth_access(["read"]) Streamer.get_topic_and_add_socket("user", user2, user2_token) - {:ok, user2, user, _activity} = CommonAPI.follow(user2, user) + {:ok, user2, user, _activity} = CommonAPI.follow(user, user2) {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - {:ok, _} = CommonAPI.add_mute(user2, activity) + {:ok, _} = CommonAPI.add_mute(activity, user2) assert_receive {:render_with_user, _, _, ^activity, _} assert Streamer.filtered_by_user?(user2, activity) @@ -1026,8 +1026,8 @@ defmodule Pleroma.Web.StreamerTest do %{user: user2, token: user2_token} = oauth_access(["read"]) post_user = insert(:user) - CommonAPI.follow(user, post_user) - CommonAPI.follow(user2, post_user) + CommonAPI.follow(post_user, user) + CommonAPI.follow(post_user, user2) tasks = [ Task.async(child_proc.(starter.(user, token), hit)), @@ -1058,7 +1058,7 @@ defmodule Pleroma.Web.StreamerTest do %{user: user, token: token} = oauth_access(["read"]) post_user = insert(:user) - CommonAPI.follow(user, post_user) + CommonAPI.follow(post_user, user) tasks = [ Task.async(child_proc.(starter.(user, token), hit)), diff --git a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index c6ecb53f4..f762b1356 100644 --- a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -216,7 +216,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do test "returns success result when user already in followers", %{conn: conn} do user = insert(:user) user2 = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _, _, _} = CommonAPI.follow(user2, user) conn = conn diff --git a/test/pleroma/web/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs index be5e08776..aefe7b0c2 100644 --- a/test/pleroma/web/web_finger_test.exs +++ b/test/pleroma/web/web_finger_test.exs @@ -76,15 +76,6 @@ defmodule Pleroma.Web.WebFingerTest do {:ok, _data} = WebFinger.finger(user) end - test "returns the ActivityPub actor URI and subscribe address for an ActivityPub user with the ld+json mimetype" do - user = "kaniini@gerzilla.de" - - {:ok, data} = WebFinger.finger(user) - - assert data["ap_id"] == "https://gerzilla.de/channel/kaniini" - assert data["subscribe_address"] == "https://gerzilla.de/follow?f=&url={uri}" - end - test "it work for AP-only user" do user = "kpherox@mstdn.jp" @@ -99,12 +90,6 @@ defmodule Pleroma.Web.WebFingerTest do assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}" end - test "it works for friendica" do - user = "lain@squeet.me" - - {:ok, _data} = WebFinger.finger(user) - end - test "it gets the xrd endpoint" do {:ok, template} = WebFinger.find_lrdd_template("social.heldscal.la") @@ -203,5 +188,43 @@ defmodule Pleroma.Web.WebFingerTest do assert :error = WebFinger.finger("pekorino@pawoo.net") end + + test "prevents spoofing" do + Tesla.Mock.mock(fn + %{ + url: "https://gleasonator.com/.well-known/webfinger?resource=acct:alex@gleasonator.com" + } -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/webfinger_spoof.json"), + headers: [{"content-type", "application/jrd+json"}] + }} + + %{url: "https://gleasonator.com/.well-known/host-meta"} -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/gleasonator.com_host_meta") + }} + end) + + {:error, _data} = WebFinger.finger("alex@gleasonator.com") + end + end + + test "prevents forgeries" do + Tesla.Mock.mock(fn + %{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} -> + fake_webfinger = + File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!() + + Tesla.Mock.json(fake_webfinger) + + %{url: "https://fba.ryona.agency/.well-known/host-meta"} -> + {:ok, %Tesla.Env{status: 404}} + end) + + assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency") end end diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs new file mode 100644 index 000000000..749df8aff --- /dev/null +++ b/test/pleroma/workers/poll_worker_test.exs @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.PollWorkerTest do + use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo + + import Mock + import Pleroma.Factory + + alias Pleroma.Workers.PollWorker + + test "poll notification job" do + user = insert(:user) + question = insert(:question, user: user) + activity = insert(:question_activity, question: question) + + PollWorker.schedule_poll_end(activity) + + expected_job_args = %{"activity_id" => activity.id, "op" => "poll_end"} + + assert_enqueued(args: expected_job_args) + + with_mocks([ + { + Pleroma.Web.Streamer, + [], + [ + stream: fn _, _ -> nil end + ] + }, + { + Pleroma.Web.Push, + [], + [ + send: fn _ -> nil end + ] + } + ]) do + [job] = all_enqueued(worker: PollWorker) + PollWorker.perform(job) + + # Ensure notifications were streamed out when job executes + assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_)) + assert called(Pleroma.Web.Push.send(:_)) + end + end +end diff --git a/test/pleroma/workers/purge_expired_activity_test.exs b/test/pleroma/workers/purge_expired_activity_test.exs index 0372f54ca..040ff6a51 100644 --- a/test/pleroma/workers/purge_expired_activity_test.exs +++ b/test/pleroma/workers/purge_expired_activity_test.exs @@ -42,7 +42,7 @@ defmodule Pleroma.Workers.PurgeExpiredActivityTest do user = Pleroma.User.get_by_ap_id(activity.actor) Pleroma.Repo.delete(user) - assert {:error, :user_not_found} = + assert {:cancel, :user_not_found} = perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: activity.id}) end @@ -53,7 +53,7 @@ defmodule Pleroma.Workers.PurgeExpiredActivityTest do expires_at: DateTime.add(DateTime.utc_now(), 3601) }) - assert {:error, :activity_not_found} = + assert {:cancel, :activity_not_found} = perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: "some_if"}) end end diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs index b9b6d6af2..33be91085 100644 --- a/test/pleroma/workers/receiver_worker_test.exs +++ b/test/pleroma/workers/receiver_worker_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do import Mock import Pleroma.Factory + alias Pleroma.Web.Federator alias Pleroma.Workers.ReceiverWorker test "it does not retry MRF reject" do @@ -16,7 +17,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do with_mock Pleroma.Web.ActivityPub.Transmogrifier, handle_incoming: fn _ -> {:reject, "MRF"} end do - assert {:cancel, "MRF"} = + assert {:cancel, {:reject, "MRF"}} = ReceiverWorker.perform(%Oban.Job{ args: %{"op" => "incoming_ap_doc", "params" => params} }) @@ -49,4 +50,199 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do args: %{"op" => "incoming_ap_doc", "params" => params} }) end + + test "it can validate the signature" do + Tesla.Mock.mock(fn + %{url: "https://mastodon.social/users/bastianallgeier"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/bastianallgeier.json"), + headers: [{"content-type", "application/activity+json"}] + } + + %{url: "https://mastodon.social/users/bastianallgeier/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "bastianallgeier") + } + + %{url: "https://phpc.social/users/denniskoch"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/denniskoch.json"), + headers: [{"content-type", "application/activity+json"}] + } + + %{url: "https://phpc.social/users/denniskoch/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "phpc.social") + |> String.replace("{{nickname}}", "denniskoch") + } + + %{url: "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/receiver_worker_signature_activity.json") + } + end) + + params = %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + %{ + "claim" => %{"@id" => "toot:claim", "@type" => "@id"}, + "memorial" => "toot:memorial", + "atomUri" => "ostatus:atomUri", + "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", + "blurhash" => "toot:blurhash", + "ostatus" => "http://ostatus.org#", + "discoverable" => "toot:discoverable", + "focalPoint" => %{"@container" => "@list", "@id" => "toot:focalPoint"}, + "votersCount" => "toot:votersCount", + "Hashtag" => "as:Hashtag", + "Emoji" => "toot:Emoji", + "alsoKnownAs" => %{"@id" => "as:alsoKnownAs", "@type" => "@id"}, + "sensitive" => "as:sensitive", + "movedTo" => %{"@id" => "as:movedTo", "@type" => "@id"}, + "inReplyToAtomUri" => "ostatus:inReplyToAtomUri", + "conversation" => "ostatus:conversation", + "Device" => "toot:Device", + "schema" => "http://schema.org#", + "toot" => "http://joinmastodon.org/ns#", + "cipherText" => "toot:cipherText", + "suspended" => "toot:suspended", + "messageType" => "toot:messageType", + "featuredTags" => %{"@id" => "toot:featuredTags", "@type" => "@id"}, + "Curve25519Key" => "toot:Curve25519Key", + "deviceId" => "toot:deviceId", + "Ed25519Signature" => "toot:Ed25519Signature", + "featured" => %{"@id" => "toot:featured", "@type" => "@id"}, + "devices" => %{"@id" => "toot:devices", "@type" => "@id"}, + "value" => "schema:value", + "PropertyValue" => "schema:PropertyValue", + "messageFranking" => "toot:messageFranking", + "publicKeyBase64" => "toot:publicKeyBase64", + "identityKey" => %{"@id" => "toot:identityKey", "@type" => "@id"}, + "Ed25519Key" => "toot:Ed25519Key", + "indexable" => "toot:indexable", + "EncryptedMessage" => "toot:EncryptedMessage", + "fingerprintKey" => %{"@id" => "toot:fingerprintKey", "@type" => "@id"} + } + ], + "actor" => "https://phpc.social/users/denniskoch", + "cc" => [ + "https://phpc.social/users/denniskoch/followers", + "https://mastodon.social/users/bastianallgeier", + "https://chaos.social/users/distantnative", + "https://fosstodon.org/users/kev" + ], + "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/activity", + "object" => %{ + "atomUri" => "https://phpc.social/users/denniskoch/statuses/112847382711461301", + "attachment" => [], + "attributedTo" => "https://phpc.social/users/denniskoch", + "cc" => [ + "https://phpc.social/users/denniskoch/followers", + "https://mastodon.social/users/bastianallgeier", + "https://chaos.social/users/distantnative", + "https://fosstodon.org/users/kev" + ], + "content" => + "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>", + "contentMap" => %{ + "en" => + "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>" + }, + "conversation" => + "tag:mastodon.social,2024-07-25:objectId=760068442:objectType=Conversation", + "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301", + "inReplyTo" => + "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281", + "inReplyToAtomUri" => + "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281", + "published" => "2024-07-25T13:33:29Z", + "replies" => %{ + "first" => %{ + "items" => [], + "next" => + "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies?only_other_accounts=true&page=true", + "partOf" => + "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies", + "type" => "CollectionPage" + }, + "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies", + "type" => "Collection" + }, + "sensitive" => false, + "tag" => [ + %{ + "href" => "https://mastodon.social/users/bastianallgeier", + "name" => "@bastianallgeier@mastodon.social", + "type" => "Mention" + }, + %{ + "href" => "https://chaos.social/users/distantnative", + "name" => "@distantnative@chaos.social", + "type" => "Mention" + }, + %{ + "href" => "https://fosstodon.org/users/kev", + "name" => "@kev@fosstodon.org", + "type" => "Mention" + } + ], + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Note", + "url" => "https://phpc.social/@denniskoch/112847382711461301" + }, + "published" => "2024-07-25T13:33:29Z", + "signature" => %{ + "created" => "2024-07-25T13:33:29Z", + "creator" => "https://phpc.social/users/denniskoch#main-key", + "signatureValue" => + "slz9BKJzd2n1S44wdXGOU+bV/wsskdgAaUpwxj8R16mYOL8+DTpE6VnfSKoZGsBBJT8uG5gnVfVEz1YsTUYtymeUgLMh7cvd8VnJnZPS+oixbmBRVky/Myf91TEgQQE7G4vDmTdB4ii54hZrHcOOYYf5FKPNRSkMXboKA6LMqNtekhbI+JTUJYIB02WBBK6PUyo15f6B1RJ6HGWVgud9NE0y1EZXfrkqUt682p8/9D49ORf7AwjXUJibKic2RbPvhEBj70qUGfBm4vvgdWhSUn1IG46xh+U0+NrTSUED82j1ZVOeua/2k/igkGs8cSBkY35quXTkPz6gbqCCH66CuA==", + "type" => "RsaSignature2017" + }, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create" + } + + req_headers = [ + ["accept-encoding", "gzip"], + ["content-length", "5184"], + ["content-type", "application/activity+json"], + ["date", "Thu, 25 Jul 2024 13:33:31 GMT"], + ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="], + ["host", "bikeshed.party"], + [ + "signature", + "keyId=\"https://mastodon.social/users/bastianallgeier#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"ymE3vn5Iw50N6ukSp8oIuXJB5SBjGAGjBasdTDvn+ahZIzq2SIJfmVCsIIzyqIROnhWyQoTbavTclVojEqdaeOx+Ejz2wBnRBmhz5oemJLk4RnnCH0lwMWyzeY98YAvxi9Rq57Gojuv/1lBqyGa+rDzynyJpAMyFk17XIZpjMKuTNMCbjMDy76ILHqArykAIL/v1zxkgwxY/+ELzxqMpNqtZ+kQ29znNMUBB3eVZ/mNAHAz6o33Y9VKxM2jw+08vtuIZOusXyiHbRiaj2g5HtN2WBUw1MzzfRfHF2/yy7rcipobeoyk5RvP5SyHV3WrIeZ3iyoNfmv33y8fxllF0EA==\"" + ], + [ + "user-agent", + "http.rb/5.2.0 (Mastodon/4.3.0-nightly.2024-07-25; +https://mastodon.social/)" + ] + ] + + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: req_headers, + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job) + end end diff --git a/test/pleroma/workers/remote_fetcher_worker_test.exs b/test/pleroma/workers/remote_fetcher_worker_test.exs index c30e773d4..2104baab2 100644 --- a/test/pleroma/workers/remote_fetcher_worker_test.exs +++ b/test/pleroma/workers/remote_fetcher_worker_test.exs @@ -39,19 +39,19 @@ defmodule Pleroma.Workers.RemoteFetcherWorkerTest do end test "does not requeue a deleted object" do - assert {:discard, _} = + assert {:cancel, _} = RemoteFetcherWorker.perform(%Oban.Job{ args: %{"op" => "fetch_remote", "id" => @deleted_object_one} }) - assert {:discard, _} = + assert {:cancel, _} = RemoteFetcherWorker.perform(%Oban.Job{ args: %{"op" => "fetch_remote", "id" => @deleted_object_two} }) end test "does not requeue an unauthorized object" do - assert {:discard, _} = + assert {:cancel, _} = RemoteFetcherWorker.perform(%Oban.Job{ args: %{"op" => "fetch_remote", "id" => @unauthorized_object} }) @@ -60,7 +60,7 @@ defmodule Pleroma.Workers.RemoteFetcherWorkerTest do test "does not requeue an object that exceeded depth" do clear_config([:instance, :federation_incoming_replies_max_depth], 0) - assert {:discard, _} = + assert {:cancel, _} = RemoteFetcherWorker.perform(%Oban.Job{ args: %{"op" => "fetch_remote", "id" => @depth_object, "depth" => 1} }) diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 14403f0b8..52d4bef1a 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -116,6 +116,7 @@ defmodule Pleroma.DataCase do Mox.stub_with(Pleroma.Web.FederatorMock, Pleroma.Web.Federator) Mox.stub_with(Pleroma.ConfigMock, Pleroma.Config) Mox.stub_with(Pleroma.StaticStubbedConfigMock, Pleroma.Test.StaticConfig) + Mox.stub_with(Pleroma.StubbedHTTPSignaturesMock, Pleroma.Test.HTTPSignaturesProxy) end def ensure_local_uploader(context) do diff --git a/test/support/factory.ex b/test/support/factory.ex index 20bc5162e..b248508fa 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -249,6 +249,7 @@ defmodule Pleroma.Factory do "cc" => [user.follower_address], "context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(), "closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(), + "content" => "Which flavor of ice cream do you prefer?", "oneOf" => [ %{ "type" => "Note", diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index f656c9412..ed044cf98 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1521,6 +1521,120 @@ defmodule HttpRequestMock do }} end + def get("https://mastodon.example/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 302, + headers: [{"location", "https://sub.mastodon.example/.well-known/host-meta"}] + }} + end + + def get("https://sub.mastodon.example/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-host-meta.xml" + |> File.read!() + |> String.replace("{{domain}}", "sub.mastodon.example") + }} + end + + def get( + "https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example", + _, + _, + _ + ) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-webfinger.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "mastodon.example") + |> String.replace("{{subdomain}}", "sub.mastodon.example"), + headers: [{"content-type", "application/jrd+json"}] + }} + end + + def get("https://sub.mastodon.example/users/a", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-user.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "sub.mastodon.example"), + headers: [{"content-type", "application/activity+json"}] + }} + end + + def get("https://sub.mastodon.example/users/a/collections/featured", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "sub.mastodon.example") + |> String.replace("{{nickname}}", "a"), + headers: [{"content-type", "application/activity+json"}] + }} + end + + def get("https://pleroma.example/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 302, + headers: [{"location", "https://sub.pleroma.example/.well-known/host-meta"}] + }} + end + + def get("https://sub.pleroma.example/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-host-meta.xml" + |> File.read!() + |> String.replace("{{domain}}", "sub.pleroma.example") + }} + end + + def get( + "https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@pleroma.example", + _, + _, + _ + ) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-webfinger.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "pleroma.example") + |> String.replace("{{subdomain}}", "sub.pleroma.example"), + headers: [{"content-type", "application/jrd+json"}] + }} + end + + def get("https://sub.pleroma.example/users/a", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-user.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "sub.pleroma.example"), + headers: [{"content-type", "application/activity+json"}] + }} + end + def get(url, query, body, headers) do {:error, "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"} @@ -1610,7 +1724,7 @@ defmodule HttpRequestMock do ] def head(url, _query, _body, _headers) when url in @rich_media_mocks do - {:ok, %Tesla.Env{status: 404, body: ""}} + {:ok, %Tesla.Env{status: 200, body: ""}} end def head("https://example.com/pdf-file", _, _, _) do diff --git a/test/support/http_signatures_proxy.ex b/test/support/http_signatures_proxy.ex new file mode 100644 index 000000000..4c6b39d19 --- /dev/null +++ b/test/support/http_signatures_proxy.ex @@ -0,0 +1,9 @@ +defmodule Pleroma.Test.HTTPSignaturesProxy do + @behaviour Pleroma.HTTPSignaturesAPI + + @impl true + defdelegate validate_conn(conn), to: HTTPSignatures + + @impl true + defdelegate signature_for_conn(conn), to: HTTPSignatures +end diff --git a/test/support/mocks.ex b/test/support/mocks.ex index d906f0e1d..63cbc49ab 100644 --- a/test/support/mocks.ex +++ b/test/support/mocks.ex @@ -28,6 +28,7 @@ Mox.defmock(Pleroma.Web.FederatorMock, for: Pleroma.Web.Federator.Publishing) Mox.defmock(Pleroma.ConfigMock, for: Pleroma.Config.Getting) Mox.defmock(Pleroma.UnstubbedConfigMock, for: Pleroma.Config.Getting) Mox.defmock(Pleroma.StaticStubbedConfigMock, for: Pleroma.Config.Getting) +Mox.defmock(Pleroma.StubbedHTTPSignaturesMock, for: Pleroma.HTTPSignaturesAPI) Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging) diff --git a/test/test_helper.exs b/test/test_helper.exs index a117584ae..fed7ce8a7 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -4,9 +4,9 @@ Code.put_compiler_option(:warnings_as_errors, true) -ExUnit.configure(max_cases: System.schedulers_online()) +ExUnit.configure(capture_log: true, max_cases: System.schedulers_online()) -ExUnit.start(exclude: [:federated, :erratic]) +ExUnit.start(exclude: [:federated]) if match?({:unix, :darwin}, :os.type()) do excluded = ExUnit.configuration() |> Keyword.get(:exclude, []) |