X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fweb%2Factivity_pub%2Factivity_pub_test.exs;h=7735e1bf8334f263f1c49c1cac4155b4daf27697;hb=2d775bf1be5ddf0a8c5553ef15dde55c2483c1d4;hp=5cfd46238b1077eabcadf1655f68188af9c4c34c;hpb=7469616f44ddca66858e6d64040b24b7986a742e;p=akkoma diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 5cfd46238..7735e1bf8 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1,10 +1,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do use Pleroma.DataCase alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.{Activity, Object} + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.{Activity, Object, User} alias Pleroma.Builders.ActivityBuilder + import Pleroma.Factory + + describe "building a user from his ap id" do + test "it returns a user" do + user_id = "http://mastodon.example.org/users/admin" + {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) + assert user.ap_id == user_id + assert user.nickname == "admin@mastodon.example.org" + assert user.info["source_data"] + assert user.info["ap_enabled"] + assert user.follower_address == "http://mastodon.example.org/users/admin/followers" + end + end + describe "insertion" do + test "returns the activity if one with the same id is already in" do + activity = insert(:note_activity) + {:ok, new_activity} = ActivityPub.insert(activity.data) + + assert activity == new_activity + end + test "inserts a given map into the activity database, giving it an id if it has none." do data = %{ "ok" => true @@ -15,19 +37,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert is_binary(activity.data["id"]) given_id = "bla" + data = %{ "ok" => true, - "id" => given_id + "id" => given_id, + "context" => "blabla" } {:ok, %Activity{} = activity} = ActivityPub.insert(data) assert activity.data["ok"] == data["ok"] assert activity.data["id"] == given_id + assert activity.data["context"] == "blabla" + assert activity.data["context_id"] end - test "adds an id to a given object if it lacks one and inserts it to the object database" do + test "adds a context when none is there" do data = %{ + "id" => "some_id", "object" => %{ + "id" => "object_id" + } + } + + {:ok, %Activity{} = activity} = ActivityPub.insert(data) + + assert is_binary(activity.data["context"]) + assert is_binary(activity.data["object"]["context"]) + assert activity.data["context_id"] + assert activity.data["object"]["context_id"] + end + + test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do + data = %{ + "object" => %{ + "type" => "Note", "ok" => true } } @@ -38,6 +81,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end end + describe "create activities" do + test "removes doubled 'to' recipients" do + user = insert(:user) + + {:ok, activity} = + ActivityPub.create(%{ + to: ["user1", "user1", "user2"], + actor: user, + context: "", + object: %{} + }) + + assert activity.data["to"] == ["user1", "user2"] + assert activity.actor == user.ap_id + assert activity.recipients == ["user1", "user2"] + end + end + describe "fetch activities for recipients" do test "retrieve the activities for certain recipients" do {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]}) @@ -52,21 +113,51 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do describe "fetch activities in context" do test "retrieves activities that have a given context" do - {:ok, activity} = ActivityBuilder.insert(%{"context" => "2hu"}) - {:ok, activity_two} = ActivityBuilder.insert(%{"context" => "2hu"}) - {:ok, _activity_three} = ActivityBuilder.insert(%{"context" => "3hu"}) + {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) + {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) + {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) + {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"}) + activity_five = insert(:note_activity) + user = insert(:user) - activities = ActivityPub.fetch_activities_for_context("2hu") + {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]}) - assert activities == [activity, activity_two] + activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user}) + assert activities == [activity_two, activity] end end + test "doesn't return blocked activities" do + activity_one = insert(:note_activity) + activity_two = insert(:note_activity) + user = insert(:user) + {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]}) + + activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) + + assert Enum.member?(activities, activity_two) + refute Enum.member?(activities, activity_one) + + {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) + + activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_one) + + activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil}) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_one) + end + describe "public fetch activities" do test "retrieves public activities" do - %{public: public} = ActivityBuilder.public_and_non_public + _activities = ActivityPub.fetch_public_activities() - activities = ActivityPub.fetch_public_activities + %{public: public} = ActivityBuilder.public_and_non_public() + + activities = ActivityPub.fetch_public_activities() assert length(activities) == 1 assert Enum.at(activities, 0) == public end @@ -75,7 +166,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do activities = ActivityBuilder.insert_list(30) last_expected = List.last(activities) - activities = ActivityPub.fetch_public_activities + activities = ActivityPub.fetch_public_activities() last = List.last(activities) assert length(activities) == 20 @@ -110,12 +201,240 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end end + describe "like an object" do + test "adds a like activity to the db" do + note_activity = insert(:note_activity) + object = Object.get_by_ap_id(note_activity.data["object"]["id"]) + user = insert(:user) + user_two = insert(:user) + + {:ok, like_activity, object} = ActivityPub.like(user, object) + + assert like_activity.data["actor"] == user.ap_id + assert like_activity.data["type"] == "Like" + assert like_activity.data["object"] == object.data["id"] + assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]] + assert like_activity.data["context"] == object.data["context"] + assert object.data["like_count"] == 1 + assert object.data["likes"] == [user.ap_id] + + # Just return the original activity if the user already liked it. + {:ok, same_like_activity, object} = ActivityPub.like(user, object) + + assert like_activity == same_like_activity + assert object.data["likes"] == [user.ap_id] + + [note_activity] = Activity.all_by_object_ap_id(object.data["id"]) + assert note_activity.data["object"]["like_count"] == 1 + + {:ok, _like_activity, object} = ActivityPub.like(user_two, object) + assert object.data["like_count"] == 2 + end + end + + describe "unliking" do + test "unliking a previously liked object" do + note_activity = insert(:note_activity) + object = Object.get_by_ap_id(note_activity.data["object"]["id"]) + user = insert(:user) + + # Unliking something that hasn't been liked does nothing + {:ok, object} = ActivityPub.unlike(user, object) + assert object.data["like_count"] == 0 + + {:ok, like_activity, object} = ActivityPub.like(user, object) + assert object.data["like_count"] == 1 + + {:ok, object} = ActivityPub.unlike(user, object) + assert object.data["like_count"] == 0 + + assert Repo.get(Activity, like_activity.id) == nil + end + end + + describe "announcing an object" do + test "adds an announce activity to the db" do + note_activity = insert(:note_activity) + object = Object.get_by_ap_id(note_activity.data["object"]["id"]) + user = insert(:user) + + {:ok, announce_activity, object} = ActivityPub.announce(user, object) + assert object.data["announcement_count"] == 1 + assert object.data["announcements"] == [user.ap_id] + + assert announce_activity.data["to"] == [ + User.ap_followers(user), + note_activity.data["actor"] + ] + + assert announce_activity.data["object"] == object.data["id"] + assert announce_activity.data["actor"] == user.ap_id + assert announce_activity.data["context"] == object.data["context"] + end + end + + describe "unannouncing an object" do + test "unannouncing a previously announced object" do + note_activity = insert(:note_activity) + object = Object.get_by_ap_id(note_activity.data["object"]["id"]) + user = insert(:user) + + # Unannouncing an object that is not announced does nothing + # {:ok, object} = ActivityPub.unannounce(user, object) + # assert object.data["announcement_count"] == 0 + + {:ok, announce_activity, object} = ActivityPub.announce(user, object) + assert object.data["announcement_count"] == 1 + + {:ok, unannounce_activity, activity, object} = ActivityPub.unannounce(user, object) + assert object.data["announcement_count"] == 0 + + assert activity == announce_activity + + assert unannounce_activity.data["to"] == [ + User.ap_followers(user), + announce_activity.data["actor"] + ] + + assert unannounce_activity.data["type"] == "Undo" + assert unannounce_activity.data["object"] == announce_activity.data + assert unannounce_activity.data["actor"] == user.ap_id + assert unannounce_activity.data["context"] == announce_activity.data["context"] + + assert Repo.get(Activity, announce_activity.id) == nil + end + end + describe "uploading files" do test "copies the file to the configured folder" do - file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"} + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } {:ok, %Object{} = object} = ActivityPub.upload(file) assert object.data["name"] == "an_image.jpg" end + + test "works with base64 encoded images" do + file = %{ + "img" => data_uri() + } + + {:ok, %Object{}} = ActivityPub.upload(file) + end + end + + describe "fetch the latest Follow" do + test "fetches the latest Follow activity" do + %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity) + follower = Repo.get_by(User, ap_id: activity.data["actor"]) + followed = Repo.get_by(User, ap_id: activity.data["object"]) + + assert activity == Utils.fetch_latest_follow(follower, followed) + end + end + + describe "fetching an object" do + test "it fetches an object" do + {:ok, object} = + ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + + assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"]) + assert activity.data["id"] + + {:ok, object_again} = + ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + + assert [attachment] = object.data["attachment"] + assert is_list(attachment["url"]) + + assert object == object_again + end + + test "it works with objects only available via Ostatus" do + {:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") + assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"]) + assert activity.data["id"] + + {:ok, object_again} = + ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") + + assert object == object_again + end + + test "it correctly stitches up conversations between ostatus and ap" do + last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + {:ok, object} = ActivityPub.fetch_object_from_id(last) + + object = Object.get_by_ap_id(object.data["inReplyTo"]) + assert object + end + end + + describe "following / unfollowing" do + test "creates a follow activity" do + follower = insert(:user) + followed = insert(:user) + + {:ok, activity} = ActivityPub.follow(follower, followed) + assert activity.data["type"] == "Follow" + assert activity.data["actor"] == follower.ap_id + assert activity.data["object"] == followed.ap_id + end + + test "creates an undo activity for the last follow" do + follower = insert(:user) + followed = insert(:user) + + {:ok, follow_activity} = ActivityPub.follow(follower, followed) + {:ok, activity} = ActivityPub.unfollow(follower, followed) + + assert activity.data["type"] == "Undo" + assert activity.data["actor"] == follower.ap_id + assert activity.data["object"] == follow_activity.data["id"] + end + end + + describe "deletion" do + test "it creates a delete activity and deletes the original object" do + note = insert(:note_activity) + object = Object.get_by_ap_id(note.data["object"]["id"]) + {:ok, delete} = ActivityPub.delete(object) + + assert delete.data["type"] == "Delete" + assert delete.data["actor"] == note.data["actor"] + assert delete.data["object"] == note.data["object"]["id"] + + assert Repo.get(Activity, delete.id) != nil + + assert Repo.get(Object, object.id) == nil + end + end + + describe "update" do + test "it creates an update activity with the new user data" do + user = insert(:user) + {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user}) + + {:ok, update} = + ActivityPub.update(%{ + actor: user_data["id"], + to: [user.follower_address], + cc: [], + object: user_data + }) + + assert update.data["actor"] == user.ap_id + assert update.data["to"] == [user.follower_address] + assert update.data["object"]["id"] == user_data["id"] + assert update.data["object"]["type"] == user_data["type"] + end + end + + def data_uri do + File.read!("test/fixtures/avatar_data_uri") end end