diff options
Diffstat (limited to 'test')
75 files changed, 2965 insertions, 3266 deletions
| diff --git a/test/activity_test.exs b/test/activity_test.exs index 95d9341c4..e7ea2bd5e 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -126,9 +126,25 @@ defmodule Pleroma.ActivityTest do        }        {:ok, local_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "find me!"}) +      {:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "更新情報"})        {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params)        {:ok, remote_activity} = ObanHelpers.perform(job) -      %{local_activity: local_activity, remote_activity: remote_activity, user: user} + +      %{ +        japanese_activity: japanese_activity, +        local_activity: local_activity, +        remote_activity: remote_activity, +        user: user +      } +    end + +    test "finds utf8 text in statuses", %{ +      japanese_activity: japanese_activity, +      user: user +    } do +      activities = Activity.search(user, "更新情報") + +      assert [^japanese_activity] = activities      end      test "find local and remote statuses for authenticated users", %{ diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index a27167d42..a5af0d1b2 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Conversation.ParticipationTest do    use Pleroma.DataCase    import Pleroma.Factory    alias Pleroma.Conversation.Participation +  alias Pleroma.User    alias Pleroma.Web.CommonAPI    test "getting a participation will also preload things" do @@ -22,6 +23,39 @@ defmodule Pleroma.Conversation.ParticipationTest do      assert %Pleroma.Conversation{} = participation.conversation    end +  test "for a new conversation or a reply, it doesn't mark the author's participation as unread" do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, _} = +      CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"}) + +    user = User.get_cached_by_id(user.id) +    other_user = User.get_cached_by_id(other_user.id) + +    [%{read: true}] = Participation.for_user(user) +    [%{read: false} = participation] = Participation.for_user(other_user) + +    assert User.get_cached_by_id(user.id).info.unread_conversation_count == 0 +    assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 1 + +    {:ok, _} = +      CommonAPI.post(other_user, %{ +        "status" => "Hey @#{user.nickname}.", +        "visibility" => "direct", +        "in_reply_to_conversation_id" => participation.id +      }) + +    user = User.get_cached_by_id(user.id) +    other_user = User.get_cached_by_id(other_user.id) + +    [%{read: false}] = Participation.for_user(user) +    [%{read: true}] = Participation.for_user(other_user) + +    assert User.get_cached_by_id(user.id).info.unread_conversation_count == 1 +    assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 0 +  end +    test "for a new conversation, it sets the recipents of the participation" do      user = insert(:user)      other_user = insert(:user) @@ -30,6 +64,8 @@ defmodule Pleroma.Conversation.ParticipationTest do      {:ok, activity} =        CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"}) +    user = User.get_cached_by_id(user.id) +    other_user = User.get_cached_by_id(other_user.id)      [participation] = Participation.for_user(user)      participation = Pleroma.Repo.preload(participation, :recipients) @@ -155,6 +191,7 @@ defmodule Pleroma.Conversation.ParticipationTest do      [participation] = Participation.for_user_with_last_activity_id(user)      participation = Repo.preload(participation, :recipients) +    user = User.get_cached_by_id(user.id)      assert participation.recipients |> length() == 1      assert user in participation.recipients diff --git a/test/emails/admin_email_test.exs b/test/emails/admin_email_test.exs index 31eac5f12..ad89f9213 100644 --- a/test/emails/admin_email_test.exs +++ b/test/emails/admin_email_test.exs @@ -19,8 +19,8 @@ defmodule Pleroma.Emails.AdminEmailTest do        AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment")      status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12") -    reporter_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.nickname) -    account_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, account.nickname) +    reporter_url = Helpers.feed_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.id) +    account_url = Helpers.feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)      assert res.to == [{to_user.name, to_user.email}]      assert res.from == {config[:name], config[:notify_email]} diff --git a/test/fixtures/bogus-mastodon-announce.json b/test/fixtures/bogus-mastodon-announce.json new file mode 100644 index 000000000..0485b80b9 --- /dev/null +++ b/test/fixtures/bogus-mastodon-announce.json @@ -0,0 +1,43 @@ +{ +  "type": "Announce", +  "to": [ +    "https://www.w3.org/ns/activitystreams#Public" +  ], +  "published": "2018-02-17T19:39:15Z", +  "object": { +    "type": "Note", +    "id": "https://mastodon.social/users/emelie/statuses/101849165031453404", +    "attributedTo": "https://mastodon.social/users/emelie", +    "content": "this is a public toot", +    "to": [ +      "https://www.w3.org/ns/activitystreams#Public" +    ], +    "cc": [ +      "https://mastodon.social/users/emelie", +      "https://mastodon.social/users/emelie/followers" +    ] +  }, +  "id": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity", +  "cc": [ +    "http://mastodon.example.org/users/admin", +    "http://mastodon.example.org/users/admin/followers" +  ], +  "atomUri": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity", +  "actor": "http://mastodon.example.org/users/admin", +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "toot": "http://joinmastodon.org/ns#", +      "sensitive": "as:sensitive", +      "ostatus": "http://ostatus.org#", +      "movedTo": "as:movedTo", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "inReplyToAtomUri": "ostatus:inReplyToAtomUri", +      "conversation": "ostatus:conversation", +      "atomUri": "ostatus:atomUri", +      "Hashtag": "as:Hashtag", +      "Emoji": "toot:Emoji" +    } +  ] +} diff --git a/test/fixtures/mastodon-announce-private.json b/test/fixtures/mastodon-announce-private.json new file mode 100644 index 000000000..9b868b13d --- /dev/null +++ b/test/fixtures/mastodon-announce-private.json @@ -0,0 +1,35 @@ +{ +  "type": "Announce", +  "to": [ +    "http://mastodon.example.org/users/admin/followers" +  ], +  "published": "2018-02-17T19:39:15Z", +  "object": { +    "type": "Note", +    "id": "http://mastodon.example.org/@admin/99541947525187368", +    "attributedTo": "http://mastodon.example.org/users/admin", +    "content": "this is a private toot", +    "to": [ +      "http://mastodon.example.org/users/admin/followers" +    ] +  }, +  "id": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity", +  "atomUri": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity", +  "actor": "http://mastodon.example.org/users/admin", +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "toot": "http://joinmastodon.org/ns#", +      "sensitive": "as:sensitive", +      "ostatus": "http://ostatus.org#", +      "movedTo": "as:movedTo", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "inReplyToAtomUri": "ostatus:inReplyToAtomUri", +      "conversation": "ostatus:conversation", +      "atomUri": "ostatus:atomUri", +      "Hashtag": "as:Hashtag", +      "Emoji": "toot:Emoji" +    } +  ] +} diff --git a/test/fixtures/mastodon-undo-like-compact-object.json b/test/fixtures/mastodon-undo-like-compact-object.json new file mode 100644 index 000000000..ae66a0d19 --- /dev/null +++ b/test/fixtures/mastodon-undo-like-compact-object.json @@ -0,0 +1,29 @@ +{ +  "type": "Undo", +  "signature": { +    "type": "RsaSignature2017", +    "signatureValue": "fdxMfQSMwbC6wP6sh6neS/vM5879K67yQkHTbiT5Npr5wAac0y6+o3Ij+41tN3rL6wfuGTosSBTHOtta6R4GCOOhCaCSLMZKypnp1VltCzLDoyrZELnYQIC8gpUXVmIycZbREk22qWUe/w7DAFaKK4UscBlHDzeDVcA0K3Se5Sluqi9/Zh+ldAnEzj/rSEPDjrtvf5wGNf3fHxbKSRKFt90JvKK6hS+vxKUhlRFDf6/SMETw+EhwJSNW4d10yMUakqUWsFv4Acq5LW7l+HpYMvlYY1FZhNde1+uonnCyuQDyvzkff8zwtEJmAXC4RivO/VVLa17SmqheJZfI8oluVg==", +    "creator": "http://mastodon.example.org/users/admin#main-key", +    "created": "2018-05-19T16:36:58Z" +  }, +  "object": "http://mastodon.example.org/users/admin#likes/2", +  "nickname": "lain", +  "id": "http://mastodon.example.org/users/admin#likes/2/undo", +  "actor": "http://mastodon.example.org/users/admin", +  "@context": [ +    "https://www.w3.org/ns/activitystreams", +    "https://w3id.org/security/v1", +    { +      "toot": "http://joinmastodon.org/ns#", +      "sensitive": "as:sensitive", +      "ostatus": "http://ostatus.org#", +      "movedTo": "as:movedTo", +      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", +      "inReplyToAtomUri": "ostatus:inReplyToAtomUri", +      "conversation": "ostatus:conversation", +      "atomUri": "ostatus:atomUri", +      "Hashtag": "as:Hashtag", +      "Emoji": "toot:Emoji" +    } +  ] +} diff --git a/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json b/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json new file mode 100644 index 000000000..4b7b4df44 --- /dev/null +++ b/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://shitposter.club/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://shitposter.club/users/moonman","attachment":[],"attributedTo":"https://shitposter.club/users/moonman","cc":["https://shitposter.club/users/moonman/followers"],"content":"@<a href=\"https://shitposter.club/users/9655\" class=\"h-card mention\" title=\"Solidarity for Pigs\">neimzr4luzerz</a> @<a href=\"https://gs.smuglo.li/user/2326\" class=\"h-card mention\" title=\"Dolus_McHonest\">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English","context":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","conversation":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","id":"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment","inReplyTo":"tag:shitposter.club,2017-05-05:noticeId=2827849:objectType=comment","inReplyToStatusId":2827849,"published":"2017-05-05T08:51:48Z","sensitive":false,"summary":null,"tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Note"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/moonman@shitposter.club.json b/test/fixtures/tesla_mock/moonman@shitposter.club.json new file mode 100644 index 000000000..8f9ced1dd --- /dev/null +++ b/test/fixtures/tesla_mock/moonman@shitposter.club.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://shitposter.club/schemas/litepub-0.1.jsonld",{"@language":"und"}],"attachment":[],"endpoints":{"oauthAuthorizationEndpoint":"https://shitposter.club/oauth/authorize","oauthRegistrationEndpoint":"https://shitposter.club/api/v1/apps","oauthTokenEndpoint":"https://shitposter.club/oauth/token","sharedInbox":"https://shitposter.club/inbox"},"followers":"https://shitposter.club/users/moonman/followers","following":"https://shitposter.club/users/moonman/following","icon":{"type":"Image","url":"https://shitposter.club/media/bda6e00074f6a02cbf32ddb0abec08151eb4c795e580927ff7ad638d00cde4c8.jpg?name=blob.jpg"},"id":"https://shitposter.club/users/moonman","image":{"type":"Image","url":"https://shitposter.club/media/4eefb90d-cdb2-2b4f-5f29-7612856a99d2/4eefb90d-cdb2-2b4f-5f29-7612856a99d2.jpeg"},"inbox":"https://shitposter.club/users/moonman/inbox","manuallyApprovesFollowers":false,"name":"Captain Howdy","outbox":"https://shitposter.club/users/moonman/outbox","preferredUsername":"moonman","publicKey":{"id":"https://shitposter.club/users/moonman#main-key","owner":"https://shitposter.club/users/moonman","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOTitJ19ZqcOZHwSXQUM\nJq9ip4GNblp83LgwG1t5c2h2iaI3fXMsB4EaEBs8XHsoSFyDeDNRSPE3mtVgOnWv\n1eaXWMDerBT06th6DrElD9k5IoEPtZRY4HtZa1xGnte7+6RjuPOzZ1fR9C8WxGgi\nwb9iOUMhazpo85fC3iKCAL5XhiuA3Nas57MDJgueeI9BF+2oFelFZdMSWwG96uch\niDfp8nfpkmzYI6SWbylObjm8RsfZbGTosLHwWyJPEITeYI/5M0XwJe9dgVI1rVNU\n52kplWOGTo1rm6V0AMHaYAd9RpiXxe8xt5OeranrsE/5LvEQUl0fz7SE36YmsOaH\nTwIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"EMAIL:shitposterclub@gmail.com<br>XMPP: moon@talk.shitposter.club<br>PRONOUNS: none of your business<br><br>Purported leftist kike piece of shit","tag":[],"type":"Person","url":"https://shitposter.club/users/moonman"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/mstdn.jp_host_meta b/test/fixtures/tesla_mock/mstdn.jp_host_meta new file mode 100644 index 000000000..e76ddd47f --- /dev/null +++ b/test/fixtures/tesla_mock/mstdn.jp_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" type="application/xrd+xml" template="https://mstdn.jp/.well-known/webfinger?resource={uri}"/> +</XRD> diff --git a/test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json b/test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json new file mode 100644 index 000000000..3757c0dad --- /dev/null +++ b/test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json @@ -0,0 +1,12 @@ +{ +    "subject":"acct:pekorino@pawoo.net", +    "aliases":["https://pawoo.net/@pekorino","https://pawoo.net/users/pekorino"], +    "links":[ +        {"rel":"http://webfinger.net/rel/profile-page","type":"text/html","href":"https://pawoo.net/@pekorino"}, +        {"rel":"http://schemas.google.com/g/2010#updates-from","type":"application/atom+xml","href":"https://pawoo.net/users/pekorino.atom"}, +        {"rel":"self","type":"application/activity+json","href":"https://pawoo.net/users/pekorino"}, +        {"rel":"salmon","href":"https://pawoo.net/api/salmon/128378"}, +        {"rel":"magic-public-key","href":"data:application/magic-public-key,RSA.1x8XXmBqzyb-QRkfUKxKPd7Ac2KbaFhdKy2FkJY64G-ifga-BppzEb62Q5TdkRdVKdHjh5qI7A1Hk3KfnNQcNWqqak-jxII_txC2grbWpp7v-boceD2pnzdVK5l-RR-9wEwxcoCUeRWS1Ak6DStqE5tFQOAK4IIGQB-thSQGlU75KZ-2080fPA3Xc_ycH3_eB4YqawSxXrh6IeScMevN0YHSF84GAcvhXmwLKZRugiF6nYrknbPEe_niIOmN8hhEXLN9_4kDcH83hkVZd5VXssRrxqDhtokx9emvTHkA7sY1AjYeehTPZErlV74GN-kFYLeI6DluXoSI2sX1QcS08w==.AQAB"}, +        {"rel":"http://ostatus.org/schema/1.0/subscribe","template":"https://pawoo.net/authorize_follow?acct={uri}"} +    ] +} diff --git a/test/fixtures/tesla_mock/sdf.org_host_meta b/test/fixtures/tesla_mock/sdf.org_host_meta new file mode 100644 index 000000000..0ffc4f096 --- /dev/null +++ b/test/fixtures/tesla_mock/sdf.org_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" type="application/xrd+xml" template="https://mastodon.sdf.org/.well-known/webfinger?resource={uri}"/> +</XRD> diff --git a/test/fixtures/tesla_mock/snowdusk@sdf.org_host_meta.json b/test/fixtures/tesla_mock/snowdusk@sdf.org_host_meta.json new file mode 100644 index 000000000..273fc3804 --- /dev/null +++ b/test/fixtures/tesla_mock/snowdusk@sdf.org_host_meta.json @@ -0,0 +1,12 @@ +{ +    "subject":"acct:snowdusk@mastodon.sdf.org", +    "aliases":["https://mastodon.sdf.org/@snowdusk","https://mastodon.sdf.org/users/snowdusk"], +    "links":[ +        {"rel":"http://webfinger.net/rel/profile-page","type":"text/html","href":"https://mastodon.sdf.org/@snowdusk"}, +        {"rel":"http://schemas.google.com/g/2010#updates-from","type":"application/atom+xml","href":"https://mastodon.sdf.org/users/snowdusk.atom"}, +        {"rel":"self","type":"application/activity+json","href":"https://mastodon.sdf.org/users/snowdusk"}, +        {"rel":"salmon","href":"https://mastodon.sdf.org/api/salmon/2"}, +        {"rel":"magic-public-key","href":"data:application/magic-public-key,RSA.k4_Hr0WQUHumAD4uwWIz7OybovIKgIuanbXhX5pl7oGyb2TuifBf3nAqEhD6eLSo6-_6160L4BvPPV_l_6rlZEi6_nbeJUgVkayZgcZN3oou3IErSt8L0IbUdWT5s4fWM2zpkndLCkVbeeNQ3DOBccvJw7iA_QNTao8wr3ILvQaKEDnf-H5QBd9Tj3seyo4-7E0e6wCKOH_uBm8pSRgpdMdl2CehiFzaABBkmCeUKH-buU7iNQGi0fsV5VIHn6zffrv6p0EVNkjTDi1vTmmfrp9W0mcKZJ9DtvdehOKSgh3J7Mem-ILbPy6FSL2Oi6Ekj_Wh4M8Ie-YKuxI3N_0Baw==.AQAB"}, +        {"rel":"http://ostatus.org/schema/1.0/subscribe","template":"https://mastodon.sdf.org/authorize_interaction?uri={uri}"} +    ] +} diff --git a/test/fixtures/tesla_mock/soykaf.com_host_meta b/test/fixtures/tesla_mock/soykaf.com_host_meta new file mode 100644 index 000000000..99d552d32 --- /dev/null +++ b/test/fixtures/tesla_mock/soykaf.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://pleroma.soykaf.com/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /> +</XRD> diff --git a/test/fixtures/tesla_mock/stopwatchingus-heidelberg.de_host_meta b/test/fixtures/tesla_mock/stopwatchingus-heidelberg.de_host_meta new file mode 100644 index 000000000..481cfec8d --- /dev/null +++ b/test/fixtures/tesla_mock/stopwatchingus-heidelberg.de_host_meta @@ -0,0 +1,31 @@ +{ +    "links":[ +        { +            "rel":"lrdd", +            "type":"application\/jrd+json", +            "template":"https:\/\/social.stopwatchingus-heidelberg.de\/.well-known\/webfinger?resource={uri}" +        }, +        { +            "rel":"lrdd", +            "type":"application\/json", +            "template":"https:\/\/social.stopwatchingus-heidelberg.de\/.well-known\/webfinger?resource={uri}" +        }, +        { +            "rel":"lrdd", +            "type":"application\/xrd+xml", +            "template":"https:\/\/social.stopwatchingus-heidelberg.de\/.well-known\/webfinger?resource={uri}" +        }, +        { +            "rel":"http:\/\/apinamespace.org\/oauth\/access_token", +            "href":"https:\/\/social.stopwatchingus-heidelberg.de\/api\/oauth\/access_token" +        }, +        { +            "rel":"http:\/\/apinamespace.org\/oauth\/request_token", +            "href":"https:\/\/social.stopwatchingus-heidelberg.de\/api\/oauth\/request_token" +        }, +        { +            "rel":"http:\/\/apinamespace.org\/oauth\/authorize", +            "href":"https:\/\/social.stopwatchingus-heidelberg.de\/api\/oauth\/authorize" +        } +    ] +} diff --git a/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta b/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta new file mode 100644 index 000000000..45d260e55 --- /dev/null +++ b/test/fixtures/tesla_mock/xn--q9jyb4c_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://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /> +</XRD> diff --git a/test/healthcheck_test.exs b/test/healthcheck_test.exs index 6bb8d5b7f..66d5026ff 100644 --- a/test/healthcheck_test.exs +++ b/test/healthcheck_test.exs @@ -9,7 +9,14 @@ defmodule Pleroma.HealthcheckTest do    test "system_info/0" do      result = Healthcheck.system_info() |> Map.from_struct() -    assert Map.keys(result) == [:active, :healthy, :idle, :memory_used, :pool_size] +    assert Map.keys(result) == [ +             :active, +             :healthy, +             :idle, +             :job_queue_stats, +             :memory_used, +             :pool_size +           ]    end    describe "check_health/1" do diff --git a/test/job_queue_monitor_test.exs b/test/job_queue_monitor_test.exs new file mode 100644 index 000000000..17c6f3246 --- /dev/null +++ b/test/job_queue_monitor_test.exs @@ -0,0 +1,70 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.JobQueueMonitorTest do +  use ExUnit.Case, async: true + +  alias Pleroma.JobQueueMonitor + +  @success {:process_event, :success, 1337, +            %{ +              args: %{"op" => "refresh_subscriptions"}, +              attempt: 1, +              id: 339, +              max_attempts: 5, +              queue: "federator_outgoing", +              worker: "Pleroma.Workers.SubscriberWorker" +            }} + +  @failure {:process_event, :failure, 22_521_134, +            %{ +              args: %{"op" => "force_password_reset", "user_id" => "9nJG6n6Nbu7tj9GJX6"}, +              attempt: 1, +              error: %RuntimeError{message: "oops"}, +              id: 345, +              kind: :exception, +              max_attempts: 1, +              queue: "background", +              stack: [ +                {Pleroma.Workers.BackgroundWorker, :perform, 2, +                 [file: '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]} +              ], +              worker: "Pleroma.Workers.BackgroundWorker" +            }} + +  test "stats/0" do +    assert %{processed_jobs: _, queues: _, workers: _} = JobQueueMonitor.stats() +  end + +  test "handle_cast/2" do +    state = %{workers: %{}, queues: %{}, processed_jobs: 0} + +    assert {:noreply, state} = JobQueueMonitor.handle_cast(@success, state) +    assert {:noreply, state} = JobQueueMonitor.handle_cast(@failure, state) +    assert {:noreply, state} = JobQueueMonitor.handle_cast(@success, state) +    assert {:noreply, state} = JobQueueMonitor.handle_cast(@failure, state) + +    assert state == %{ +             processed_jobs: 4, +             queues: %{ +               "background" => %{failure: 2, processed_jobs: 2, success: 0}, +               "federator_outgoing" => %{failure: 0, processed_jobs: 2, success: 2} +             }, +             workers: %{ +               "Pleroma.Workers.BackgroundWorker" => %{ +                 "force_password_reset" => %{failure: 2, processed_jobs: 2, success: 0} +               }, +               "Pleroma.Workers.SubscriberWorker" => %{ +                 "refresh_subscriptions" => %{failure: 0, processed_jobs: 2, success: 2} +               } +             } +           } +  end +end diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs index a39a00e02..81c0fef12 100644 --- a/test/moderation_log_test.exs +++ b/test/moderation_log_test.exs @@ -24,13 +24,13 @@ defmodule Pleroma.ModerationLogTest do        {:ok, _} =          ModerationLog.insert_log(%{            actor: moderator, -          subject: subject1, +          subject: [subject1],            action: "delete"          })        log = Repo.one(ModerationLog) -      assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}" +      assert log.data["message"] == "@#{moderator.nickname} deleted users: @#{subject1.nickname}"      end      test "logging user creation by moderator", %{ @@ -128,7 +128,7 @@ defmodule Pleroma.ModerationLogTest do        {:ok, _} =          ModerationLog.insert_log(%{            actor: moderator, -          subject: subject1, +          subject: [subject1],            action: "grant",            permission: "moderator"          }) @@ -142,7 +142,7 @@ defmodule Pleroma.ModerationLogTest do        {:ok, _} =          ModerationLog.insert_log(%{            actor: moderator, -          subject: subject1, +          subject: [subject1],            action: "revoke",            permission: "moderator"          }) diff --git a/test/object/containment_test.exs b/test/object/containment_test.exs index 61cd1b412..0dc2728b9 100644 --- a/test/object/containment_test.exs +++ b/test/object/containment_test.exs @@ -65,7 +65,7 @@ defmodule Pleroma.Object.ContainmentTest do        assert capture_log(fn ->                 {:error, _} = User.get_or_fetch_by_ap_id("https://n1u.moe/users/rye")               end) =~ -               "[error] Could not decode user at fetch https://n1u.moe/users/rye, {:error, :error}" +               "[error] Could not decode user at fetch https://n1u.moe/users/rye"      end    end diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs index 895a73d2c..9ae6b015d 100644 --- a/test/object/fetcher_test.exs +++ b/test/object/fetcher_test.exs @@ -27,31 +27,16 @@ defmodule Pleroma.Object.FetcherTest do    end    describe "actor origin containment" do -    test_with_mock "it rejects objects with a bogus origin", -                   Pleroma.Web.OStatus, -                   [:passthrough], -                   [] do +    test "it rejects objects with a bogus origin" do        {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity.json") - -      refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_))      end -    test_with_mock "it rejects objects when attributedTo is wrong (variant 1)", -                   Pleroma.Web.OStatus, -                   [:passthrough], -                   [] do +    test "it rejects objects when attributedTo is wrong (variant 1)" do        {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity2.json") - -      refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_))      end -    test_with_mock "it rejects objects when attributedTo is wrong (variant 2)", -                   Pleroma.Web.OStatus, -                   [:passthrough], -                   [] do +    test "it rejects objects when attributedTo is wrong (variant 2)" do        {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity3.json") - -      refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_))      end    end @@ -71,24 +56,6 @@ defmodule Pleroma.Object.FetcherTest do        assert object == object_again      end - -    test "it works with objects only available via Ostatus" do -      {:ok, object} = Fetcher.fetch_object_from_id("https://shitposter.club/notice/2827873") -      assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) -      assert activity.data["id"] - -      {:ok, object_again} = Fetcher.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} = Fetcher.fetch_object_from_id(last) - -      object = Object.get_by_ap_id(object.data["inReplyTo"]) -      assert object -    end    end    describe "implementation quirks" do diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs index 6a13ea811..be6d1340b 100644 --- a/test/plugs/oauth_scopes_plug_test.exs +++ b/test/plugs/oauth_scopes_plug_test.exs @@ -5,24 +5,48 @@  defmodule Pleroma.Plugs.OAuthScopesPlugTest do    use Pleroma.Web.ConnCase, async: true +  alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug    alias Pleroma.Plugs.OAuthScopesPlug    alias Pleroma.Repo +  import Mock    import Pleroma.Factory -  test "proceeds with no op if `assigns[:token]` is nil", %{conn: conn} do -    conn = -      conn -      |> assign(:user, insert(:user)) -      |> OAuthScopesPlug.call(%{scopes: ["read"]}) +  setup_with_mocks([{EnsurePublicOrAuthenticatedPlug, [], [call: fn conn, _ -> conn end]}]) do +    :ok +  end -    refute conn.halted -    assert conn.assigns[:user] +  describe "when `assigns[:token]` is nil, " do +    test "with :skip_instance_privacy_check option, proceeds with no op", %{conn: conn} do +      conn = +        conn +        |> assign(:user, insert(:user)) +        |> OAuthScopesPlug.call(%{scopes: ["read"], skip_instance_privacy_check: true}) + +      refute conn.halted +      assert conn.assigns[:user] + +      refute called(EnsurePublicOrAuthenticatedPlug.call(conn, :_)) +    end + +    test "without :skip_instance_privacy_check option, calls EnsurePublicOrAuthenticatedPlug", %{ +      conn: conn +    } do +      conn = +        conn +        |> assign(:user, insert(:user)) +        |> OAuthScopesPlug.call(%{scopes: ["read"]}) + +      refute conn.halted +      assert conn.assigns[:user] + +      assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_)) +    end    end -  test "proceeds with no op if `token.scopes` fulfill specified 'any of' conditions", %{ -    conn: conn -  } do +  test "if `token.scopes` fulfills specified 'any of' conditions, " <> +         "proceeds with no op", +       %{conn: conn} do      token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)      conn = @@ -35,9 +59,9 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do      assert conn.assigns[:user]    end -  test "proceeds with no op if `token.scopes` fulfill specified 'all of' conditions", %{ -    conn: conn -  } do +  test "if `token.scopes` fulfills specified 'all of' conditions, " <> +         "proceeds with no op", +       %{conn: conn} do      token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)      conn = @@ -50,73 +74,154 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do      assert conn.assigns[:user]    end -  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'any of' conditions " <> -         "and `fallback: :proceed_unauthenticated` option is specified", -       %{conn: conn} do -    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) +  describe "with `fallback: :proceed_unauthenticated` option, " do +    test "if `token.scopes` doesn't fulfill specified 'any of' conditions, " <> +           "clears `assigns[:user]` and calls EnsurePublicOrAuthenticatedPlug", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +      conn = +        conn +        |> assign(:user, token.user) +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated}) + +      refute conn.halted +      refute conn.assigns[:user] + +      assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_)) +    end + +    test "if `token.scopes` doesn't fulfill specified 'all of' conditions, " <> +           "clears `assigns[:user] and calls EnsurePublicOrAuthenticatedPlug", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +      conn = +        conn +        |> assign(:user, token.user) +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{ +          scopes: ["read", "follow"], +          op: :&, +          fallback: :proceed_unauthenticated +        }) + +      refute conn.halted +      refute conn.assigns[:user] + +      assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_)) +    end + +    test "with :skip_instance_privacy_check option, " <> +           "if `token.scopes` doesn't fulfill specified conditions, " <> +           "clears `assigns[:user]` and does not call EnsurePublicOrAuthenticatedPlug", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read:statuses", "write"]) |> Repo.preload(:user) + +      conn = +        conn +        |> assign(:user, token.user) +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{ +          scopes: ["read"], +          fallback: :proceed_unauthenticated, +          skip_instance_privacy_check: true +        }) + +      refute conn.halted +      refute conn.assigns[:user] + +      refute called(EnsurePublicOrAuthenticatedPlug.call(conn, :_)) +    end +  end -    conn = -      conn -      |> assign(:user, token.user) -      |> assign(:token, token) -      |> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated}) +  describe "without :fallback option, " do +    test "if `token.scopes` does not fulfill specified 'any of' conditions, " <> +           "returns 403 and halts", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "write"]) +      any_of_scopes = ["follow"] -    refute conn.halted -    refute conn.assigns[:user] -  end +      conn = +        conn +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{scopes: any_of_scopes}) -  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'all of' conditions " <> -         "and `fallback: :proceed_unauthenticated` option is specified", -       %{conn: conn} do -    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) +      assert conn.halted +      assert 403 == conn.status -    conn = -      conn -      |> assign(:user, token.user) -      |> assign(:token, token) -      |> OAuthScopesPlug.call(%{ -        scopes: ["read", "follow"], -        op: :&, -        fallback: :proceed_unauthenticated -      }) +      expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}." +      assert Jason.encode!(%{error: expected_error}) == conn.resp_body +    end -    refute conn.halted -    refute conn.assigns[:user] -  end +    test "if `token.scopes` does not fulfill specified 'all of' conditions, " <> +           "returns 403 and halts", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "write"]) +      all_of_scopes = ["write", "follow"] -  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'any of' conditions", -       %{conn: conn} do -    token = insert(:oauth_token, scopes: ["read", "write"]) -    any_of_scopes = ["follow"] +      conn = +        conn +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&}) -    conn = -      conn -      |> assign(:token, token) -      |> OAuthScopesPlug.call(%{scopes: any_of_scopes}) +      assert conn.halted +      assert 403 == conn.status -    assert conn.halted -    assert 403 == conn.status +      expected_error = +        "Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}." -    expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}." -    assert Jason.encode!(%{error: expected_error}) == conn.resp_body +      assert Jason.encode!(%{error: expected_error}) == conn.resp_body +    end    end -  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'all of' conditions", -       %{conn: conn} do -    token = insert(:oauth_token, scopes: ["read", "write"]) -    all_of_scopes = ["write", "follow"] +  describe "with hierarchical scopes, " do +    test "if `token.scopes` fulfills specified 'any of' conditions, " <> +           "proceeds with no op", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +      conn = +        conn +        |> assign(:user, token.user) +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{scopes: ["read:something"]}) + +      refute conn.halted +      assert conn.assigns[:user] +    end + +    test "if `token.scopes` fulfills specified 'all of' conditions, " <> +           "proceeds with no op", +         %{conn: conn} do +      token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user) + +      conn = +        conn +        |> assign(:user, token.user) +        |> assign(:token, token) +        |> OAuthScopesPlug.call(%{scopes: ["scope1:subscope", "scope2:subscope"], op: :&}) + +      refute conn.halted +      assert conn.assigns[:user] +    end +  end -    conn = -      conn -      |> assign(:token, token) -      |> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&}) +  describe "filter_descendants/2" do +    test "filters scopes which directly match or are ancestors of supported scopes" do +      f = fn scopes, supported_scopes -> +        OAuthScopesPlug.filter_descendants(scopes, supported_scopes) +      end + +      assert f.(["read", "follow"], ["write", "read"]) == ["read"] -    assert conn.halted -    assert 403 == conn.status +      assert f.(["read", "write:something", "follow"], ["write", "read"]) == +               ["read", "write:something"] -    expected_error = -      "Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}." +      assert f.(["admin:read"], ["write", "read"]) == [] -    assert Jason.encode!(%{error: expected_error}) == conn.resp_body +      assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"] +    end    end  end diff --git a/test/reverse_proxy_test.exs b/test/reverse_proxy_test.exs index 3a83c4c48..0672f57db 100644 --- a/test/reverse_proxy_test.exs +++ b/test/reverse_proxy_test.exs @@ -42,6 +42,18 @@ defmodule Pleroma.ReverseProxyTest do      end)    end +  describe "reverse proxy" do +    test "do not track successful request", %{conn: conn} do +      user_agent_mock("hackney/1.15.1", 2) +      url = "/success" + +      conn = ReverseProxy.call(conn, url) + +      assert conn.status == 200 +      assert Cachex.get(:failed_proxy_url_cache, url) == {:ok, nil} +    end +  end +    describe "user-agent" do      test "don't keep", %{conn: conn} do        user_agent_mock("hackney/1.15.1", 2) @@ -71,9 +83,15 @@ defmodule Pleroma.ReverseProxyTest do        user_agent_mock("hackney/1.15.1", 0)        assert capture_log(fn -> -               ReverseProxy.call(conn, "/user-agent", max_body_length: 4) +               ReverseProxy.call(conn, "/huge-file", max_body_length: 4)               end) =~ -               "[error] Elixir.Pleroma.ReverseProxy: request to \"/user-agent\" failed: :body_too_large" +               "[error] Elixir.Pleroma.ReverseProxy: request to \"/huge-file\" failed: :body_too_large" + +      assert {:ok, true} == Cachex.get(:failed_proxy_url_cache, "/huge-file") + +      assert capture_log(fn -> +               ReverseProxy.call(conn, "/huge-file", max_body_length: 4) +             end) == ""      end      defp stream_mock(invokes, with_close? \\ false) do @@ -140,28 +158,54 @@ defmodule Pleroma.ReverseProxyTest do    describe "returns error on" do      test "500", %{conn: conn} do        error_mock(500) +      url = "/status/500" -      capture_log(fn -> ReverseProxy.call(conn, "/status/500") end) =~ +      capture_log(fn -> ReverseProxy.call(conn, url) end) =~          "[error] Elixir.Pleroma.ReverseProxy: request to /status/500 failed with HTTP status 500" + +      assert Cachex.get(:failed_proxy_url_cache, url) == {:ok, true} + +      {:ok, ttl} = Cachex.ttl(:failed_proxy_url_cache, url) +      assert ttl <= 60_000      end      test "400", %{conn: conn} do        error_mock(400) +      url = "/status/400" -      capture_log(fn -> ReverseProxy.call(conn, "/status/400") end) =~ +      capture_log(fn -> ReverseProxy.call(conn, url) end) =~          "[error] Elixir.Pleroma.ReverseProxy: request to /status/400 failed with HTTP status 400" + +      assert Cachex.get(:failed_proxy_url_cache, url) == {:ok, true} +      assert Cachex.ttl(:failed_proxy_url_cache, url) == {:ok, nil} +    end + +    test "403", %{conn: conn} do +      error_mock(403) +      url = "/status/403" + +      capture_log(fn -> +        ReverseProxy.call(conn, url, failed_request_ttl: :timer.seconds(120)) +      end) =~ +        "[error] Elixir.Pleroma.ReverseProxy: request to /status/403 failed with HTTP status 403" + +      {:ok, ttl} = Cachex.ttl(:failed_proxy_url_cache, url) +      assert ttl > 100_000      end      test "204", %{conn: conn} do -      ClientMock -      |> expect(:request, fn :get, "/status/204", _, _, _ -> {:ok, 204, [], %{}} end) +      url = "/status/204" +      expect(ClientMock, :request, fn :get, _url, _, _, _ -> {:ok, 204, [], %{}} end)        capture_log(fn -> -        conn = ReverseProxy.call(conn, "/status/204") +        conn = ReverseProxy.call(conn, url)          assert conn.resp_body == "Request failed: No Content"          assert conn.halted        end) =~          "[error] Elixir.Pleroma.ReverseProxy: request to \"/status/204\" failed with HTTP status 204" + +      assert Cachex.get(:failed_proxy_url_cache, url) == {:ok, true} +      assert Cachex.ttl(:failed_proxy_url_cache, url) == {:ok, nil}      end    end diff --git a/test/safe_jsonb_set_test.exs b/test/safe_jsonb_set_test.exs new file mode 100644 index 000000000..748540570 --- /dev/null +++ b/test/safe_jsonb_set_test.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.SafeJsonbSetTest do +  use Pleroma.DataCase + +  test "it doesn't wipe the object when asked to set the value to NULL" do +    assert %{rows: [[%{"key" => "value", "test" => nil}]]} = +             Ecto.Adapters.SQL.query!( +               Pleroma.Repo, +               "select safe_jsonb_set('{\"key\": \"value\"}'::jsonb, '{test}', NULL);", +               [] +             ) +  end +end diff --git a/test/signature_test.exs b/test/signature_test.exs index d5bf63d7d..6b168f2d9 100644 --- a/test/signature_test.exs +++ b/test/signature_test.exs @@ -69,8 +69,7 @@ defmodule Pleroma.SignatureTest do      test "it returns error when not found user" do        assert capture_log(fn -> -               assert Signature.refetch_public_key(make_fake_conn("test-ap_id")) == -                        {:error, {:error, :ok}} +               {:error, _} = Signature.refetch_public_key(make_fake_conn("test-ap_id"))               end) =~ "[error] Could not decode user"      end    end @@ -80,7 +79,7 @@ defmodule Pleroma.SignatureTest do        user =          insert(:user, %{            ap_id: "https://mastodon.social/users/lambadalambda", -          info: %{keys: @private_key} +          keys: @private_key          })        assert Signature.sign( @@ -94,8 +93,7 @@ defmodule Pleroma.SignatureTest do      end      test "it returns error" do -      user = -        insert(:user, %{ap_id: "https://mastodon.social/users/lambadalambda", info: %{keys: ""}}) +      user = insert(:user, %{ap_id: "https://mastodon.social/users/lambadalambda", keys: ""})        assert Signature.sign(                 user, diff --git a/test/support/factory.ex b/test/support/factory.ex index 4f3244025..0fdb1e952 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -281,26 +281,6 @@ defmodule Pleroma.Factory do      }    end -  def websub_subscription_factory do -    %Pleroma.Web.Websub.WebsubServerSubscription{ -      topic: "http://example.org", -      callback: "http://example.org/callback", -      secret: "here's a secret", -      valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 100), -      state: "requested" -    } -  end - -  def websub_client_subscription_factory do -    %Pleroma.Web.Websub.WebsubClientSubscription{ -      topic: "http://example.org", -      secret: "here's a secret", -      valid_until: nil, -      state: "requested", -      subscribers: [] -    } -  end -    def oauth_app_factory do      %Pleroma.Web.OAuth.App{        client_name: "Some client", @@ -324,6 +304,7 @@ defmodule Pleroma.Factory do      %Pleroma.Web.OAuth.Token{        token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(), +      scopes: ["read"],        refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),        user: build(:user),        app_id: oauth_app.id, diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 5506c0626..7d65209fb 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -38,6 +38,14 @@ defmodule HttpRequestMock do       }}    end +  def get("https://shitposter.club/users/moonman", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json") +     }} +  end +    def get("https://mastodon.social/users/emelie/statuses/101849165031453009", _, _, _) do      {:ok,       %Tesla.Env{ @@ -46,6 +54,14 @@ defmodule HttpRequestMock do       }}    end +  def get("https://mastodon.social/users/emelie/statuses/101849165031453404", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 404, +       body: "" +     }} +  end +    def get("https://mastodon.social/users/emelie", _, _, _) do      {:ok,       %Tesla.Env{ @@ -336,6 +352,181 @@ defmodule HttpRequestMock do      {:error, :nxdomain}    end +  def get("http://osada.macgirvin.com/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 404, +       body: "" +     }} +  end + +  def get("https://osada.macgirvin.com/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 404, +       body: "" +     }} +  end + +  def get("http://mastodon.sdf.org/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/sdf.org_host_meta") +     }} +  end + +  def get("https://mastodon.sdf.org/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/sdf.org_host_meta") +     }} +  end + +  def get( +        "https://mastodon.sdf.org/.well-known/webfinger?resource=https://mastodon.sdf.org/users/snowdusk", +        _, +        _, +        _ +      ) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/snowdusk@sdf.org_host_meta.json") +     }} +  end + +  def get("http://mstdn.jp/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/mstdn.jp_host_meta") +     }} +  end + +  def get("https://mstdn.jp/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/mstdn.jp_host_meta") +     }} +  end + +  def get("https://mstdn.jp/.well-known/webfinger?resource=kpherox@mstdn.jp", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml") +     }} +  end + +  def get("http://mamot.fr/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/mamot.fr_host_meta") +     }} +  end + +  def get("https://mamot.fr/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/mamot.fr_host_meta") +     }} +  end + +  def get( +        "https://mamot.fr/.well-known/webfinger?resource=https://mamot.fr/users/Skruyb", +        _, +        _, +        _ +      ) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/skruyb@mamot.fr.atom") +     }} +  end + +  def get("http://pawoo.net/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/pawoo.net_host_meta") +     }} +  end + +  def get("https://pawoo.net/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/pawoo.net_host_meta") +     }} +  end + +  def get( +        "https://pawoo.net/.well-known/webfinger?resource=https://pawoo.net/users/pekorino", +        _, +        _, +        _ +      ) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json") +     }} +  end + +  def get("http://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta") +     }} +  end + +  def get("https://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta") +     }} +  end + +  def get("http://pleroma.soykaf.com/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/soykaf.com_host_meta") +     }} +  end + +  def get("https://pleroma.soykaf.com/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/soykaf.com_host_meta") +     }} +  end + +  def get("http://social.stopwatchingus-heidelberg.de/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/stopwatchingus-heidelberg.de_host_meta") +     }} +  end + +  def get("https://social.stopwatchingus-heidelberg.de/.well-known/host-meta", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/tesla_mock/stopwatchingus-heidelberg.de_host_meta") +     }} +  end +    def get(          "http://mastodon.example.org/@admin/99541947525187367",          _, @@ -349,6 +540,14 @@ defmodule HttpRequestMock do       }}    end +  def get("http://mastodon.example.org/@admin/99541947525187368", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 404, +       body: "" +     }} +  end +    def get("https://shitposter.club/notice/7369654", _, _, _) do      {:ok,       %Tesla.Env{ @@ -429,7 +628,7 @@ defmodule HttpRequestMock do      {:ok,       %Tesla.Env{         status: 200, -       body: File.read!("test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.html") +       body: File.read!("test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json")       }}    end diff --git a/test/tasks/count_statuses_test.exs b/test/tasks/count_statuses_test.exs new file mode 100644 index 000000000..6035da3c3 --- /dev/null +++ b/test/tasks/count_statuses_test.exs @@ -0,0 +1,39 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.CountStatusesTest do +  use Pleroma.DataCase + +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import ExUnit.CaptureIO, only: [capture_io: 1] +  import Pleroma.Factory + +  test "counts statuses" do +    user = insert(:user) +    {:ok, _} = CommonAPI.post(user, %{"status" => "test"}) +    {:ok, _} = CommonAPI.post(user, %{"status" => "test2"}) + +    user2 = insert(:user) +    {:ok, _} = CommonAPI.post(user2, %{"status" => "test3"}) + +    user = refresh_record(user) +    user2 = refresh_record(user2) + +    assert %{info: %{note_count: 2}} = user +    assert %{info: %{note_count: 1}} = user2 + +    {:ok, user} = User.update_info(user, &User.Info.set_note_count(&1, 0)) +    {:ok, user2} = User.update_info(user2, &User.Info.set_note_count(&1, 0)) + +    assert %{info: %{note_count: 0}} = user +    assert %{info: %{note_count: 0}} = user2 + +    assert capture_io(fn -> Mix.Tasks.Pleroma.CountStatuses.run([]) end) == "Done\n" + +    assert %{info: %{note_count: 2}} = refresh_record(user) +    assert %{info: %{note_count: 1}} = refresh_record(user2) +  end +end diff --git a/test/user_search_test.exs b/test/user_search_test.exs index f7ab31287..78a02d536 100644 --- a/test/user_search_test.exs +++ b/test/user_search_test.exs @@ -65,21 +65,6 @@ defmodule Pleroma.UserSearchTest do        assert [u2.id, u1.id] == Enum.map(User.search("bar word"), & &1.id)      end -    test "finds users, ranking by similarity" do -      u1 = insert(:user, %{name: "lain"}) -      _u2 = insert(:user, %{name: "ean"}) -      u3 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"}) -      u4 = insert(:user, %{nickname: "lain@pleroma.soykaf.com"}) - -      assert [u4.id, u3.id, u1.id] == Enum.map(User.search("lain@ple", for_user: u1), & &1.id) -    end - -    test "finds users, handling misspelled requests" do -      u1 = insert(:user, %{name: "lain"}) - -      assert [u1.id] == Enum.map(User.search("laiin"), & &1.id) -    end -      test "finds users, boosting ranks of friends and followers" do        u1 = insert(:user)        u2 = insert(:user, %{name: "Doe"}) @@ -163,17 +148,6 @@ defmodule Pleroma.UserSearchTest do        Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)      end -    test "finds a user whose name is nil" do -      _user = insert(:user, %{name: "notamatch", nickname: "testuser@pleroma.amplifie.red"}) -      user_two = insert(:user, %{name: nil, nickname: "lain@pleroma.soykaf.com"}) - -      assert user_two == -               User.search("lain@pleroma.soykaf.com") -               |> List.first() -               |> Map.put(:search_rank, nil) -               |> Map.put(:search_type, nil) -    end -      test "does not yield false-positive matches" do        insert(:user, %{name: "John Doe"}) diff --git a/test/user_test.exs b/test/user_test.exs index 126bd69e8..ad050b7da 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -190,23 +190,6 @@ defmodule Pleroma.UserTest do      refute User.following?(follower, followed)    end -  # This is a somewhat useless test. -  # test "following a remote user will ensure a websub subscription is present" do -  #   user = insert(:user) -  #   {:ok, followed} = OStatus.make_user("shp@social.heldscal.la") - -  #   assert followed.local == false - -  #   {:ok, user} = User.follow(user, followed) -  #   assert User.ap_followers(followed) in user.following - -  #   query = from w in WebsubClientSubscription, -  #   where: w.topic == ^followed.info["topic"] -  #   websub = Repo.one(query) - -  #   assert websub -  # end -    describe "unfollow/2" do      setup do        setting = Pleroma.Config.get([:instance, :external_user_synchronization]) @@ -474,11 +457,6 @@ defmodule Pleroma.UserTest do        assert user == fetched_user      end -    test "fetches an external user via ostatus if no user exists" do -      {:ok, fetched_user} = User.get_or_fetch_by_nickname("shp@social.heldscal.la") -      assert fetched_user.nickname == "shp@social.heldscal.la" -    end -      test "returns nil if no user could be fetched" do        {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")        assert fetched_user == "not found nonexistant@social.heldscal.la" @@ -515,7 +493,7 @@ defmodule Pleroma.UserTest do      user = insert(:user)      assert User.ap_id(user) == -             Pleroma.Web.Router.Helpers.o_status_url( +             Pleroma.Web.Router.Helpers.feed_url(                 Pleroma.Web.Endpoint,                 :feed_redirect,                 user.nickname @@ -526,7 +504,7 @@ defmodule Pleroma.UserTest do      user = insert(:user)      assert User.ap_followers(user) == -             Pleroma.Web.Router.Helpers.o_status_url( +             Pleroma.Web.Router.Helpers.feed_url(                 Pleroma.Web.Endpoint,                 :feed_redirect,                 user.nickname @@ -1457,15 +1435,15 @@ defmodule Pleroma.UserTest do    describe "ensure_keys_present" do      test "it creates keys for a user and stores them in info" do        user = insert(:user) -      refute is_binary(user.info.keys) +      refute is_binary(user.keys)        {:ok, user} = User.ensure_keys_present(user) -      assert is_binary(user.info.keys) +      assert is_binary(user.keys)      end      test "it doesn't create keys if there already are some" do -      user = insert(:user, %{info: %{keys: "xxx"}}) +      user = insert(:user, keys: "xxx")        {:ok, user} = User.ensure_keys_present(user) -      assert user.info.keys == "xxx" +      assert user.keys == "xxx"      end    end @@ -1725,4 +1703,61 @@ defmodule Pleroma.UserTest do      assert %{info: %{hide_follows: true}} = Repo.get(User, user.id)      assert {:ok, %{info: %{hide_follows: true}}} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")    end + +  describe "get_cached_by_nickname_or_id" do +    setup do +      limit_to_local_content = Pleroma.Config.get([:instance, :limit_to_local_content]) +      local_user = insert(:user) +      remote_user = insert(:user, nickname: "nickname@example.com", local: false) + +      on_exit(fn -> +        Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local_content) +      end) + +      [local_user: local_user, remote_user: remote_user] +    end + +    test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{ +      remote_user: remote_user +    } do +      Pleroma.Config.put([:instance, :limit_to_local_content], false) +      assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) + +      Pleroma.Config.put([:instance, :limit_to_local_content], true) +      assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) + +      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) +      assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) +    end + +    test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated", +         %{remote_user: remote_user} do +      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) +      assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) +    end + +    test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated", +         %{remote_user: remote_user, local_user: local_user} do +      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) +      assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user) +    end + +    test "disallows getting remote users by nickname when :limit_to_local_content is set to true", +         %{remote_user: remote_user} do +      Pleroma.Config.put([:instance, :limit_to_local_content], true) +      assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) +    end + +    test "allows getting local users by nickname no matter what :limit_to_local_content is set to", +         %{local_user: local_user} do +      Pleroma.Config.put([:instance, :limit_to_local_content], false) +      assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) + +      Pleroma.Config.put([:instance, :limit_to_local_content], true) +      assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) + +      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) +      assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) +    end +  end  end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 1ffa91b70..6a3e48b5e 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -225,69 +225,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      end    end -  describe "/object/:uuid/likes" do -    setup do -      like = insert(:like_activity) -      like_object_ap_id = Object.normalize(like).data["id"] - -      uuid = -        like_object_ap_id -        |> String.split("/") -        |> List.last() - -      [id: like.data["id"], uuid: uuid] -    end - -    test "it returns the like activities in a collection", %{conn: conn, id: id, uuid: uuid} do -      result = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/objects/#{uuid}/likes") -        |> json_response(200) - -      assert List.first(result["first"]["orderedItems"])["id"] == id -      assert result["type"] == "OrderedCollection" -      assert result["totalItems"] == 1 -      refute result["first"]["next"] -    end - -    test "it does not crash when page number is exceeded total pages", %{conn: conn, uuid: uuid} do -      result = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/objects/#{uuid}/likes?page=2") -        |> json_response(200) - -      assert result["type"] == "OrderedCollectionPage" -      assert result["totalItems"] == 1 -      refute result["next"] -      assert Enum.empty?(result["orderedItems"]) -    end - -    test "it contains the next key when likes count is more than 10", %{conn: conn} do -      note = insert(:note_activity) -      insert_list(11, :like_activity, note_activity: note) - -      uuid = -        note -        |> Object.normalize() -        |> Map.get(:data) -        |> Map.get("id") -        |> String.split("/") -        |> List.last() - -      result = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/objects/#{uuid}/likes?page=1") -        |> json_response(200) - -      assert result["totalItems"] == 11 -      assert length(result["orderedItems"]) == 10 -      assert result["next"] -    end -  end -    describe "/activities/:uuid" do      test "it returns a json representation of the activity", %{conn: conn} do        activity = insert(:note_activity) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index a203d1d30..28a9b773c 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -41,6 +41,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do          assert called(Pleroma.Web.Streamer.stream("participation", participations))        end      end + +    test "streams them out on activity creation" do +      user_one = insert(:user) +      user_two = insert(:user) + +      with_mock Pleroma.Web.Streamer, +        stream: fn _, _ -> nil end do +        {:ok, activity} = +          CommonAPI.post(user_one, %{ +            "status" => "@#{user_two.nickname}", +            "visibility" => "direct" +          }) + +        conversation = +          activity.data["context"] +          |> Pleroma.Conversation.get_for_ap_id() +          |> Repo.preload(participations: :user) + +        assert called(Pleroma.Web.Streamer.stream("participation", conversation.participations)) +      end +    end    end    describe "fetching restricted by visibility" do @@ -87,6 +108,66 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end +  describe "fetching excluded by visibility" do +    test "it excludes by the appropriate visibility" do +      user = insert(:user) + +      {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) + +      {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + +      {:ok, unlisted_activity} = +        CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"}) + +      {:ok, private_activity} = +        CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) + +      activities = +        ActivityPub.fetch_activities([], %{ +          "exclude_visibilities" => "direct", +          "actor_id" => user.ap_id +        }) + +      assert public_activity in activities +      assert unlisted_activity in activities +      assert private_activity in activities +      refute direct_activity in activities + +      activities = +        ActivityPub.fetch_activities([], %{ +          "exclude_visibilities" => "unlisted", +          "actor_id" => user.ap_id +        }) + +      assert public_activity in activities +      refute unlisted_activity in activities +      assert private_activity in activities +      assert direct_activity in activities + +      activities = +        ActivityPub.fetch_activities([], %{ +          "exclude_visibilities" => "private", +          "actor_id" => user.ap_id +        }) + +      assert public_activity in activities +      assert unlisted_activity in activities +      refute private_activity in activities +      assert direct_activity in activities + +      activities = +        ActivityPub.fetch_activities([], %{ +          "exclude_visibilities" => "public", +          "actor_id" => user.ap_id +        }) + +      refute public_activity in activities +      assert unlisted_activity in activities +      assert private_activity in activities +      assert direct_activity in activities +    end +  end +    describe "building a user from his ap id" do      test "it returns a user" do        user_id = "http://mastodon.example.org/users/admin" @@ -811,10 +892,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, like_activity, object} = ActivityPub.like(user, object)        assert object.data["like_count"] == 1 -      {:ok, _, _, object} = ActivityPub.unlike(user, object) +      {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)        assert object.data["like_count"] == 0        assert Activity.get_by_id(like_activity.id) == nil +      assert note_activity.actor in unlike_activity.recipients      end    end @@ -839,6 +921,39 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end +  describe "announcing a private object" do +    test "adds an announce activity to the db if the audience is not widened" do +      user = insert(:user) +      {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) +      object = Object.normalize(note_activity) + +      {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false) + +      assert announce_activity.data["to"] == [User.ap_followers(user)] + +      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 + +    test "does not add an announce activity to the db if the audience is widened" do +      user = insert(:user) +      {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) +      object = Object.normalize(note_activity) + +      assert {:error, _} = ActivityPub.announce(user, object, nil, true, true) +    end + +    test "does not add an announce activity to the db if the announcer is not the author" do +      user = insert(:user) +      announcer = insert(:user) +      {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) +      object = Object.normalize(note_activity) + +      assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false) +    end +  end +    describe "unannouncing an object" do      test "unannouncing a previously announced object" do        note_activity = insert(:note_activity) @@ -857,7 +972,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert unannounce_activity.data["to"] == [                 User.ap_followers(user), -               announce_activity.data["actor"] +               object.data["actor"]               ]        assert unannounce_activity.data["type"] == "Undo" diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs index 7203b27da..df0f223f8 100644 --- a/test/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/web/activity_pub/mrf/simple_policy_test.exs @@ -236,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(remote_message) == {:ok, remote_message}      end -    test "has a matching host" do +    test "activity has a matching host" do        Config.put([:mrf_simple, :reject], ["remote.instance"])        remote_message = build_remote_message() @@ -244,13 +244,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(remote_message) == {:reject, nil}      end -    test "match with wildcard domain" do +    test "activity matches with wildcard domain" do        Config.put([:mrf_simple, :reject], ["*.remote.instance"])        remote_message = build_remote_message()        assert SimplePolicy.filter(remote_message) == {:reject, nil}      end + +    test "actor has a matching host" do +      Config.put([:mrf_simple, :reject], ["remote.instance"]) + +      remote_user = build_remote_user() + +      assert SimplePolicy.filter(remote_user) == {:reject, nil} +    end    end    describe "when :accept" do @@ -264,7 +272,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(remote_message) == {:ok, remote_message}      end -    test "is not empty but it doesn't have a matching host" do +    test "is not empty but activity doesn't have a matching host" do        Config.put([:mrf_simple, :accept], ["non.matching.remote"])        local_message = build_local_message() @@ -274,7 +282,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(remote_message) == {:reject, nil}      end -    test "has a matching host" do +    test "activity has a matching host" do        Config.put([:mrf_simple, :accept], ["remote.instance"])        local_message = build_local_message() @@ -284,7 +292,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(remote_message) == {:ok, remote_message}      end -    test "match with wildcard domain" do +    test "activity matches with wildcard domain" do        Config.put([:mrf_simple, :accept], ["*.remote.instance"])        local_message = build_local_message() @@ -293,6 +301,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do        assert SimplePolicy.filter(local_message) == {:ok, local_message}        assert SimplePolicy.filter(remote_message) == {:ok, remote_message}      end + +    test "actor has a matching host" do +      Config.put([:mrf_simple, :accept], ["remote.instance"]) + +      remote_user = build_remote_user() + +      assert SimplePolicy.filter(remote_user) == {:ok, remote_user} +    end    end    describe "when :avatar_removal" do diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 0f7556538..4a0a03944 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -22,8 +22,8 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    describe "follow/1" do      test "returns errors when user not found" do        assert capture_log(fn -> -               assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} -             end) =~ "Could not fetch by AP id" +               {:error, _} = Relay.follow("test-ap-id") +             end) =~ "Could not decode user at fetch"      end      test "returns activity" do @@ -41,8 +41,8 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    describe "unfollow/1" do      test "returns errors when user not found" do        assert capture_log(fn -> -               assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} -             end) =~ "Could not fetch by AP id" +               {:error, _} = Relay.unfollow("test-ap-id") +             end) =~ "Could not decode user at fetch"      end      test "returns activity" do diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 193d6d301..dbb6e59b0 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -7,14 +7,11 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    alias Pleroma.Activity    alias Pleroma.Object    alias Pleroma.Object.Fetcher -  alias Pleroma.Repo    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.CommonAPI -  alias Pleroma.Web.OStatus -  alias Pleroma.Web.Websub.WebsubClientSubscription    import Mock    import Pleroma.Factory @@ -378,6 +375,31 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"      end +    test "it works for incoming unlikes with an existing like activity and a compact object" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"}) + +      like_data = +        File.read!("test/fixtures/mastodon-like.json") +        |> Poison.decode!() +        |> Map.put("object", activity.data["object"]) + +      {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data) + +      data = +        File.read!("test/fixtures/mastodon-undo-like.json") +        |> Poison.decode!() +        |> Map.put("object", like_data["id"]) +        |> Map.put("actor", like_data["actor"]) + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +      assert data["actor"] == "http://mastodon.example.org/users/admin" +      assert data["type"] == "Undo" +      assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo" +      assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2" +    end +      test "it works for incoming announces" do        data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!() @@ -417,6 +439,33 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id      end +    test "it works for incoming announces with an inlined activity" do +      data = +        File.read!("test/fixtures/mastodon-announce-private.json") +        |> Poison.decode!() + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +      assert data["actor"] == "http://mastodon.example.org/users/admin" +      assert data["type"] == "Announce" + +      assert data["id"] == +               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" + +      object = Object.normalize(data["object"]) + +      assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368" +      assert object.data["content"] == "this is a private toot" +    end + +    test "it rejects incoming announces with an inlined activity from another origin" do +      data = +        File.read!("test/fixtures/bogus-mastodon-announce.json") +        |> Poison.decode!() + +      assert :error = Transmogrifier.handle_incoming(data) +    end +      test "it does not clobber the addressing on announce activities" do        user = insert(:user)        {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"}) @@ -521,6 +570,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) +      assert data["id"] == update_data["id"] +        user = User.get_cached_by_ap_id(data["actor"])        assert user.name == "gargle" @@ -628,6 +679,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do      test "it works for incoming deletes" do        activity = insert(:note_activity) +      deleting_user = insert(:user)        data =          File.read!("test/fixtures/mastodon-delete.json") @@ -640,11 +692,14 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data =          data          |> Map.put("object", object) -        |> Map.put("actor", activity.data["actor"]) +        |> Map.put("actor", deleting_user.ap_id) -      {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) +      {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} = +        Transmogrifier.handle_incoming(data) +      assert id == data["id"]        refute Activity.get_by_id(activity.id) +      assert actor == deleting_user.ap_id      end      test "it fails for incoming deletes with spoofed origin" do @@ -851,6 +906,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert activity.data["object"] == follow_activity.data["id"] +      assert activity.data["id"] == accept_data["id"] +        follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == true @@ -955,6 +1012,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} = Transmogrifier.handle_incoming(reject_data)        refute activity.local +      assert activity.data["id"] == reject_data["id"]        follower = User.get_cached_by_id(follower.id) @@ -1051,6 +1109,19 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    end    describe "prepare outgoing" do +    test "it inlines private announced objects" do +      user = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "hey", "visibility" => "private"}) + +      {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) + +      {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) + +      assert modified["object"]["content"] == "hey" +      assert modified["object"]["actor"] == modified["object"]["attributedTo"] +    end +      test "it turns mentions into tags" do        user = insert(:user)        other_user = insert(:user) @@ -1107,32 +1178,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert modified["object"]["actor"] == modified["object"]["attributedTo"]      end -    test "it translates ostatus IDs to external URLs" do -      incoming = File.read!("test/fixtures/incoming_note_activity.xml") -      {:ok, [referent_activity]} = OStatus.handle_incoming(incoming) - -      user = insert(:user) - -      {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user) -      {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - -      assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29" -    end - -    test "it translates ostatus reply_to IDs to external URLs" do -      incoming = File.read!("test/fixtures/incoming_note_activity.xml") -      {:ok, [referred_activity]} = OStatus.handle_incoming(incoming) - -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id}) - -      {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - -      assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29" -    end -      test "it strips internal hashtag data" do        user = insert(:user) @@ -1297,21 +1342,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do      end    end -  describe "maybe_retire_websub" do -    test "it deletes all websub client subscripitions with the user as topic" do -      subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"} -      {:ok, ws} = Repo.insert(subscription) - -      subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"} -      {:ok, ws2} = Repo.insert(subscription) - -      Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye") - -      refute Repo.get(WebsubClientSubscription, ws.id) -      assert Repo.get(WebsubClientSubscription, ws2.id) -    end -  end -    describe "actor rewriting" do      test "it fixes the actor URL property to be a proper URI" do        data = %{ diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index b1c1d6f71..c57ea7eb9 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -106,11 +106,13 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        user = insert(:user)        like_activity = insert(:like_activity, data_attrs: %{"context" => "test context"}) +      object = Object.normalize(like_activity.data["object"]) +        assert Utils.make_unlike_data(user, like_activity, nil) == %{                 "type" => "Undo",                 "actor" => user.ap_id,                 "object" => like_activity.data, -               "to" => [user.follower_address, like_activity.data["actor"]], +               "to" => [user.follower_address, object.data["actor"]],                 "cc" => [Pleroma.Constants.as_public()],                 "context" => like_activity.data["context"]               } @@ -119,7 +121,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do                 "type" => "Undo",                 "actor" => user.ap_id,                 "object" => like_activity.data, -               "to" => [user.follower_address, like_activity.data["actor"]], +               "to" => [user.follower_address, object.data["actor"]],                 "cc" => [Pleroma.Constants.as_public()],                 "context" => like_activity.data["context"],                 "id" => "9mJEZK0tky1w2xD2vY" diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index b5c355e66..9da4940be 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -17,8 +17,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    alias Pleroma.Web.MediaProxy    import Pleroma.Factory -  describe "/api/pleroma/admin/users" do -    test "Delete" do +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + +    :ok +  end + +  describe "DELETE /api/pleroma/admin/users" do +    test "single user" do        admin = insert(:user, info: %{is_admin: true})        user = insert(:user) @@ -30,15 +36,36 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        log_entry = Repo.one(ModerationLog) -      assert log_entry.data["subject"]["nickname"] == user.nickname -      assert log_entry.data["action"] == "delete" -        assert ModerationLog.get_log_entry_message(log_entry) == -               "@#{admin.nickname} deleted user @#{user.nickname}" +               "@#{admin.nickname} deleted users: @#{user.nickname}"        assert json_response(conn, 200) == user.nickname      end +    test "multiple users" do +      admin = insert(:user, info: %{is_admin: true}) +      user_one = insert(:user) +      user_two = insert(:user) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> put_req_header("accept", "application/json") +        |> delete("/api/pleroma/admin/users", %{ +          nicknames: [user_one.nickname, user_two.nickname] +        }) + +      log_entry = Repo.one(ModerationLog) + +      assert ModerationLog.get_log_entry_message(log_entry) == +               "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}" + +      response = json_response(conn, 200) +      assert response -- [user_one.nickname, user_two.nickname] == [] +    end +  end + +  describe "/api/pleroma/admin/users" do      test "Create" do        admin = insert(:user, info: %{is_admin: true}) @@ -404,82 +431,72 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 "@#{admin.nickname} made @#{user.nickname} admin"      end -    test "/:right DELETE, can remove from a permission group" do +    test "/:right POST, can add to a permission group (multiple)" do        admin = insert(:user, info: %{is_admin: true}) -      user = insert(:user, info: %{is_admin: true}) +      user_one = insert(:user) +      user_two = insert(:user)        conn =          build_conn()          |> assign(:user, admin)          |> put_req_header("accept", "application/json") -        |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") +        |> post("/api/pleroma/admin/users/permission_group/admin", %{ +          nicknames: [user_one.nickname, user_two.nickname] +        })        assert json_response(conn, 200) == %{ -               "is_admin" => false +               "is_admin" => true               }        log_entry = Repo.one(ModerationLog)        assert ModerationLog.get_log_entry_message(log_entry) == -               "@#{admin.nickname} revoked admin role from @#{user.nickname}" +               "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"      end -  end -  describe "PUT /api/pleroma/admin/users/:nickname/activation_status" do -    setup %{conn: conn} do +    test "/:right DELETE, can remove from a permission group" do        admin = insert(:user, info: %{is_admin: true}) +      user = insert(:user, info: %{is_admin: true})        conn = -        conn +        build_conn()          |> assign(:user, admin)          |> put_req_header("accept", "application/json") +        |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") -      %{conn: conn, admin: admin} -    end - -    test "deactivates the user", %{conn: conn, admin: admin} do -      user = insert(:user) - -      conn = -        conn -        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: false}) - -      user = User.get_cached_by_id(user.id) -      assert user.info.deactivated == true -      assert json_response(conn, :no_content) +      assert json_response(conn, 200) == %{ +               "is_admin" => false +             }        log_entry = Repo.one(ModerationLog)        assert ModerationLog.get_log_entry_message(log_entry) == -               "@#{admin.nickname} deactivated user @#{user.nickname}" +               "@#{admin.nickname} revoked admin role from @#{user.nickname}"      end -    test "activates the user", %{conn: conn, admin: admin} do -      user = insert(:user, info: %{deactivated: true}) +    test "/:right DELETE, can remove from a permission group (multiple)" do +      admin = insert(:user, info: %{is_admin: true}) +      user_one = insert(:user, info: %{is_admin: true}) +      user_two = insert(:user, info: %{is_admin: true})        conn = -        conn -        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: true}) +        build_conn() +        |> assign(:user, admin) +        |> put_req_header("accept", "application/json") +        |> delete("/api/pleroma/admin/users/permission_group/admin", %{ +          nicknames: [user_one.nickname, user_two.nickname] +        }) -      user = User.get_cached_by_id(user.id) -      assert user.info.deactivated == false -      assert json_response(conn, :no_content) +      assert json_response(conn, 200) == %{ +               "is_admin" => false +             }        log_entry = Repo.one(ModerationLog)        assert ModerationLog.get_log_entry_message(log_entry) == -               "@#{admin.nickname} activated user @#{user.nickname}" -    end - -    test "returns 403 when requested by a non-admin", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: false}) - -      assert json_response(conn, :forbidden) +               "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{ +                 user_two.nickname +               }"      end    end @@ -1029,6 +1046,50 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end +  test "PATCH /api/pleroma/admin/users/activate" do +    admin = insert(:user, info: %{is_admin: true}) +    user_one = insert(:user, info: %{deactivated: true}) +    user_two = insert(:user, info: %{deactivated: true}) + +    conn = +      build_conn() +      |> assign(:user, admin) +      |> patch( +        "/api/pleroma/admin/users/activate", +        %{nicknames: [user_one.nickname, user_two.nickname]} +      ) + +    response = json_response(conn, 200) +    assert Enum.map(response["users"], & &1["deactivated"]) == [false, false] + +    log_entry = Repo.one(ModerationLog) + +    assert ModerationLog.get_log_entry_message(log_entry) == +             "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" +  end + +  test "PATCH /api/pleroma/admin/users/deactivate" do +    admin = insert(:user, info: %{is_admin: true}) +    user_one = insert(:user, info: %{deactivated: false}) +    user_two = insert(:user, info: %{deactivated: false}) + +    conn = +      build_conn() +      |> assign(:user, admin) +      |> patch( +        "/api/pleroma/admin/users/deactivate", +        %{nicknames: [user_one.nickname, user_two.nickname]} +      ) + +    response = json_response(conn, 200) +    assert Enum.map(response["users"], & &1["deactivated"]) == [true, true] + +    log_entry = Repo.one(ModerationLog) + +    assert ModerationLog.get_log_entry_message(log_entry) == +             "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" +  end +    test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do      admin = insert(:user, info: %{is_admin: true})      user = insert(:user) @@ -1053,7 +1114,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      log_entry = Repo.one(ModerationLog)      assert ModerationLog.get_log_entry_message(log_entry) == -             "@#{admin.nickname} deactivated user @#{user.nickname}" +             "@#{admin.nickname} deactivated users: @#{user.nickname}"    end    describe "POST /api/pleroma/admin/users/invite_token" do @@ -2486,6 +2547,74 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert User.get_by_id(user.id).info.password_reset_pending == true      end    end + +  describe "relays" do +    setup %{conn: conn} do +      admin = insert(:user, info: %{is_admin: true}) + +      %{conn: assign(conn, :user, admin), admin: admin} +    end + +    test "POST /relay", %{admin: admin} do +      conn = +        build_conn() +        |> assign(:user, admin) +        |> post("/api/pleroma/admin/relay", %{ +          relay_url: "http://mastodon.example.org/users/admin" +        }) + +      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin" + +      log_entry = Repo.one(ModerationLog) + +      assert ModerationLog.get_log_entry_message(log_entry) == +               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" +    end + +    test "GET /relay", %{admin: admin} do +      Pleroma.Web.ActivityPub.Relay.get_actor() +      |> Ecto.Changeset.change( +        following: [ +          "http://test-app.com/user/test1", +          "http://test-app.com/user/test1", +          "http://test-app-42.com/user/test1" +        ] +      ) +      |> Pleroma.User.update_and_set_cache() + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/relay") + +      assert json_response(conn, 200)["relays"] -- ["test-app.com", "test-app-42.com"] == [] +    end + +    test "DELETE /relay", %{admin: admin} do +      build_conn() +      |> assign(:user, admin) +      |> post("/api/pleroma/admin/relay", %{ +        relay_url: "http://mastodon.example.org/users/admin" +      }) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> delete("/api/pleroma/admin/relay", %{ +          relay_url: "http://mastodon.example.org/users/admin" +        }) + +      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin" + +      [log_entry_one, log_entry_two] = Repo.all(ModerationLog) + +      assert ModerationLog.get_log_entry_message(log_entry_one) == +               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" + +      assert ModerationLog.get_log_entry_message(log_entry_two) == +               "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" +    end +  end  end  # Needed for testing diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 0f4a5eb25..83df44c36 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -14,6 +14,8 @@ defmodule Pleroma.Web.CommonAPITest do    import Pleroma.Factory +  require Pleroma.Constants +    clear_config([:instance, :safe_dm_mentions])    clear_config([:instance, :limit])    clear_config([:instance, :max_pinned_statuses]) @@ -96,11 +98,13 @@ defmodule Pleroma.Web.CommonAPITest do    test "it adds emoji when updating profiles" do      user = insert(:user, %{name: ":firefox:"}) -    CommonAPI.update(user) +    {:ok, activity} = CommonAPI.update(user)      user = User.get_cached_by_ap_id(user.ap_id)      [firefox] = user.info.source_data["tag"]      assert firefox["name"] == ":firefox:" + +    assert Pleroma.Constants.as_public() in activity.recipients    end    describe "posting" do @@ -231,6 +235,18 @@ defmodule Pleroma.Web.CommonAPITest do        {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)      end +    test "repeating a status privately" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) + +      {:ok, %Activity{} = announce_activity, _} = +        CommonAPI.repeat(activity.id, user, %{"visibility" => "private"}) + +      assert Visibility.is_private?(announce_activity) +    end +      test "favoriting a status" do        user = insert(:user)        other_user = insert(:user) diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 43a715706..bdaefdce1 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -111,93 +111,6 @@ defmodule Pleroma.Web.FederatorTest do                 all_enqueued(worker: PublisherWorker)               )      end - -    test "it federates only to reachable instances via Websub" do -      user = insert(:user) -      websub_topic = Pleroma.Web.OStatus.feed_path(user) - -      sub1 = -        insert(:websub_subscription, %{ -          topic: websub_topic, -          state: "active", -          callback: "http://pleroma.soykaf.com/cb" -        }) - -      sub2 = -        insert(:websub_subscription, %{ -          topic: websub_topic, -          state: "active", -          callback: "https://pleroma2.soykaf.com/cb" -        }) - -      dt = NaiveDateTime.utc_now() -      Instances.set_unreachable(sub2.callback, dt) - -      Instances.set_consistently_unreachable(sub1.callback) - -      {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI"}) - -      expected_callback = sub2.callback -      expected_dt = NaiveDateTime.to_iso8601(dt) - -      ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) - -      assert ObanHelpers.member?( -               %{ -                 "op" => "publish_one", -                 "params" => %{ -                   "callback" => expected_callback, -                   "unreachable_since" => expected_dt -                 } -               }, -               all_enqueued(worker: PublisherWorker) -             ) -    end - -    test "it federates only to reachable instances via Salmon" do -      user = insert(:user) - -      _remote_user1 = -        insert(:user, %{ -          local: false, -          nickname: "nick1@domain.com", -          ap_id: "https://domain.com/users/nick1", -          info: %{salmon: "https://domain.com/salmon"} -        }) - -      remote_user2 = -        insert(:user, %{ -          local: false, -          nickname: "nick2@domain2.com", -          ap_id: "https://domain2.com/users/nick2", -          info: %{salmon: "https://domain2.com/salmon"} -        }) - -      remote_user2_id = remote_user2.id - -      dt = NaiveDateTime.utc_now() -      Instances.set_unreachable(remote_user2.ap_id, dt) - -      Instances.set_consistently_unreachable("domain.com") - -      {:ok, _activity} = -        CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"}) - -      expected_dt = NaiveDateTime.to_iso8601(dt) - -      ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) - -      assert ObanHelpers.member?( -               %{ -                 "op" => "publish_one", -                 "params" => %{ -                   "recipient_id" => remote_user2_id, -                   "unreachable_since" => expected_dt -                 } -               }, -               all_enqueued(worker: PublisherWorker) -             ) -    end    end    describe "Receive an activity" do diff --git a/test/web/feed/feed_controller_test.exs b/test/web/feed/feed_controller_test.exs new file mode 100644 index 000000000..1f44eae20 --- /dev/null +++ b/test/web/feed/feed_controller_test.exs @@ -0,0 +1,227 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Feed.FeedControllerTest do +  use Pleroma.Web.ConnCase + +  import Pleroma.Factory + +  alias Pleroma.Object +  alias Pleroma.User + +  test "gets a feed", %{conn: conn} do +    activity = insert(:note_activity) + +    note = +      insert(:note, +        data: %{ +          "attachment" => [ +            %{ +              "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}] +            } +          ], +          "inReplyTo" => activity.data["id"] +        } +      ) + +    note_activity = insert(:note_activity, note: note) +    object = Object.normalize(note_activity) +    user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +    conn = +      conn +      |> put_req_header("content-type", "application/atom+xml") +      |> get("/users/#{user.nickname}/feed.atom") + +    assert response(conn, 200) =~ object.data["content"] +  end + +  test "returns 404 for a missing feed", %{conn: conn} do +    conn = +      conn +      |> put_req_header("content-type", "application/atom+xml") +      |> get("/users/nonexisting/feed.atom") + +    assert response(conn, 404) +  end + +  describe "feed_redirect" do +    test "undefined format. it redirects to feed", %{conn: conn} do +      note_activity = insert(:note_activity) +      user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +      response = +        conn +        |> put_req_header("accept", "application/xml") +        |> get("/users/#{user.nickname}") +        |> response(302) + +      assert response == +               "<html><body>You are being <a href=\"#{Pleroma.Web.base_url()}/users/#{ +                 user.nickname +               }/feed.atom\">redirected</a>.</body></html>" +    end + +    test "undefined format. it returns error when user not found", %{conn: conn} do +      response = +        conn +        |> put_req_header("accept", "application/xml") +        |> get("/users/jimm") +        |> response(404) + +      assert response == ~S({"error":"Not found"}) +    end + +    test "activity+json format. it redirects on actual feed of user", %{conn: conn} do +      note_activity = insert(:note_activity) +      user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +      response = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get("/users/#{user.nickname}") +        |> json_response(200) + +      assert response["endpoints"] == %{ +               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", +               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", +               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", +               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", +               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" +             } + +      assert response["@context"] == [ +               "https://www.w3.org/ns/activitystreams", +               "http://localhost:4001/schemas/litepub-0.1.jsonld", +               %{"@language" => "und"} +             ] + +      assert Map.take(response, [ +               "followers", +               "following", +               "id", +               "inbox", +               "manuallyApprovesFollowers", +               "name", +               "outbox", +               "preferredUsername", +               "summary", +               "tag", +               "type", +               "url" +             ]) == %{ +               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", +               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", +               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", +               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", +               "manuallyApprovesFollowers" => false, +               "name" => user.name, +               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", +               "preferredUsername" => user.nickname, +               "summary" => user.bio, +               "tag" => [], +               "type" => "Person", +               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" +             } +    end + +    test "activity+json format. it returns error whe use not found", %{conn: conn} do +      response = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get("/users/jimm") +        |> json_response(404) + +      assert response == "Not found" +    end + +    test "json format. it redirects on actual feed of user", %{conn: conn} do +      note_activity = insert(:note_activity) +      user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +      response = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/#{user.nickname}") +        |> json_response(200) + +      assert response["endpoints"] == %{ +               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", +               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", +               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", +               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", +               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" +             } + +      assert response["@context"] == [ +               "https://www.w3.org/ns/activitystreams", +               "http://localhost:4001/schemas/litepub-0.1.jsonld", +               %{"@language" => "und"} +             ] + +      assert Map.take(response, [ +               "followers", +               "following", +               "id", +               "inbox", +               "manuallyApprovesFollowers", +               "name", +               "outbox", +               "preferredUsername", +               "summary", +               "tag", +               "type", +               "url" +             ]) == %{ +               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", +               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", +               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", +               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", +               "manuallyApprovesFollowers" => false, +               "name" => user.name, +               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", +               "preferredUsername" => user.nickname, +               "summary" => user.bio, +               "tag" => [], +               "type" => "Person", +               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" +             } +    end + +    test "json format. it returns error whe use not found", %{conn: conn} do +      response = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/jimm") +        |> json_response(404) + +      assert response == "Not found" +    end + +    test "html format. it redirects on actual feed of user", %{conn: conn} do +      note_activity = insert(:note_activity) +      user = User.get_cached_by_ap_id(note_activity.data["actor"]) + +      response = +        conn +        |> get("/users/#{user.nickname}") +        |> response(200) + +      assert response == +               Fallback.RedirectController.redirector_with_meta( +                 conn, +                 %{user: user} +               ).resp_body +    end + +    test "html format. it returns error when user not found", %{conn: conn} do +      response = +        conn +        |> get("/users/jimm") +        |> json_response(404) + +      assert response == %{"error" => "Not found"} +    end +  end +end diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs new file mode 100644 index 000000000..ab9dab352 --- /dev/null +++ b/test/web/masto_fe_controller_test.exs @@ -0,0 +1,84 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MastoFEController do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Config +  alias Pleroma.User + +  import Pleroma.Factory + +  clear_config([:instance, :public]) + +  test "put settings", %{conn: conn} do +    user = insert(:user) + +    conn = +      conn +      |> assign(:user, user) +      |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}}) + +    assert _result = json_response(conn, 200) + +    user = User.get_cached_by_ap_id(user.ap_id) +    assert user.info.settings == %{"programming" => "socks"} +  end + +  describe "index/2 redirections" do +    setup %{conn: conn} do +      session_opts = [ +        store: :cookie, +        key: "_test", +        signing_salt: "cooldude" +      ] + +      conn = +        conn +        |> Plug.Session.call(Plug.Session.init(session_opts)) +        |> fetch_session() + +      test_path = "/web/statuses/test" +      %{conn: conn, path: test_path} +    end + +    test "redirects not logged-in users to the login page", %{conn: conn, path: path} do +      conn = get(conn, path) + +      assert conn.status == 302 +      assert redirected_to(conn) == "/web/login" +    end + +    test "redirects not logged-in users to the login page on private instances", %{ +      conn: conn, +      path: path +    } do +      Config.put([:instance, :public], false) + +      conn = get(conn, path) + +      assert conn.status == 302 +      assert redirected_to(conn) == "/web/login" +    end + +    test "does not redirect logged in users to the login page", %{conn: conn, path: path} do +      token = insert(:oauth_token) + +      conn = +        conn +        |> assign(:user, token.user) +        |> put_session(:oauth_token, token.token) +        |> get(path) + +      assert conn.status == 200 +    end + +    test "saves referer path to session", %{conn: conn, path: path} do +      conn = get(conn, path) +      return_to = Plug.Conn.get_session(conn, :return_to) + +      assert return_to == path +    end +  end +end diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index 560f55137..618031b40 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -272,7 +272,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert user_response["pleroma"]["background_image"]      end -    test "requires 'write' permission", %{conn: conn} do +    test "requires 'write:accounts' permission", %{conn: conn} do        token1 = insert(:oauth_token, scopes: ["read"])        token2 = insert(:oauth_token, scopes: ["write", "follow"]) @@ -283,7 +283,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do            |> patch("/api/v1/accounts/update_credentials", %{})          if token == token1 do -          assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403) +          assert %{"error" => "Insufficient permissions: write:accounts."} == +                   json_response(conn, 403)          else            assert json_response(conn, 200)          end @@ -328,7 +329,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        account =          conn          |> assign(:user, user) -        |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) +        |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})          |> json_response(200)        assert account["fields"] == [ @@ -344,6 +345,35 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do                 %{"name" => "link", "value" => "cofe.io"}               ] +      fields = +        [ +          "fields_attributes[1][name]=link", +          "fields_attributes[1][value]=cofe.io", +          "fields_attributes[0][name]=<a href=\"http://google.com\">foo</a>", +          "fields_attributes[0][value]=bar" +        ] +        |> Enum.join("&") + +      account = +        conn +        |> put_req_header("content-type", "application/x-www-form-urlencoded") +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", fields) +        |> json_response(200) + +      assert account["fields"] == [ +               %{"name" => "foo", "value" => "bar"}, +               %{"name" => "link", "value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>)} +             ] + +      assert account["source"]["fields"] == [ +               %{ +                 "name" => "<a href=\"http://google.com\">foo</a>", +                 "value" => "bar" +               }, +               %{"name" => "link", "value" => "cofe.io"} +             ] +        name_limit = Pleroma.Config.get([:instance, :account_field_name_length])        value_limit = Pleroma.Config.get([:instance, :account_field_value_length]) @@ -354,7 +384,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert %{"error" => "Invalid request"} ==                 conn                 |> assign(:user, user) -               |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) +               |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})                 |> json_response(403)        long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join() @@ -364,7 +394,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert %{"error" => "Invalid request"} ==                 conn                 |> assign(:user, user) -               |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) +               |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})                 |> json_response(403)        Pleroma.Config.put([:instance, :max_account_fields], 1) @@ -377,8 +407,23 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert %{"error" => "Invalid request"} ==                 conn                 |> assign(:user, user) -               |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) +               |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})                 |> json_response(403) + +      fields = [ +        %{"name" => "foo", "value" => ""}, +        %{"name" => "", "value" => "bar"} +      ] + +      account = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) +        |> json_response(200) + +      assert account["fields"] == [ +               %{"name" => "foo", "value" => ""} +             ]      end    end  end diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 8c8017838..745383757 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -237,6 +237,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        assert [%{"id" => id}] = json_response(conn, 200)        assert id == to_string(post.id)      end + +    test "the user views their own timelines and excludes direct messages", %{conn: conn} do +      user = insert(:user) +      {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) +      {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]}) + +      assert [%{"id" => id}] = json_response(conn, 200) +      assert id == to_string(public_activity.id) +    end    end    describe "followers" do @@ -849,4 +863,34 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        assert [] = json_response(conn, 200)      end    end + +  test "getting a list of mutes", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, user} = User.mute(user, other_user) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/mutes") + +    other_user_id = to_string(other_user.id) +    assert [%{"id" => ^other_user_id}] = json_response(conn, 200) +  end + +  test "getting a list of blocks", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, user} = User.block(user, other_user) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/blocks") + +    other_user_id = to_string(other_user.id) +    assert [%{"id" => ^other_user_id}] = json_response(conn, 200) +  end  end diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/web/mastodon_api/controllers/app_controller_test.exs new file mode 100644 index 000000000..51788155b --- /dev/null +++ b/test/web/mastodon_api/controllers/app_controller_test.exs @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AppControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.Repo +  alias Pleroma.Web.OAuth.App +  alias Pleroma.Web.Push + +  import Pleroma.Factory + +  test "apps/verify_credentials", %{conn: conn} do +    token = insert(:oauth_token) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(:token, token) +      |> get("/api/v1/apps/verify_credentials") + +    app = Repo.preload(token, :app).app + +    expected = %{ +      "name" => app.client_name, +      "website" => app.website, +      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) +    } + +    assert expected == json_response(conn, 200) +  end + +  test "creates an oauth app", %{conn: conn} do +    user = insert(:user) +    app_attrs = build(:oauth_app) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/apps", %{ +        client_name: app_attrs.client_name, +        redirect_uris: app_attrs.redirect_uris +      }) + +    [app] = Repo.all(App) + +    expected = %{ +      "name" => app.client_name, +      "website" => app.website, +      "client_id" => app.client_id, +      "client_secret" => app.client_secret, +      "id" => app.id |> to_string(), +      "redirect_uri" => app.redirect_uris, +      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) +    } + +    assert expected == json_response(conn, 200) +  end +end diff --git a/test/web/mastodon_api/controllers/auth_controller_test.exs b/test/web/mastodon_api/controllers/auth_controller_test.exs new file mode 100644 index 000000000..98b2a82e7 --- /dev/null +++ b/test/web/mastodon_api/controllers/auth_controller_test.exs @@ -0,0 +1,121 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Config +  alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers + +  import Pleroma.Factory +  import Swoosh.TestAssertions + +  describe "GET /web/login" do +    setup %{conn: conn} do +      session_opts = [ +        store: :cookie, +        key: "_test", +        signing_salt: "cooldude" +      ] + +      conn = +        conn +        |> Plug.Session.call(Plug.Session.init(session_opts)) +        |> fetch_session() + +      test_path = "/web/statuses/test" +      %{conn: conn, path: test_path} +    end + +    test "redirects to the saved path after log in", %{conn: conn, path: path} do +      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") +      auth = insert(:oauth_authorization, app: app) + +      conn = +        conn +        |> put_session(:return_to, path) +        |> get("/web/login", %{code: auth.token}) + +      assert conn.status == 302 +      assert redirected_to(conn) == path +    end + +    test "redirects to the getting-started page when referer is not present", %{conn: conn} do +      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") +      auth = insert(:oauth_authorization, app: app) + +      conn = get(conn, "/web/login", %{code: auth.token}) + +      assert conn.status == 302 +      assert redirected_to(conn) == "/web/getting-started" +    end +  end + +  describe "POST /auth/password, with valid parameters" do +    setup %{conn: conn} do +      user = insert(:user) +      conn = post(conn, "/auth/password?email=#{user.email}") +      %{conn: conn, user: user} +    end + +    test "it returns 204", %{conn: conn} do +      assert json_response(conn, :no_content) +    end + +    test "it creates a PasswordResetToken record for user", %{user: user} do +      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) +      assert token_record +    end + +    test "it sends an email to user", %{user: user} do +      ObanHelpers.perform_all() +      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) + +      email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) +      notify_email = Config.get([:instance, :notify_email]) +      instance_name = Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      ) +    end +  end + +  describe "POST /auth/password, with invalid parameters" do +    setup do +      user = insert(:user) +      {:ok, user: user} +    end + +    test "it returns 404 when user is not found", %{conn: conn, user: user} do +      conn = post(conn, "/auth/password?email=nonexisting_#{user.email}") +      assert conn.status == 404 +      assert conn.resp_body == "" +    end + +    test "it returns 400 when user is not local", %{conn: conn, user: user} do +      {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false)) +      conn = post(conn, "/auth/password?email=#{user.email}") +      assert conn.status == 400 +      assert conn.resp_body == "" +    end +  end + +  describe "DELETE /auth/sign_out" do +    test "redirect to root page", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> delete("/auth/sign_out") + +      assert conn.status == 302 +      assert redirected_to(conn) == "/" +    end +  end +end diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs index 7117fc76a..d89a87179 100644 --- a/test/web/mastodon_api/controllers/conversation_controller_test.exs +++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs @@ -10,19 +10,23 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do    import Pleroma.Factory -  test "Conversations", %{conn: conn} do +  test "returns a list of conversations", %{conn: conn} do      user_one = insert(:user)      user_two = insert(:user)      user_three = insert(:user)      {:ok, user_two} = User.follow(user_two, user_one) +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 0 +      {:ok, direct} =        CommonAPI.post(user_one, %{          "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",          "visibility" => "direct"        }) +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 1 +      {:ok, _follower_only} =        CommonAPI.post(user_one, %{          "status" => "Hi @#{user_two.nickname}!", @@ -50,25 +54,108 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do      assert user_two.id in account_ids      assert user_three.id in account_ids      assert is_binary(res_id) -    assert unread == true +    assert unread == false      assert res_last_status["id"] == direct.id +    assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 0 +  end -    # Apparently undocumented API endpoint -    res_conn = +  test "updates the last_status on reply", %{conn: conn} do +    user_one = insert(:user) +    user_two = insert(:user) + +    {:ok, direct} = +      CommonAPI.post(user_one, %{ +        "status" => "Hi @#{user_two.nickname}", +        "visibility" => "direct" +      }) + +    {:ok, direct_reply} = +      CommonAPI.post(user_two, %{ +        "status" => "reply", +        "visibility" => "direct", +        "in_reply_to_status_id" => direct.id +      }) + +    [%{"last_status" => res_last_status}] =        conn        |> assign(:user, user_one) -      |> post("/api/v1/conversations/#{res_id}/read") +      |> get("/api/v1/conversations") +      |> json_response(200) -    assert response = json_response(res_conn, 200) -    assert length(response["accounts"]) == 2 -    assert response["last_status"]["id"] == direct.id -    assert response["unread"] == false +    assert res_last_status["id"] == direct_reply.id +  end + +  test "the user marks a conversation as read", %{conn: conn} do +    user_one = insert(:user) +    user_two = insert(:user) + +    {:ok, direct} = +      CommonAPI.post(user_one, %{ +        "status" => "Hi @#{user_two.nickname}", +        "visibility" => "direct" +      }) + +    assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 0 +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 1 + +    [%{"id" => direct_conversation_id, "unread" => true}] = +      conn +      |> assign(:user, user_two) +      |> get("/api/v1/conversations") +      |> json_response(200) + +    %{"unread" => false} = +      conn +      |> assign(:user, user_two) +      |> post("/api/v1/conversations/#{direct_conversation_id}/read") +      |> json_response(200) + +    assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 0 +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 0 + +    # The conversation is marked as unread on reply +    {:ok, _} = +      CommonAPI.post(user_two, %{ +        "status" => "reply", +        "visibility" => "direct", +        "in_reply_to_status_id" => direct.id +      }) + +    [%{"unread" => true}] = +      conn +      |> assign(:user, user_one) +      |> get("/api/v1/conversations") +      |> json_response(200) + +    assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 1 +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 0 + +    # A reply doesn't increment the user's unread_conversation_count if the conversation is unread +    {:ok, _} = +      CommonAPI.post(user_two, %{ +        "status" => "reply", +        "visibility" => "direct", +        "in_reply_to_status_id" => direct.id +      }) + +    assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 1 +    assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 0 +  end + +  test "(vanilla) Mastodon frontend behaviour", %{conn: conn} do +    user_one = insert(:user) +    user_two = insert(:user) + +    {:ok, direct} = +      CommonAPI.post(user_one, %{ +        "status" => "Hi @#{user_two.nickname}!", +        "visibility" => "direct" +      }) -    # (vanilla) Mastodon frontend behaviour      res_conn =        conn        |> assign(:user, user_one) -      |> get("/api/v1/statuses/#{res_last_status["id"]}/context") +      |> get("/api/v1/statuses/#{direct.id}/context")      assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)    end diff --git a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs b/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs new file mode 100644 index 000000000..2d988b0b8 --- /dev/null +++ b/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs @@ -0,0 +1,22 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  test "with tags", %{conn: conn} do +    [emoji | _body] = +      conn +      |> get("/api/v1/custom_emojis") +      |> json_response(200) + +    assert Map.has_key?(emoji, "shortcode") +    assert Map.has_key?(emoji, "static_url") +    assert Map.has_key?(emoji, "tags") +    assert is_list(emoji["tags"]) +    assert Map.has_key?(emoji, "category") +    assert Map.has_key?(emoji, "url") +    assert Map.has_key?(emoji, "visible_in_picker") +  end +end diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/web/mastodon_api/controllers/instance_controller_test.exs new file mode 100644 index 000000000..f8049f81f --- /dev/null +++ b/test/web/mastodon_api/controllers/instance_controller_test.exs @@ -0,0 +1,84 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.User +  import Pleroma.Factory + +  test "get instance information", %{conn: conn} do +    conn = get(conn, "/api/v1/instance") +    assert result = json_response(conn, 200) + +    email = Pleroma.Config.get([:instance, :email]) +    # Note: not checking for "max_toot_chars" since it's optional +    assert %{ +             "uri" => _, +             "title" => _, +             "description" => _, +             "version" => _, +             "email" => from_config_email, +             "urls" => %{ +               "streaming_api" => _ +             }, +             "stats" => _, +             "thumbnail" => _, +             "languages" => _, +             "registrations" => _, +             "poll_limits" => _, +             "upload_limit" => _, +             "avatar_upload_limit" => _, +             "background_upload_limit" => _, +             "banner_upload_limit" => _ +           } = result + +    assert email == from_config_email +  end + +  test "get instance stats", %{conn: conn} do +    user = insert(:user, %{local: true}) + +    user2 = insert(:user, %{local: true}) +    {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated) + +    insert(:user, %{local: false, nickname: "u@peer1.com"}) +    insert(:user, %{local: false, nickname: "u@peer2.com"}) + +    {:ok, _} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofe"}) + +    # Stats should count users with missing or nil `info.deactivated` value + +    {:ok, _user} = +      user.id +      |> User.get_cached_by_id() +      |> User.update_info(&Ecto.Changeset.change(&1, %{deactivated: nil})) + +    Pleroma.Stats.force_update() + +    conn = get(conn, "/api/v1/instance") + +    assert result = json_response(conn, 200) + +    stats = result["stats"] + +    assert stats +    assert stats["user_count"] == 1 +    assert stats["status_count"] == 1 +    assert stats["domain_count"] == 2 +  end + +  test "get peers", %{conn: conn} do +    insert(:user, %{local: false, nickname: "u@peer1.com"}) +    insert(:user, %{local: false, nickname: "u@peer2.com"}) + +    Pleroma.Stats.force_update() + +    conn = get(conn, "/api/v1/instance/peers") + +    assert result = json_response(conn, 200) + +    assert ["peer1.com", "peer2.com"] == Enum.sort(result) +  end +end diff --git a/test/web/mastodon_api/controllers/media_controller_test.exs b/test/web/mastodon_api/controllers/media_controller_test.exs new file mode 100644 index 000000000..06c6a1cb3 --- /dev/null +++ b/test/web/mastodon_api/controllers/media_controller_test.exs @@ -0,0 +1,92 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Object +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub + +  import Pleroma.Factory + +  describe "media upload" do +    setup do +      user = insert(:user) + +      conn = +        build_conn() +        |> assign(:user, user) + +      image = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      [conn: conn, image: image] +    end + +    clear_config([:media_proxy]) +    clear_config([Pleroma.Upload]) + +    test "returns uploaded image", %{conn: conn, image: image} do +      desc = "Description of the image" + +      media = +        conn +        |> post("/api/v1/media", %{"file" => image, "description" => desc}) +        |> json_response(:ok) + +      assert media["type"] == "image" +      assert media["description"] == desc +      assert media["id"] + +      object = Object.get_by_id(media["id"]) +      assert object.data["actor"] == User.ap_id(conn.assigns[:user]) +    end +  end + +  describe "PUT /api/v1/media/:id" do +    setup do +      actor = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, %Object{} = object} = +        ActivityPub.upload( +          file, +          actor: User.ap_id(actor), +          description: "test-m" +        ) + +      [actor: actor, object: object] +    end + +    test "updates name of media", %{conn: conn, actor: actor, object: object} do +      media = +        conn +        |> assign(:user, actor) +        |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"}) +        |> json_response(:ok) + +      assert media["description"] == "test-media" +      assert refresh_record(object).data["name"] == "test-media" +    end + +    test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do +      media = +        conn +        |> assign(:user, actor) +        |> put("/api/v1/media/#{object.id}", %{}) +        |> json_response(400) + +      assert media == %{"error" => "bad_request"} +    end +  end +end diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs index e4137e92c..fa55a7cf9 100644 --- a/test/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/web/mastodon_api/controllers/notification_controller_test.exs @@ -137,6 +137,57 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result    end +  test "filters notifications using exclude_visibilities", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, public_activity} = +      CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "public"}) + +    {:ok, direct_activity} = +      CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"}) + +    {:ok, unlisted_activity} = +      CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "unlisted"}) + +    {:ok, private_activity} = +      CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "private"}) + +    conn = assign(conn, :user, user) + +    conn_res = +      get(conn, "/api/v1/notifications", %{ +        exclude_visibilities: ["public", "unlisted", "private"] +      }) + +    assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) +    assert id == direct_activity.id + +    conn_res = +      get(conn, "/api/v1/notifications", %{ +        exclude_visibilities: ["public", "unlisted", "direct"] +      }) + +    assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) +    assert id == private_activity.id + +    conn_res = +      get(conn, "/api/v1/notifications", %{ +        exclude_visibilities: ["public", "private", "direct"] +      }) + +    assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) +    assert id == unlisted_activity.id + +    conn_res = +      get(conn, "/api/v1/notifications", %{ +        exclude_visibilities: ["unlisted", "private", "direct"] +      }) + +    assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) +    assert id == public_activity.id +  end +    test "filters notifications using exclude_types", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) diff --git a/test/web/mastodon_api/controllers/poll_controller_test.exs b/test/web/mastodon_api/controllers/poll_controller_test.exs new file mode 100644 index 000000000..40cf3e879 --- /dev/null +++ b/test/web/mastodon_api/controllers/poll_controller_test.exs @@ -0,0 +1,184 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.PollControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Object +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "GET /api/v1/polls/:id" do +    test "returns poll entity for object id", %{conn: conn} do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Pleroma does", +          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20} +        }) + +      object = Object.normalize(activity) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/polls/#{object.id}") + +      response = json_response(conn, 200) +      id = to_string(object.id) +      assert %{"id" => ^id, "expired" => false, "multiple" => false} = response +    end + +    test "does not expose polls for private statuses", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Pleroma does", +          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}, +          "visibility" => "private" +        }) + +      object = Object.normalize(activity) + +      conn = +        conn +        |> assign(:user, other_user) +        |> get("/api/v1/polls/#{object.id}") + +      assert json_response(conn, 404) +    end +  end + +  describe "POST /api/v1/polls/:id/votes" do +    test "votes are added to the poll", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "A very delicious sandwich", +          "poll" => %{ +            "options" => ["Lettuce", "Grilled Bacon", "Tomato"], +            "expires_in" => 20, +            "multiple" => true +          } +        }) + +      object = Object.normalize(activity) + +      conn = +        conn +        |> assign(:user, other_user) +        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) + +      assert json_response(conn, 200) +      object = Object.get_by_id(object.id) + +      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} -> +               total_items == 1 +             end) +    end + +    test "author can't vote", %{conn: conn} do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Am I cute?", +          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20} +        }) + +      object = Object.normalize(activity) + +      assert conn +             |> assign(:user, user) +             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]}) +             |> json_response(422) == %{"error" => "Poll's author can't vote"} + +      object = Object.get_by_id(object.id) + +      refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1 +    end + +    test "does not allow multiple choices on a single-choice question", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "The glass is", +          "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20} +        }) + +      object = Object.normalize(activity) + +      assert conn +             |> assign(:user, other_user) +             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]}) +             |> json_response(422) == %{"error" => "Too many choices"} + +      object = Object.get_by_id(object.id) + +      refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} -> +               total_items == 1 +             end) +    end + +    test "does not allow choice index to be greater than options count", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Am I cute?", +          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20} +        }) + +      object = Object.normalize(activity) + +      conn = +        conn +        |> assign(:user, other_user) +        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]}) + +      assert json_response(conn, 422) == %{"error" => "Invalid indices"} +    end + +    test "returns 404 error when object is not exist", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/polls/1/votes", %{"choices" => [0]}) + +      assert json_response(conn, 404) == %{"error" => "Record not found"} +    end + +    test "returns 404 when poll is private and not available for user", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Am I cute?", +          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}, +          "visibility" => "private" +        }) + +      object = Object.normalize(activity) + +      conn = +        conn +        |> assign(:user, other_user) +        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]}) + +      assert json_response(conn, 404) == %{"error" => "Record not found"} +    end +  end +end diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/web/mastodon_api/controllers/search_controller_test.exs index 49c79ff0a..7953fad62 100644 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/web/mastodon_api/controllers/search_controller_test.exs @@ -42,7 +42,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do        user_two = insert(:user, %{nickname: "shp@shitposter.club"})        user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"}) -      {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu private"}) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu private 天子"})        {:ok, _activity} =          CommonAPI.post(user, %{ @@ -52,9 +52,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do        {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"}) -      conn = get(conn, "/api/v2/search", %{"q" => "2hu #private"}) - -      assert results = json_response(conn, 200) +      results = +        get(conn, "/api/v2/search", %{"q" => "2hu #private"}) +        |> json_response(200)        [account | _] = results["accounts"]        assert account["id"] == to_string(user_three.id) @@ -65,6 +65,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do        [status] = results["statuses"]        assert status["id"] == to_string(activity.id) + +      results = +        get(conn, "/api/v2/search", %{"q" => "天子"}) +        |> json_response(200) + +      [status] = results["statuses"] +      assert status["id"] == to_string(activity.id)      end    end @@ -197,17 +204,17 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do        conn =          conn          |> assign(:user, user) -        |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"}) +        |> get("/api/v1/search", %{"q" => "mike@osada.macgirvin.com", "resolve" => "true"})        assert results = json_response(conn, 200)        [account] = results["accounts"] -      assert account["acct"] == "shp@social.heldscal.la" +      assert account["acct"] == "mike@osada.macgirvin.com"      end      test "search doesn't fetch remote accounts if resolve is false", %{conn: conn} do        conn =          conn -        |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "false"}) +        |> get("/api/v1/search", %{"q" => "mike@osada.macgirvin.com", "resolve" => "false"})        assert results = json_response(conn, 200)        assert [] == results["accounts"] diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index b194feae6..2de2725e0 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do    alias Pleroma.Activity    alias Pleroma.ActivityExpiration    alias Pleroma.Config +  alias Pleroma.Conversation.Participation    alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.ScheduledActivity @@ -465,6 +466,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do      assert id == to_string(activity.id)    end +  test "get a direct status", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = +      CommonAPI.post(user, %{"status" => "@#{other_user.nickname}", "visibility" => "direct"}) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/statuses/#{activity.id}") + +    [participation] = Participation.for_user(user) + +    res = json_response(conn, 200) +    assert res["pleroma"]["direct_conversation_id"] == participation.id +  end +    test "get statuses by IDs", %{conn: conn} do      %{id: id1} = insert(:note_activity)      %{id: id2} = insert(:note_activity) @@ -547,6 +566,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do        assert to_string(activity.id) == id      end +    test "reblogs privately and returns the reblogged status", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/reblog", %{"visibility" => "private"}) + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, +               "reblogged" => true, +               "visibility" => "private" +             } = json_response(conn, 200) + +      assert to_string(activity.id) == id +    end +      test "reblogged status for another user", %{conn: conn} do        activity = insert(:note_activity)        user1 = insert(:user) @@ -1149,6 +1186,23 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do        assert Enum.empty?(response)      end +    test "does not return users who have reblogged the status privately", %{ +      conn: %{assigns: %{user: user}} = conn, +      activity: activity +    } do +      other_user = insert(:user) + +      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user, %{"visibility" => "private"}) + +      response = +        conn +        |> assign(:user, user) +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end +      test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do        other_user = insert(:user)        {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) @@ -1207,4 +1261,51 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do               "descendants" => [%{"id" => ^id4}, %{"id" => ^id5}]             } = response    end + +  test "returns the favorites of a user", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"}) +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"}) + +    {:ok, _, _} = CommonAPI.favorite(activity.id, user) + +    first_conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/favourites") + +    assert [status] = json_response(first_conn, 200) +    assert status["id"] == to_string(activity.id) + +    assert [{"link", _link_header}] = +             Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end) + +    # Honours query params +    {:ok, second_activity} = +      CommonAPI.post(other_user, %{ +        "status" => +          "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful." +      }) + +    {:ok, _, _} = CommonAPI.favorite(second_activity.id, user) + +    last_like = status["id"] + +    second_conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/favourites?since_id=#{last_like}") + +    assert [second_status] = json_response(second_conn, 200) +    assert second_status["id"] == to_string(second_activity.id) + +    third_conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/favourites?limit=0") + +    assert [] = json_response(third_conn, 200) +  end  end diff --git a/test/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/web/mastodon_api/controllers/suggestion_controller_test.exs new file mode 100644 index 000000000..78620a873 --- /dev/null +++ b/test/web/mastodon_api/controllers/suggestion_controller_test.exs @@ -0,0 +1,92 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Config + +  import ExUnit.CaptureLog +  import Pleroma.Factory +  import Tesla.Mock + +  setup do +    user = insert(:user) +    other_user = insert(:user) +    host = Config.get([Pleroma.Web.Endpoint, :url, :host]) +    url500 = "http://test500?#{host}&#{user.nickname}" +    url200 = "http://test200?#{host}&#{user.nickname}" + +    mock(fn +      %{method: :get, url: ^url500} -> +        %Tesla.Env{status: 500, body: "bad request"} + +      %{method: :get, url: ^url200} -> +        %Tesla.Env{ +          status: 200, +          body: +            ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{ +              other_user.ap_id +            }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}]) +        } +    end) + +    [user: user, other_user: other_user] +  end + +  clear_config(:suggestions) + +  test "returns empty result when suggestions disabled", %{conn: conn, user: user} do +    Config.put([:suggestions, :enabled], false) + +    res = +      conn +      |> assign(:user, user) +      |> get("/api/v1/suggestions") +      |> json_response(200) + +    assert res == [] +  end + +  test "returns error", %{conn: conn, user: user} do +    Config.put([:suggestions, :enabled], true) +    Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") + +    assert capture_log(fn -> +             res = +               conn +               |> assign(:user, user) +               |> get("/api/v1/suggestions") +               |> json_response(500) + +             assert res == "Something went wrong" +           end) =~ "Could not retrieve suggestions" +  end + +  test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do +    Config.put([:suggestions, :enabled], true) +    Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}") + +    res = +      conn +      |> assign(:user, user) +      |> get("/api/v1/suggestions") +      |> json_response(200) + +    assert res == [ +             %{ +               "acct" => "yj455", +               "avatar" => "https://social.heldscal.la/avatar/201.jpeg", +               "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg", +               "id" => 0 +             }, +             %{ +               "acct" => other_user.ap_id, +               "avatar" => "https://social.heldscal.la/avatar/202.jpeg", +               "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg", +               "id" => other_user.id +             } +           ] +  end +end diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs index d3652d964..61b6cea75 100644 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -11,7 +11,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do    alias Pleroma.Config    alias Pleroma.User    alias Pleroma.Web.CommonAPI -  alias Pleroma.Web.OStatus    clear_config([:instance, :public]) @@ -20,27 +19,52 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do      :ok    end -  test "the home timeline", %{conn: conn} do -    user = insert(:user) -    following = insert(:user) +  describe "home" do +    test "the home timeline", %{conn: conn} do +      user = insert(:user) +      following = insert(:user) + +      {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/timelines/home") + +      assert Enum.empty?(json_response(conn, :ok)) + +      {:ok, user} = User.follow(user, following) + +      conn = +        build_conn() +        |> assign(:user, user) +        |> get("/api/v1/timelines/home") -    {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) +      assert [%{"content" => "test"}] = json_response(conn, :ok) +    end -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/timelines/home") +    test "the home timeline when the direct messages are excluded", %{conn: conn} do +      user = insert(:user) +      {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) +      {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) -    assert Enum.empty?(json_response(conn, :ok)) +      {:ok, unlisted_activity} = +        CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"}) -    {:ok, user} = User.follow(user, following) +      {:ok, private_activity} = +        CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) -    conn = -      build_conn() -      |> assign(:user, user) -      |> get("/api/v1/timelines/home") +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/timelines/home", %{"exclude_visibilities" => ["direct"]}) -    assert [%{"content" => "test"}] = json_response(conn, :ok) +      assert status_ids = json_response(conn, :ok) |> Enum.map(& &1["id"]) +      assert public_activity.id in status_ids +      assert unlisted_activity.id in status_ids +      assert private_activity.id in status_ids +      refute direct_activity.id in status_ids +    end    end    describe "public" do @@ -50,8 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do        {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) -      {:ok, [_activity]} = -        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") +      _activity = insert(:note_activity, local: false)        conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"}) @@ -246,9 +269,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do        {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"}) -      {:ok, [_activity]} = -        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") -        nconn = get(conn, "/api/v1/timelines/tag/2hu")        assert [%{"id" => id}] = json_response(nconn, :ok) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f2f8c0578..42a8779c0 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -5,21 +5,11 @@  defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    use Pleroma.Web.ConnCase -  alias Ecto.Changeset -  alias Pleroma.Config    alias Pleroma.Notification -  alias Pleroma.Object    alias Pleroma.Repo -  alias Pleroma.Tests.ObanHelpers -  alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI -  alias Pleroma.Web.OAuth.App -  alias Pleroma.Web.Push -  import ExUnit.CaptureLog    import Pleroma.Factory -  import Swoosh.TestAssertions    import Tesla.Mock    setup do @@ -27,191 +17,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      :ok    end -  clear_config([:instance, :public])    clear_config([:rich_media, :enabled]) -  test "apps/verify_credentials", %{conn: conn} do -    token = insert(:oauth_token) - -    conn = -      conn -      |> assign(:user, token.user) -      |> assign(:token, token) -      |> get("/api/v1/apps/verify_credentials") - -    app = Repo.preload(token, :app).app - -    expected = %{ -      "name" => app.client_name, -      "website" => app.website, -      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) -    } - -    assert expected == json_response(conn, 200) -  end - -  test "creates an oauth app", %{conn: conn} do -    user = insert(:user) -    app_attrs = build(:oauth_app) - -    conn = -      conn -      |> assign(:user, user) -      |> post("/api/v1/apps", %{ -        client_name: app_attrs.client_name, -        redirect_uris: app_attrs.redirect_uris -      }) - -    [app] = Repo.all(App) - -    expected = %{ -      "name" => app.client_name, -      "website" => app.website, -      "client_id" => app.client_id, -      "client_secret" => app.client_secret, -      "id" => app.id |> to_string(), -      "redirect_uri" => app.redirect_uris, -      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) -    } - -    assert expected == json_response(conn, 200) -  end - -  describe "media upload" do -    setup do -      user = insert(:user) - -      conn = -        build_conn() -        |> assign(:user, user) - -      image = %Plug.Upload{ -        content_type: "image/jpg", -        path: Path.absname("test/fixtures/image.jpg"), -        filename: "an_image.jpg" -      } - -      [conn: conn, image: image] -    end - -    clear_config([:media_proxy]) -    clear_config([Pleroma.Upload]) - -    test "returns uploaded image", %{conn: conn, image: image} do -      desc = "Description of the image" - -      media = -        conn -        |> post("/api/v1/media", %{"file" => image, "description" => desc}) -        |> json_response(:ok) - -      assert media["type"] == "image" -      assert media["description"] == desc -      assert media["id"] - -      object = Repo.get(Object, media["id"]) -      assert object.data["actor"] == User.ap_id(conn.assigns[:user]) -    end -  end - -  describe "/api/v1/pleroma/mascot" do -    test "mascot upload", %{conn: conn} do -      user = insert(:user) - -      non_image_file = %Plug.Upload{ -        content_type: "audio/mpeg", -        path: Path.absname("test/fixtures/sound.mp3"), -        filename: "sound.mp3" -      } - -      conn = -        conn -        |> assign(:user, user) -        |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) - -      assert json_response(conn, 415) - -      file = %Plug.Upload{ -        content_type: "image/jpg", -        path: Path.absname("test/fixtures/image.jpg"), -        filename: "an_image.jpg" -      } - -      conn = -        build_conn() -        |> assign(:user, user) -        |> put("/api/v1/pleroma/mascot", %{"file" => file}) - -      assert %{"id" => _, "type" => image} = json_response(conn, 200) -    end - -    test "mascot retrieving", %{conn: conn} do -      user = insert(:user) -      # When user hasn't set a mascot, we should just get pleroma tan back -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/pleroma/mascot") - -      assert %{"url" => url} = json_response(conn, 200) -      assert url =~ "pleroma-fox-tan-smol" - -      # When a user sets their mascot, we should get that back -      file = %Plug.Upload{ -        content_type: "image/jpg", -        path: Path.absname("test/fixtures/image.jpg"), -        filename: "an_image.jpg" -      } - -      conn = -        build_conn() -        |> assign(:user, user) -        |> put("/api/v1/pleroma/mascot", %{"file" => file}) - -      assert json_response(conn, 200) - -      user = User.get_cached_by_id(user.id) - -      conn = -        build_conn() -        |> assign(:user, user) -        |> get("/api/v1/pleroma/mascot") - -      assert %{"url" => url, "type" => "image"} = json_response(conn, 200) -      assert url =~ "an_image" -    end -  end - -  test "getting a list of mutes", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, user} = User.mute(user, other_user) - -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/mutes") - -    other_user_id = to_string(other_user.id) -    assert [%{"id" => ^other_user_id}] = json_response(conn, 200) -  end - -  test "getting a list of blocks", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, user} = User.block(user, other_user) - -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/blocks") - -    other_user_id = to_string(other_user.id) -    assert [%{"id" => ^other_user_id}] = json_response(conn, 200) -  end -    test "unimplemented follow_requests, blocks, domain blocks" do      user = insert(:user) @@ -226,137 +33,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end)    end -  test "returns the favorites of a user", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"}) -    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"}) - -    {:ok, _, _} = CommonAPI.favorite(activity.id, user) - -    first_conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/favourites") - -    assert [status] = json_response(first_conn, 200) -    assert status["id"] == to_string(activity.id) - -    assert [{"link", _link_header}] = -             Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end) - -    # Honours query params -    {:ok, second_activity} = -      CommonAPI.post(other_user, %{ -        "status" => -          "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful." -      }) - -    {:ok, _, _} = CommonAPI.favorite(second_activity.id, user) - -    last_like = status["id"] - -    second_conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/favourites?since_id=#{last_like}") - -    assert [second_status] = json_response(second_conn, 200) -    assert second_status["id"] == to_string(second_activity.id) - -    third_conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/favourites?limit=0") - -    assert [] = json_response(third_conn, 200) -  end - -  test "get instance information", %{conn: conn} do -    conn = get(conn, "/api/v1/instance") -    assert result = json_response(conn, 200) - -    email = Config.get([:instance, :email]) -    # Note: not checking for "max_toot_chars" since it's optional -    assert %{ -             "uri" => _, -             "title" => _, -             "description" => _, -             "version" => _, -             "email" => from_config_email, -             "urls" => %{ -               "streaming_api" => _ -             }, -             "stats" => _, -             "thumbnail" => _, -             "languages" => _, -             "registrations" => _, -             "poll_limits" => _ -           } = result - -    assert email == from_config_email -  end - -  test "get instance stats", %{conn: conn} do -    user = insert(:user, %{local: true}) - -    user2 = insert(:user, %{local: true}) -    {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated) - -    insert(:user, %{local: false, nickname: "u@peer1.com"}) -    insert(:user, %{local: false, nickname: "u@peer2.com"}) - -    {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"}) - -    # Stats should count users with missing or nil `info.deactivated` value - -    {:ok, _user} = -      user.id -      |> User.get_cached_by_id() -      |> User.update_info(&Changeset.change(&1, %{deactivated: nil})) - -    Pleroma.Stats.force_update() - -    conn = get(conn, "/api/v1/instance") - -    assert result = json_response(conn, 200) - -    stats = result["stats"] - -    assert stats -    assert stats["user_count"] == 1 -    assert stats["status_count"] == 1 -    assert stats["domain_count"] == 2 -  end - -  test "get peers", %{conn: conn} do -    insert(:user, %{local: false, nickname: "u@peer1.com"}) -    insert(:user, %{local: false, nickname: "u@peer2.com"}) - -    Pleroma.Stats.force_update() - -    conn = get(conn, "/api/v1/instance/peers") - -    assert result = json_response(conn, 200) - -    assert ["peer1.com", "peer2.com"] == Enum.sort(result) -  end - -  test "put settings", %{conn: conn} do -    user = insert(:user) - -    conn = -      conn -      |> assign(:user, user) -      |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}}) - -    assert _result = json_response(conn, 200) - -    user = User.get_cached_by_ap_id(user.ap_id) -    assert user.info.settings == %{"programming" => "socks"} -  end -    describe "link headers" do      test "preserves parameters in link headers", %{conn: conn} do        user = insert(:user) @@ -389,463 +65,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end    end -  describe "custom emoji" do -    test "with tags", %{conn: conn} do -      [emoji | _body] = -        conn -        |> get("/api/v1/custom_emojis") -        |> json_response(200) - -      assert Map.has_key?(emoji, "shortcode") -      assert Map.has_key?(emoji, "static_url") -      assert Map.has_key?(emoji, "tags") -      assert is_list(emoji["tags"]) -      assert Map.has_key?(emoji, "category") -      assert Map.has_key?(emoji, "url") -      assert Map.has_key?(emoji, "visible_in_picker") -    end -  end - -  describe "index/2 redirections" do -    setup %{conn: conn} do -      session_opts = [ -        store: :cookie, -        key: "_test", -        signing_salt: "cooldude" -      ] - -      conn = -        conn -        |> Plug.Session.call(Plug.Session.init(session_opts)) -        |> fetch_session() - -      test_path = "/web/statuses/test" -      %{conn: conn, path: test_path} -    end - -    test "redirects not logged-in users to the login page", %{conn: conn, path: path} do -      conn = get(conn, path) - -      assert conn.status == 302 -      assert redirected_to(conn) == "/web/login" -    end - -    test "redirects not logged-in users to the login page on private instances", %{ -      conn: conn, -      path: path -    } do -      Config.put([:instance, :public], false) - -      conn = get(conn, path) - -      assert conn.status == 302 -      assert redirected_to(conn) == "/web/login" -    end - -    test "does not redirect logged in users to the login page", %{conn: conn, path: path} do -      token = insert(:oauth_token) - -      conn = -        conn -        |> assign(:user, token.user) -        |> put_session(:oauth_token, token.token) -        |> get(path) - -      assert conn.status == 200 -    end - -    test "saves referer path to session", %{conn: conn, path: path} do -      conn = get(conn, path) -      return_to = Plug.Conn.get_session(conn, :return_to) - -      assert return_to == path -    end - -    test "redirects to the saved path after log in", %{conn: conn, path: path} do -      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") -      auth = insert(:oauth_authorization, app: app) - -      conn = -        conn -        |> put_session(:return_to, path) -        |> get("/web/login", %{code: auth.token}) - -      assert conn.status == 302 -      assert redirected_to(conn) == path -    end - -    test "redirects to the getting-started page when referer is not present", %{conn: conn} do -      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") -      auth = insert(:oauth_authorization, app: app) - -      conn = get(conn, "/web/login", %{code: auth.token}) - -      assert conn.status == 302 -      assert redirected_to(conn) == "/web/getting-started" -    end -  end - -  describe "GET /api/v1/polls/:id" do -    test "returns poll entity for object id", %{conn: conn} do -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Pleroma does", -          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20} -        }) - -      object = Object.normalize(activity) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/polls/#{object.id}") - -      response = json_response(conn, 200) -      id = to_string(object.id) -      assert %{"id" => ^id, "expired" => false, "multiple" => false} = response -    end - -    test "does not expose polls for private statuses", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Pleroma does", -          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}, -          "visibility" => "private" -        }) - -      object = Object.normalize(activity) - -      conn = -        conn -        |> assign(:user, other_user) -        |> get("/api/v1/polls/#{object.id}") - -      assert json_response(conn, 404) -    end -  end - -  describe "POST /api/v1/polls/:id/votes" do -    test "votes are added to the poll", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "A very delicious sandwich", -          "poll" => %{ -            "options" => ["Lettuce", "Grilled Bacon", "Tomato"], -            "expires_in" => 20, -            "multiple" => true -          } -        }) - -      object = Object.normalize(activity) - -      conn = -        conn -        |> assign(:user, other_user) -        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) - -      assert json_response(conn, 200) -      object = Object.get_by_id(object.id) - -      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} -> -               total_items == 1 -             end) -    end - -    test "author can't vote", %{conn: conn} do -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Am I cute?", -          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20} -        }) - -      object = Object.normalize(activity) - -      assert conn -             |> assign(:user, user) -             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]}) -             |> json_response(422) == %{"error" => "Poll's author can't vote"} - -      object = Object.get_by_id(object.id) - -      refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1 -    end - -    test "does not allow multiple choices on a single-choice question", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "The glass is", -          "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20} -        }) - -      object = Object.normalize(activity) - -      assert conn -             |> assign(:user, other_user) -             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]}) -             |> json_response(422) == %{"error" => "Too many choices"} - -      object = Object.get_by_id(object.id) - -      refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} -> -               total_items == 1 -             end) -    end - -    test "does not allow choice index to be greater than options count", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Am I cute?", -          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20} -        }) - -      object = Object.normalize(activity) - -      conn = -        conn -        |> assign(:user, other_user) -        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]}) - -      assert json_response(conn, 422) == %{"error" => "Invalid indices"} -    end - -    test "returns 404 error when object is not exist", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/polls/1/votes", %{"choices" => [0]}) - -      assert json_response(conn, 404) == %{"error" => "Record not found"} -    end - -    test "returns 404 when poll is private and not available for user", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Am I cute?", -          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}, -          "visibility" => "private" -        }) - -      object = Object.normalize(activity) - -      conn = -        conn -        |> assign(:user, other_user) -        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]}) - -      assert json_response(conn, 404) == %{"error" => "Record not found"} -    end -  end - -  describe "POST /auth/password, with valid parameters" do -    setup %{conn: conn} do -      user = insert(:user) -      conn = post(conn, "/auth/password?email=#{user.email}") -      %{conn: conn, user: user} -    end - -    test "it returns 204", %{conn: conn} do -      assert json_response(conn, :no_content) -    end - -    test "it creates a PasswordResetToken record for user", %{user: user} do -      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) -      assert token_record -    end - -    test "it sends an email to user", %{user: user} do -      ObanHelpers.perform_all() -      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - -      email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) -      notify_email = Config.get([:instance, :notify_email]) -      instance_name = Config.get([:instance, :name]) - -      assert_email_sent( -        from: {instance_name, notify_email}, -        to: {user.name, user.email}, -        html_body: email.html_body -      ) -    end -  end - -  describe "POST /auth/password, with invalid parameters" do -    setup do -      user = insert(:user) -      {:ok, user: user} -    end - -    test "it returns 404 when user is not found", %{conn: conn, user: user} do -      conn = post(conn, "/auth/password?email=nonexisting_#{user.email}") -      assert conn.status == 404 -      assert conn.resp_body == "" -    end - -    test "it returns 400 when user is not local", %{conn: conn, user: user} do -      {:ok, user} = Repo.update(Changeset.change(user, local: false)) -      conn = post(conn, "/auth/password?email=#{user.email}") -      assert conn.status == 400 -      assert conn.resp_body == "" -    end -  end - -  describe "GET /api/v1/suggestions" do -    setup do -      user = insert(:user) -      other_user = insert(:user) -      host = Config.get([Pleroma.Web.Endpoint, :url, :host]) -      url500 = "http://test500?#{host}&#{user.nickname}" -      url200 = "http://test200?#{host}&#{user.nickname}" - -      mock(fn -        %{method: :get, url: ^url500} -> -          %Tesla.Env{status: 500, body: "bad request"} - -        %{method: :get, url: ^url200} -> -          %Tesla.Env{ -            status: 200, -            body: -              ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{ -                other_user.ap_id -              }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}]) -          } -      end) - -      [user: user, other_user: other_user] -    end - -    clear_config(:suggestions) - -    test "returns empty result when suggestions disabled", %{conn: conn, user: user} do -      Config.put([:suggestions, :enabled], false) - -      res = -        conn -        |> assign(:user, user) -        |> get("/api/v1/suggestions") -        |> json_response(200) - -      assert res == [] -    end - -    test "returns error", %{conn: conn, user: user} do -      Config.put([:suggestions, :enabled], true) -      Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") - -      assert capture_log(fn -> -               res = -                 conn -                 |> assign(:user, user) -                 |> get("/api/v1/suggestions") -                 |> json_response(500) - -               assert res == "Something went wrong" -             end) =~ "Could not retrieve suggestions" -    end - -    test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do -      Config.put([:suggestions, :enabled], true) -      Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}") - -      res = -        conn -        |> assign(:user, user) -        |> get("/api/v1/suggestions") -        |> json_response(200) - -      assert res == [ -               %{ -                 "acct" => "yj455", -                 "avatar" => "https://social.heldscal.la/avatar/201.jpeg", -                 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg", -                 "id" => 0 -               }, -               %{ -                 "acct" => other_user.ap_id, -                 "avatar" => "https://social.heldscal.la/avatar/202.jpeg", -                 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg", -                 "id" => other_user.id -               } -             ] -    end -  end - -  describe "PUT /api/v1/media/:id" do -    setup do -      actor = insert(:user) - -      file = %Plug.Upload{ -        content_type: "image/jpg", -        path: Path.absname("test/fixtures/image.jpg"), -        filename: "an_image.jpg" -      } - -      {:ok, %Object{} = object} = -        ActivityPub.upload( -          file, -          actor: User.ap_id(actor), -          description: "test-m" -        ) - -      [actor: actor, object: object] -    end - -    test "updates name of media", %{conn: conn, actor: actor, object: object} do -      media = -        conn -        |> assign(:user, actor) -        |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"}) -        |> json_response(:ok) - -      assert media["description"] == "test-media" -      assert refresh_record(object).data["name"] == "test-media" -    end - -    test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do -      media = -        conn -        |> assign(:user, actor) -        |> put("/api/v1/media/#{object.id}", %{}) -        |> json_response(400) - -      assert media == %{"error" => "bad_request"} -    end -  end - -  describe "DELETE /auth/sign_out" do -    test "redirect to root page", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> delete("/auth/sign_out") - -      assert conn.status == 302 -      assert redirected_to(conn) == "/" -    end -  end -    describe "empty_array, stubs for mastodon api" do      test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do        user = insert(:user) diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 62b2ab7e3..ad209b4a3 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -418,6 +418,27 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do                 following_count: 1               } = AccountView.render("show.json", %{user: user, for: user})      end + +    test "shows unread_conversation_count only to the account owner" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, _activity} = +        CommonAPI.post(other_user, %{ +          "status" => "Hey @#{user.nickname}.", +          "visibility" => "direct" +        }) + +      user = User.get_cached_by_ap_id(user.ap_id) + +      assert AccountView.render("show.json", %{user: user, for: other_user})[:pleroma][ +               :unread_conversation_count +             ] == nil + +      assert AccountView.render("show.json", %{user: user, for: user})[:pleroma][ +               :unread_conversation_count +             ] == 1 +    end    end    describe "follow requests counter" do diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index 81ab82e2b..c9043a69a 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -100,5 +100,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do        NotificationView.render("index.json", %{notifications: [notification], for: followed})      assert [expected] == result + +    User.perform(:delete, follower) +    notification = Notification |> Repo.one() |> Repo.preload(:activity) + +    assert [] == +             NotificationView.render("index.json", %{notifications: [notification], for: followed})    end  end diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/web/mastodon_api/views/poll_view_test.exs new file mode 100644 index 000000000..8cd7636a5 --- /dev/null +++ b/test/web/mastodon_api/views/poll_view_test.exs @@ -0,0 +1,126 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.PollViewTest do +  use Pleroma.DataCase + +  alias Pleroma.Object +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.MastodonAPI.PollView + +  import Pleroma.Factory +  import Tesla.Mock + +  setup do +    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end + +  test "renders a poll" do +    user = insert(:user) + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => "Is Tenshi eating a corndog cute?", +        "poll" => %{ +          "options" => ["absolutely!", "sure", "yes", "why are you even asking?"], +          "expires_in" => 20 +        } +      }) + +    object = Object.normalize(activity) + +    expected = %{ +      emojis: [], +      expired: false, +      id: to_string(object.id), +      multiple: false, +      options: [ +        %{title: "absolutely!", votes_count: 0}, +        %{title: "sure", votes_count: 0}, +        %{title: "yes", votes_count: 0}, +        %{title: "why are you even asking?", votes_count: 0} +      ], +      voted: false, +      votes_count: 0 +    } + +    result = PollView.render("show.json", %{object: object}) +    expires_at = result.expires_at +    result = Map.delete(result, :expires_at) + +    assert result == expected + +    expires_at = NaiveDateTime.from_iso8601!(expires_at) +    assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20 +  end + +  test "detects if it is multiple choice" do +    user = insert(:user) + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => "Which Mastodon developer is your favourite?", +        "poll" => %{ +          "options" => ["Gargron", "Eugen"], +          "expires_in" => 20, +          "multiple" => true +        } +      }) + +    object = Object.normalize(activity) + +    assert %{multiple: true} = PollView.render("show.json", %{object: object}) +  end + +  test "detects emoji" do +    user = insert(:user) + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => "What's with the smug face?", +        "poll" => %{ +          "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"], +          "expires_in" => 20 +        } +      }) + +    object = Object.normalize(activity) + +    assert %{emojis: [%{shortcode: "blank"}]} = PollView.render("show.json", %{object: object}) +  end + +  test "detects vote status" do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => "Which input devices do you use?", +        "poll" => %{ +          "options" => ["mouse", "trackball", "trackpoint"], +          "multiple" => true, +          "expires_in" => 20 +        } +      }) + +    object = Object.normalize(activity) + +    {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2]) + +    result = PollView.render("show.json", %{object: object, for: other_user}) + +    assert result[:voted] == true +    assert Enum.at(result[:options], 1)[:votes_count] == 1 +    assert Enum.at(result[:options], 2)[:votes_count] == 1 +  end + +  test "does not crash on polls with no end date" do +    object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i") +    result = PollView.render("show.json", %{object: object}) + +    assert result[:expires_at] == nil +    assert result[:expired] == false +  end +end diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 8df23d0a8..c200ad8fe 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -14,7 +14,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do    alias Pleroma.Web.CommonAPI.Utils    alias Pleroma.Web.MastodonAPI.AccountView    alias Pleroma.Web.MastodonAPI.StatusView -  alias Pleroma.Web.OStatus    import Pleroma.Factory    import Tesla.Mock @@ -230,17 +229,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do    end    test "contains mentions" do -    incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml") -    # a user with this ap id might be in the cache. -    recipient = "https://pleroma.soykaf.com/users/lain" -    user = insert(:user, %{ap_id: recipient}) +    user = insert(:user) +    mentioned = insert(:user) -    {:ok, [activity]} = OStatus.handle_incoming(incoming) +    {:ok, activity} = CommonAPI.post(user, %{"status" => "hi @#{mentioned.nickname}"})      status = StatusView.render("show.json", %{activity: activity})      assert status.mentions == -             Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end) +             Enum.map([mentioned], fn u -> AccountView.render("mention.json", %{user: u}) end)    end    test "create mentions from the 'to' field" do @@ -451,116 +448,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      end    end -  describe "poll view" do -    test "renders a poll" do -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Is Tenshi eating a corndog cute?", -          "poll" => %{ -            "options" => ["absolutely!", "sure", "yes", "why are you even asking?"], -            "expires_in" => 20 -          } -        }) - -      object = Object.normalize(activity) - -      expected = %{ -        emojis: [], -        expired: false, -        id: to_string(object.id), -        multiple: false, -        options: [ -          %{title: "absolutely!", votes_count: 0}, -          %{title: "sure", votes_count: 0}, -          %{title: "yes", votes_count: 0}, -          %{title: "why are you even asking?", votes_count: 0} -        ], -        voted: false, -        votes_count: 0 -      } - -      result = StatusView.render("poll.json", %{object: object}) -      expires_at = result.expires_at -      result = Map.delete(result, :expires_at) - -      assert result == expected - -      expires_at = NaiveDateTime.from_iso8601!(expires_at) -      assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20 -    end - -    test "detects if it is multiple choice" do -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Which Mastodon developer is your favourite?", -          "poll" => %{ -            "options" => ["Gargron", "Eugen"], -            "expires_in" => 20, -            "multiple" => true -          } -        }) - -      object = Object.normalize(activity) - -      assert %{multiple: true} = StatusView.render("poll.json", %{object: object}) -    end - -    test "detects emoji" do -      user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "What's with the smug face?", -          "poll" => %{ -            "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"], -            "expires_in" => 20 -          } -        }) - -      object = Object.normalize(activity) - -      assert %{emojis: [%{shortcode: "blank"}]} = -               StatusView.render("poll.json", %{object: object}) -    end - -    test "detects vote status" do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = -        CommonAPI.post(user, %{ -          "status" => "Which input devices do you use?", -          "poll" => %{ -            "options" => ["mouse", "trackball", "trackpoint"], -            "multiple" => true, -            "expires_in" => 20 -          } -        }) - -      object = Object.normalize(activity) - -      {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2]) - -      result = StatusView.render("poll.json", %{object: object, for: other_user}) - -      assert result[:voted] == true -      assert Enum.at(result[:options], 1)[:votes_count] == 1 -      assert Enum.at(result[:options], 2)[:votes_count] == 1 -    end - -    test "does not crash on polls with no end date" do -      object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i") -      result = StatusView.render("poll.json", %{object: object}) - -      assert result[:expires_at] == nil -      assert result[:expired] == false -    end -  end -    test "embeds a relationship in the account" do      user = insert(:user)      other_user = insert(:user) diff --git a/test/web/metadata/feed_test.exs b/test/web/metadata/feed_test.exs new file mode 100644 index 000000000..50e9ce52e --- /dev/null +++ b/test/web/metadata/feed_test.exs @@ -0,0 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Metadata.Providers.FeedTest do +  use Pleroma.DataCase +  import Pleroma.Factory +  alias Pleroma.Web.Metadata.Providers.Feed + +  test "it renders a link to user's atom feed" do +    user = insert(:user, nickname: "lain") + +    assert Feed.build_tags(%{user: user}) == [ +             {:link, +              [rel: "alternate", type: "application/atom+xml", href: "/users/lain/feed.atom"], []} +           ] +  end +end diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 0cf755806..41aaf6189 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -557,7 +557,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do              "password" => "test",              "client_id" => app.client_id,              "redirect_uri" => redirect_uri, -            "scope" => "read write", +            "scope" => "read:subscope write",              "state" => "statepassed"            }          }) @@ -570,7 +570,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        assert %{"state" => "statepassed", "code" => code} = query        auth = Repo.get_by(Authorization, token: code)        assert auth -      assert auth.scopes == ["read", "write"] +      assert auth.scopes == ["read:subscope", "write"]      end      test "returns 401 for wrong credentials", %{conn: conn} do @@ -627,7 +627,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        assert result =~ "This action is outside the authorized scopes"      end -    test "returns 401 for scopes beyond app scopes", %{conn: conn} do +    test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do        user = insert(:user)        app = insert(:oauth_app, scopes: ["read", "write"])        redirect_uri = OAuthController.default_redirect_uri(app) @@ -852,6 +852,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        assert resp = json_response(conn, 403)        assert resp["error"] == "Password reset is required" +      assert resp["identifier"] == "password_reset_required"        refute Map.has_key?(resp, "access_token")      end diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs deleted file mode 100644 index a8d500890..000000000 --- a/test/web/ostatus/activity_representer_test.exs +++ /dev/null @@ -1,300 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do -  use Pleroma.DataCase - -  alias Pleroma.Activity -  alias Pleroma.Object -  alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub -  alias Pleroma.Web.OStatus -  alias Pleroma.Web.OStatus.ActivityRepresenter - -  import Pleroma.Factory -  import Tesla.Mock - -  setup do -    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) -    :ok -  end - -  test "an external note activity" do -    incoming = File.read!("test/fixtures/mastodon-note-cw.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) - -    user = User.get_cached_by_ap_id(activity.data["actor"]) - -    tuple = ActivityRepresenter.to_simple_form(activity, user) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    assert String.contains?( -             res, -             ~s{<link type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748" rel="alternate"/>} -           ) -  end - -  test "a note activity" do -    note_activity = insert(:note_activity) -    object_data = Object.normalize(note_activity).data - -    user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> -    <id>#{object_data["id"]}</id> -    <title>New note by #{user.nickname}</title> -    <content type="html">#{object_data["content"]}</content> -    <published>#{object_data["published"]}</published> -    <updated>#{object_data["published"]}</updated> -    <ostatus:conversation ref="#{note_activity.data["context"]}">#{note_activity.data["context"]}</ostatus:conversation> -    <link ref="#{note_activity.data["context"]}" rel="ostatus:conversation" /> -    <summary>#{object_data["summary"]}</summary> -    <link type="application/atom+xml" href="#{object_data["id"]}" rel="self" /> -    <link type="text/html" href="#{object_data["id"]}" rel="alternate" /> -    <category term="2hu"/> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> -    <link name="2hu" rel="emoji" href="corndog.png" /> -    """ - -    tuple = ActivityRepresenter.to_simple_form(note_activity, user) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    assert clean(res) == clean(expected) -  end - -  test "a reply note" do -    user = insert(:user) -    note_object = insert(:note) -    _note = insert(:note_activity, %{note: note_object}) -    object = insert(:note, %{data: %{"inReplyTo" => note_object.data["id"]}}) -    answer = insert(:note_activity, %{note: object}) - -    Repo.update!( -      Object.change(note_object, %{data: Map.put(note_object.data, "external_url", "someurl")}) -    ) - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> -    <id>#{object.data["id"]}</id> -    <title>New note by #{user.nickname}</title> -    <content type="html">#{object.data["content"]}</content> -    <published>#{object.data["published"]}</published> -    <updated>#{object.data["published"]}</updated> -    <ostatus:conversation ref="#{answer.data["context"]}">#{answer.data["context"]}</ostatus:conversation> -    <link ref="#{answer.data["context"]}" rel="ostatus:conversation" /> -    <summary>2hu</summary> -    <link type="application/atom+xml" href="#{object.data["id"]}" rel="self" /> -    <link type="text/html" href="#{object.data["id"]}" rel="alternate" /> -    <category term="2hu"/> -    <thr:in-reply-to ref="#{note_object.data["id"]}" href="someurl" /> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> -    <link name="2hu" rel="emoji" href="corndog.png" /> -    """ - -    tuple = ActivityRepresenter.to_simple_form(answer, user) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    assert clean(res) == clean(expected) -  end - -  test "an announce activity" do -    note = insert(:note_activity) -    user = insert(:user) -    object = Object.normalize(note) - -    {:ok, announce, _object} = ActivityPub.announce(user, object) - -    announce = Activity.get_by_id(announce.id) - -    note_user = User.get_cached_by_ap_id(note.data["actor"]) -    note = Activity.get_by_id(note.id) - -    note_xml = -      ActivityRepresenter.to_simple_form(note, note_user, true) -      |> :xmerl.export_simple_content(:xmerl_xml) -      |> to_string - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> -    <id>#{announce.data["id"]}</id> -    <title>#{user.nickname} repeated a notice</title> -    <content type="html">RT #{object.data["content"]}</content> -    <published>#{announce.data["published"]}</published> -    <updated>#{announce.data["published"]}</updated> -    <ostatus:conversation ref="#{announce.data["context"]}">#{announce.data["context"]}</ostatus:conversation> -    <link ref="#{announce.data["context"]}" rel="ostatus:conversation" /> -    <link rel="self" type="application/atom+xml" href="#{announce.data["id"]}"/> -    <activity:object> -      #{note_xml} -    </activity:object> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{ -      note.data["actor"] -    }"/> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> -    """ - -    announce_xml = -      ActivityRepresenter.to_simple_form(announce, user) -      |> :xmerl.export_simple_content(:xmerl_xml) -      |> to_string - -    assert clean(expected) == clean(announce_xml) -  end - -  test "a like activity" do -    note = insert(:note) -    user = insert(:user) -    {:ok, like, _note} = ActivityPub.like(user, note) - -    tuple = ActivityRepresenter.to_simple_form(like, user) -    refute is_nil(tuple) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    expected = """ -    <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> -    <id>#{like.data["id"]}</id> -    <title>New favorite by #{user.nickname}</title> -    <content type="html">#{user.nickname} favorited something</content> -    <published>#{like.data["published"]}</published> -    <updated>#{like.data["published"]}</updated> -    <activity:object> -      <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> -      <id>#{note.data["id"]}</id> -    </activity:object> -    <ostatus:conversation ref="#{like.data["context"]}">#{like.data["context"]}</ostatus:conversation> -    <link ref="#{like.data["context"]}" rel="ostatus:conversation" /> -    <link rel="self" type="application/atom+xml" href="#{like.data["id"]}"/> -    <thr:in-reply-to ref="#{note.data["id"]}" /> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{ -      note.data["actor"] -    }"/> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> -    """ - -    assert clean(res) == clean(expected) -  end - -  test "a follow activity" do -    follower = insert(:user) -    followed = insert(:user) - -    {:ok, activity} = -      ActivityPub.insert(%{ -        "type" => "Follow", -        "actor" => follower.ap_id, -        "object" => followed.ap_id, -        "to" => [followed.ap_id] -      }) - -    tuple = ActivityRepresenter.to_simple_form(activity, follower) - -    refute is_nil(tuple) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> -    <id>#{activity.data["id"]}</id> -    <title>#{follower.nickname} started following #{activity.data["object"]}</title> -    <content type="html"> #{follower.nickname} started following #{activity.data["object"]}</content> -    <published>#{activity.data["published"]}</published> -    <updated>#{activity.data["published"]}</updated> -    <activity:object> -      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> -      <id>#{activity.data["object"]}</id> -      <uri>#{activity.data["object"]}</uri> -    </activity:object> -    <link rel="self" type="application/atom+xml" href="#{activity.data["id"]}"/> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{ -      activity.data["object"] -    }"/> -    """ - -    assert clean(res) == clean(expected) -  end - -  test "an unfollow activity" do -    follower = insert(:user) -    followed = insert(:user) -    {:ok, _activity} = ActivityPub.follow(follower, followed) -    {:ok, activity} = ActivityPub.unfollow(follower, followed) - -    tuple = ActivityRepresenter.to_simple_form(activity, follower) - -    refute is_nil(tuple) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/unfollow</activity:verb> -    <id>#{activity.data["id"]}</id> -    <title>#{follower.nickname} stopped following #{followed.ap_id}</title> -    <content type="html"> #{follower.nickname} stopped following #{followed.ap_id}</content> -    <published>#{activity.data["published"]}</published> -    <updated>#{activity.data["published"]}</updated> -    <activity:object> -      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> -      <id>#{followed.ap_id}</id> -      <uri>#{followed.ap_id}</uri> -    </activity:object> -    <link rel="self" type="application/atom+xml" href="#{activity.data["id"]}"/> -    <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{ -      followed.ap_id -    }"/> -    """ - -    assert clean(res) == clean(expected) -  end - -  test "a delete" do -    user = insert(:user) - -    activity = %Activity{ -      data: %{ -        "id" => "ap_id", -        "type" => "Delete", -        "actor" => user.ap_id, -        "object" => "some_id", -        "published" => "2017-06-18T12:00:18+00:00" -      } -    } - -    tuple = ActivityRepresenter.to_simple_form(activity, nil) - -    refute is_nil(tuple) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary() - -    expected = """ -    <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> -    <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb> -    <id>#{activity.data["object"]}</id> -    <title>An object was deleted</title> -    <content type="html">An object was deleted</content> -    <published>#{activity.data["published"]}</published> -    <updated>#{activity.data["published"]}</updated> -    """ - -    assert clean(res) == clean(expected) -  end - -  test "an unknown activity" do -    tuple = ActivityRepresenter.to_simple_form(%Activity{}, nil) -    assert is_nil(tuple) -  end - -  defp clean(string) do -    String.replace(string, ~r/\s/, "") -  end -end diff --git a/test/web/ostatus/feed_representer_test.exs b/test/web/ostatus/feed_representer_test.exs deleted file mode 100644 index d1cadf1e4..000000000 --- a/test/web/ostatus/feed_representer_test.exs +++ /dev/null @@ -1,59 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatus.FeedRepresenterTest do -  use Pleroma.DataCase -  import Pleroma.Factory -  alias Pleroma.User -  alias Pleroma.Web.OStatus -  alias Pleroma.Web.OStatus.ActivityRepresenter -  alias Pleroma.Web.OStatus.FeedRepresenter -  alias Pleroma.Web.OStatus.UserRepresenter - -  test "returns a feed of the last 20 items of the user" do -    note_activity = insert(:note_activity) -    user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -    tuple = FeedRepresenter.to_simple_form(user, [note_activity], [user]) - -    most_recent_update = -      note_activity.updated_at -      |> NaiveDateTime.to_iso8601() - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> to_string - -    user_xml = -      UserRepresenter.to_simple_form(user) -      |> :xmerl.export_simple_content(:xmerl_xml) - -    entry_xml = -      ActivityRepresenter.to_simple_form(note_activity, user) -      |> :xmerl.export_simple_content(:xmerl_xml) - -    expected = """ -    <feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"> -      <id>#{OStatus.feed_path(user)}</id> -      <title>#{user.nickname}'s timeline</title> -      <updated>#{most_recent_update}</updated> -      <logo>#{User.avatar_url(user)}</logo> -      <link rel="hub" href="#{OStatus.pubsub_path(user)}" /> -      <link rel="salmon" href="#{OStatus.salmon_path(user)}" /> -      <link rel="self" href="#{OStatus.feed_path(user)}" type="application/atom+xml" /> -      <author> -        #{user_xml} -      </author> -      <link rel="next" href="#{OStatus.feed_path(user)}?max_id=#{note_activity.id}" type="application/atom+xml" /> -      <entry> -        #{entry_xml} -      </entry> -    </feed> -    """ - -    assert clean(res) == clean(expected) -  end - -  defp clean(string) do -    String.replace(string, ~r/\s/, "") -  end -end diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs deleted file mode 100644 index cd0447af7..000000000 --- a/test/web/ostatus/incoming_documents/delete_handling_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatus.DeleteHandlingTest do -  use Pleroma.DataCase - -  import Pleroma.Factory -  import Tesla.Mock - -  alias Pleroma.Activity -  alias Pleroma.Object -  alias Pleroma.Web.OStatus - -  setup do -    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) -    :ok -  end - -  describe "deletions" do -    test "it removes the mentioned activity" do -      note = insert(:note_activity) -      second_note = insert(:note_activity) -      object = Object.normalize(note) -      second_object = Object.normalize(second_note) -      user = insert(:user) - -      {:ok, like, _object} = Pleroma.Web.ActivityPub.ActivityPub.like(user, object) - -      incoming = -        File.read!("test/fixtures/delete.xml") -        |> String.replace( -          "tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status", -          object.data["id"] -        ) - -      {:ok, [delete]} = OStatus.handle_incoming(incoming) - -      refute Activity.get_by_id(note.id) -      refute Activity.get_by_id(like.id) -      assert Object.get_by_ap_id(object.data["id"]).data["type"] == "Tombstone" -      assert Activity.get_by_id(second_note.id) -      assert Object.get_by_ap_id(second_object.data["id"]) - -      assert delete.data["type"] == "Delete" -    end -  end -end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index f06023dff..58534396e 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -11,7 +11,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do    alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.CommonAPI -  alias Pleroma.Web.OStatus.ActivityRepresenter    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -22,100 +21,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do      Pleroma.Config.put([:instance, :federating], true)    end -  describe "salmon_incoming" do -    test "decodes a salmon", %{conn: conn} do -      user = insert(:user) -      salmon = File.read!("test/fixtures/salmon.xml") - -      assert capture_log(fn -> -               conn = -                 conn -                 |> put_req_header("content-type", "application/atom+xml") -                 |> post("/users/#{user.nickname}/salmon", salmon) - -               assert response(conn, 200) -             end) =~ "[error]" -    end - -    test "decodes a salmon with a changed magic key", %{conn: conn} do -      user = insert(:user) -      salmon = File.read!("test/fixtures/salmon.xml") - -      assert capture_log(fn -> -               conn = -                 conn -                 |> put_req_header("content-type", "application/atom+xml") -                 |> post("/users/#{user.nickname}/salmon", salmon) - -               assert response(conn, 200) -             end) =~ "[error]" - -      # Wrong key -      info = %{ -        magic_key: -          "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" -      } - -      # Set a wrong magic-key for a user so it has to refetch -      "http://gs.example.org:4040/index.php/user/1" -      |> User.get_cached_by_ap_id() -      |> User.update_info(&User.Info.remote_user_creation(&1, info)) - -      assert capture_log(fn -> -               conn = -                 build_conn() -                 |> put_req_header("content-type", "application/atom+xml") -                 |> post("/users/#{user.nickname}/salmon", salmon) - -               assert response(conn, 200) -             end) =~ "[error]" -    end -  end - -  test "gets a feed", %{conn: conn} do -    note_activity = insert(:note_activity) -    object = Object.normalize(note_activity) -    user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -    conn = -      conn -      |> put_req_header("content-type", "application/atom+xml") -      |> get("/users/#{user.nickname}/feed.atom") - -    assert response(conn, 200) =~ object.data["content"] -  end - -  test "returns 404 for a missing feed", %{conn: conn} do -    conn = -      conn -      |> put_req_header("content-type", "application/atom+xml") -      |> get("/users/nonexisting/feed.atom") - -    assert response(conn, 404) -  end -    describe "GET object/2" do -    test "gets an object", %{conn: conn} do -      note_activity = insert(:note_activity) -      object = Object.normalize(note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) -      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) -      url = "/objects/#{uuid}" - -      conn = -        conn -        |> put_req_header("accept", "application/xml") -        |> get(url) - -      expected = -        ActivityRepresenter.to_simple_form(note_activity, user, true) -        |> ActivityRepresenter.wrap_with_entry() -        |> :xmerl.export_simple(:xmerl_xml) -        |> to_string - -      assert response(conn, 200) == expected -    end -      test "redirects to /notice/id for html format", %{conn: conn} do        note_activity = insert(:note_activity)        object = Object.normalize(note_activity) @@ -165,16 +71,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do    end    describe "GET activity/2" do -    test "gets an activity in xml format", %{conn: conn} do -      note_activity = insert(:note_activity) -      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - -      conn -      |> put_req_header("accept", "application/xml") -      |> get("/activities/#{uuid}") -      |> response(200) -    end -      test "redirects to /notice/id for html format", %{conn: conn} do        note_activity = insert(:note_activity)        [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) @@ -202,24 +98,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        assert response(conn, 500) == ~S({"error":"Something went wrong"})      end -    test "404s on deleted objects", %{conn: conn} do -      note_activity = insert(:note_activity) -      object = Object.normalize(note_activity) -      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - -      conn -      |> put_req_header("accept", "application/xml") -      |> get("/objects/#{uuid}") -      |> response(200) - -      Object.delete(object) - -      conn -      |> put_req_header("accept", "application/xml") -      |> get("/objects/#{uuid}") -      |> response(404) -    end -      test "404s on private activities", %{conn: conn} do        note_activity = insert(:direct_note_activity)        [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) @@ -355,185 +233,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do      end    end -  describe "feed_redirect" do -    test "undefined format. it redirects to feed", %{conn: conn} do -      note_activity = insert(:note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -      response = -        conn -        |> put_req_header("accept", "application/xml") -        |> get("/users/#{user.nickname}") -        |> response(302) - -      assert response == -               "<html><body>You are being <a href=\"#{Pleroma.Web.base_url()}/users/#{ -                 user.nickname -               }/feed.atom\">redirected</a>.</body></html>" -    end - -    test "undefined format. it returns error when user not found", %{conn: conn} do -      response = -        conn -        |> put_req_header("accept", "application/xml") -        |> get("/users/jimm") -        |> response(404) - -      assert response == ~S({"error":"Not found"}) -    end - -    test "activity+json format. it redirects on actual feed of user", %{conn: conn} do -      note_activity = insert(:note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -      response = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}") -        |> json_response(200) - -      assert response["endpoints"] == %{ -               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", -               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", -               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", -               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", -               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" -             } - -      assert response["@context"] == [ -               "https://www.w3.org/ns/activitystreams", -               "http://localhost:4001/schemas/litepub-0.1.jsonld", -               %{"@language" => "und"} -             ] - -      assert Map.take(response, [ -               "followers", -               "following", -               "id", -               "inbox", -               "manuallyApprovesFollowers", -               "name", -               "outbox", -               "preferredUsername", -               "summary", -               "tag", -               "type", -               "url" -             ]) == %{ -               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", -               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", -               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", -               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", -               "manuallyApprovesFollowers" => false, -               "name" => user.name, -               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", -               "preferredUsername" => user.nickname, -               "summary" => user.bio, -               "tag" => [], -               "type" => "Person", -               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" -             } -    end - -    test "activity+json format. it returns error whe use not found", %{conn: conn} do -      response = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/users/jimm") -        |> json_response(404) - -      assert response == "Not found" -    end - -    test "json format. it redirects on actual feed of user", %{conn: conn} do -      note_activity = insert(:note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -      response = -        conn -        |> put_req_header("accept", "application/json") -        |> get("/users/#{user.nickname}") -        |> json_response(200) - -      assert response["endpoints"] == %{ -               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", -               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", -               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", -               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", -               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" -             } - -      assert response["@context"] == [ -               "https://www.w3.org/ns/activitystreams", -               "http://localhost:4001/schemas/litepub-0.1.jsonld", -               %{"@language" => "und"} -             ] - -      assert Map.take(response, [ -               "followers", -               "following", -               "id", -               "inbox", -               "manuallyApprovesFollowers", -               "name", -               "outbox", -               "preferredUsername", -               "summary", -               "tag", -               "type", -               "url" -             ]) == %{ -               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", -               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", -               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", -               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", -               "manuallyApprovesFollowers" => false, -               "name" => user.name, -               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", -               "preferredUsername" => user.nickname, -               "summary" => user.bio, -               "tag" => [], -               "type" => "Person", -               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" -             } -    end - -    test "json format. it returns error whe use not found", %{conn: conn} do -      response = -        conn -        |> put_req_header("accept", "application/json") -        |> get("/users/jimm") -        |> json_response(404) - -      assert response == "Not found" -    end - -    test "html format. it redirects on actual feed of user", %{conn: conn} do -      note_activity = insert(:note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -      response = -        conn -        |> get("/users/#{user.nickname}") -        |> response(200) - -      assert response == -               Fallback.RedirectController.redirector_with_meta( -                 conn, -                 %{user: user} -               ).resp_body -    end - -    test "html format. it returns error when user not found", %{conn: conn} do -      response = -        conn -        |> get("/users/jimm") -        |> json_response(404) - -      assert response == %{"error" => "Not found"} -    end -  end -    describe "GET /notice/:id/embed_player" do      test "render embed player", %{conn: conn} do        note_activity = insert(:note_activity) diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs deleted file mode 100644 index 70a0e4473..000000000 --- a/test/web/ostatus/ostatus_test.exs +++ /dev/null @@ -1,645 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatusTest do -  use Pleroma.DataCase -  alias Pleroma.Activity -  alias Pleroma.Instances -  alias Pleroma.Object -  alias Pleroma.Repo -  alias Pleroma.User -  alias Pleroma.Web.OStatus -  alias Pleroma.Web.XML - -  import ExUnit.CaptureLog -  import Mock -  import Pleroma.Factory - -  setup_all do -    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) -    :ok -  end - -  test "don't insert create notes twice" do -    incoming = File.read!("test/fixtures/incoming_note_activity.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    assert {:ok, [activity]} == OStatus.handle_incoming(incoming) -  end - -  test "handle incoming note - GS, Salmon" do -    incoming = File.read!("test/fixtures/incoming_note_activity.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    user = User.get_cached_by_ap_id(activity.data["actor"]) -    assert user.info.note_count == 1 -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" - -    assert object.data["id"] == "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note" - -    assert activity.data["published"] == "2017-04-23T14:51:03+00:00" -    assert object.data["published"] == "2017-04-23T14:51:03+00:00" - -    assert activity.data["context"] == -             "tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b" - -    assert "http://pleroma.example.org:4000/users/lain3" in activity.data["to"] -    assert object.data["emoji"] == %{"marko" => "marko.png", "reimu" => "reimu.png"} -    assert activity.local == false -  end - -  test "handle incoming notes - GS, subscription" do -    incoming = File.read!("test/fixtures/ostatus_incoming_post.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" -    assert object.data["actor"] == "https://social.heldscal.la/user/23211" -    assert object.data["content"] == "Will it blend?" -    user = User.get_cached_by_ap_id(activity.data["actor"]) -    assert User.ap_followers(user) in activity.data["to"] -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming notes with attachments - GS, subscription" do -    incoming = File.read!("test/fixtures/incoming_websub_gnusocial_attachments.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" -    assert object.data["actor"] == "https://social.heldscal.la/user/23211" -    assert object.data["attachment"] |> length == 2 -    assert object.data["external_url"] == "https://social.heldscal.la/notice/2020923" -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming notes with tags" do -    incoming = File.read!("test/fixtures/ostatus_incoming_post_tag.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert object.data["tag"] == ["nsfw"] -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming notes - Mastodon, salmon, reply" do -    # It uses the context of the replied to object -    Repo.insert!(%Object{ -      data: %{ -        "id" => "https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4", -        "context" => "2hu" -      } -    }) - -    incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" -    assert object.data["actor"] == "https://mastodon.social/users/lambadalambda" -    assert activity.data["context"] == "2hu" -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming notes - Mastodon, with CW" do -    incoming = File.read!("test/fixtures/mastodon-note-cw.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" -    assert object.data["actor"] == "https://mastodon.social/users/lambadalambda" -    assert object.data["summary"] == "technologic" -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming unlisted messages, put public into cc" do -    incoming = File.read!("test/fixtures/mastodon-note-unlisted.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    refute "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["cc"] -    refute "https://www.w3.org/ns/activitystreams#Public" in object.data["to"] -    assert "https://www.w3.org/ns/activitystreams#Public" in object.data["cc"] -  end - -  test "handle incoming retweets - Mastodon, with CW" do -    incoming = File.read!("test/fixtures/cw_retweet.xml") -    {:ok, [[_activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) -    retweeted_object = Object.normalize(retweeted_activity) - -    assert retweeted_object.data["summary"] == "Hey." -  end - -  test "handle incoming notes - GS, subscription, reply" do -    incoming = File.read!("test/fixtures/ostatus_incoming_reply.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" -    assert object.data["actor"] == "https://social.heldscal.la/user/23211" - -    assert object.data["content"] == -             "@<a href=\"https://gs.archae.me/user/4687\" class=\"h-card u-url p-nickname mention\" title=\"shpbot\">shpbot</a> why not indeed." - -    assert object.data["inReplyTo"] == -             "tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note" - -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] -  end - -  test "handle incoming retweets - GS, subscription" do -    incoming = File.read!("test/fixtures/share-gs.xml") -    {:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) - -    assert activity.data["type"] == "Announce" -    assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"] == retweeted_activity.data["object"] -    assert "https://pleroma.soykaf.com/users/lain" in activity.data["to"] -    refute activity.local - -    retweeted_activity = Activity.get_by_id(retweeted_activity.id) -    retweeted_object = Object.normalize(retweeted_activity) -    assert retweeted_activity.data["type"] == "Create" -    assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain" -    refute retweeted_activity.local -    assert retweeted_object.data["announcement_count"] == 1 -    assert String.contains?(retweeted_object.data["content"], "mastodon") -    refute String.contains?(retweeted_object.data["content"], "Test account") -  end - -  test "handle incoming retweets - GS, subscription - local message" do -    incoming = File.read!("test/fixtures/share-gs-local.xml") -    note_activity = insert(:note_activity) -    object = Object.normalize(note_activity) -    user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -    incoming = -      incoming -      |> String.replace("LOCAL_ID", object.data["id"]) -      |> String.replace("LOCAL_USER", user.ap_id) - -    {:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) - -    assert activity.data["type"] == "Announce" -    assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"] == object.data["id"] -    assert user.ap_id in activity.data["to"] -    refute activity.local - -    retweeted_activity = Activity.get_by_id(retweeted_activity.id) -    assert note_activity.id == retweeted_activity.id -    assert retweeted_activity.data["type"] == "Create" -    assert retweeted_activity.data["actor"] == user.ap_id -    assert retweeted_activity.local -    assert Object.normalize(retweeted_activity).data["announcement_count"] == 1 -  end - -  test "handle incoming retweets - Mastodon, salmon" do -    incoming = File.read!("test/fixtures/share.xml") -    {:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) -    retweeted_object = Object.normalize(retweeted_activity) - -    assert activity.data["type"] == "Announce" -    assert activity.data["actor"] == "https://mastodon.social/users/lambadalambda" -    assert activity.data["object"] == retweeted_activity.data["object"] - -    assert activity.data["id"] == -             "tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status" - -    refute activity.local -    assert retweeted_activity.data["type"] == "Create" -    assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain" -    refute retweeted_activity.local -    refute String.contains?(retweeted_object.data["content"], "Test account") -  end - -  test "handle incoming favorites - GS, websub" do -    capture_log(fn -> -      incoming = File.read!("test/fixtures/favorite.xml") -      {:ok, [[activity, favorited_activity]]} = OStatus.handle_incoming(incoming) - -      assert activity.data["type"] == "Like" -      assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -      assert activity.data["object"] == favorited_activity.data["object"] - -      assert activity.data["id"] == -               "tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00" - -      refute activity.local -      assert favorited_activity.data["type"] == "Create" -      assert favorited_activity.data["actor"] == "https://shitposter.club/user/1" - -      assert favorited_activity.data["object"] == -               "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" - -      refute favorited_activity.local -    end) -  end - -  test "handle conversation references" do -    incoming = File.read!("test/fixtures/mastodon_conversation.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) - -    assert activity.data["context"] == -             "tag:mastodon.social,2017-08-28:objectId=7876885:objectType=Conversation" -  end - -  test "handle incoming favorites with locally available object - GS, websub" do -    note_activity = insert(:note_activity) -    object = Object.normalize(note_activity) - -    incoming = -      File.read!("test/fixtures/favorite_with_local_note.xml") -      |> String.replace("localid", object.data["id"]) - -    {:ok, [[activity, favorited_activity]]} = OStatus.handle_incoming(incoming) - -    assert activity.data["type"] == "Like" -    assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"] == object.data["id"] -    refute activity.local -    assert note_activity.id == favorited_activity.id -    assert favorited_activity.local -  end - -  test_with_mock "handle incoming replies, fetching replied-to activities if we don't have them", -                 OStatus, -                 [:passthrough], -                 [] do -    incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    object = Object.normalize(activity, false) - -    assert activity.data["type"] == "Create" -    assert object.data["type"] == "Note" - -    assert object.data["inReplyTo"] == -             "http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc" - -    assert "http://pleroma.example.org:4000/users/lain5" in activity.data["to"] - -    assert object.data["id"] == "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note" - -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] - -    assert called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_)) -  end - -  test_with_mock "handle incoming replies, not fetching replied-to activities beyond max_replies_depth", -                 OStatus, -                 [:passthrough], -                 [] do -    incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml") - -    with_mock Pleroma.Web.Federator, -      allowed_incoming_reply_depth?: fn _ -> false end do -      {:ok, [activity]} = OStatus.handle_incoming(incoming) -      object = Object.normalize(activity, false) - -      refute called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_)) -    end -  end - -  test "handle incoming follows" do -    incoming = File.read!("test/fixtures/follow.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) -    assert activity.data["type"] == "Follow" - -    assert activity.data["id"] == -             "tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00" - -    assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"] == "https://pawoo.net/users/pekorino" -    refute activity.local - -    follower = User.get_cached_by_ap_id(activity.data["actor"]) -    followed = User.get_cached_by_ap_id(activity.data["object"]) - -    assert User.following?(follower, followed) -  end - -  test "refuse following over OStatus if the followed's account is locked" do -    incoming = File.read!("test/fixtures/follow.xml") -    _user = insert(:user, info: %{locked: true}, ap_id: "https://pawoo.net/users/pekorino") - -    {:ok, [{:error, "It's not possible to follow locked accounts over OStatus"}]} = -      OStatus.handle_incoming(incoming) -  end - -  test "handle incoming unfollows with existing follow" do -    incoming_follow = File.read!("test/fixtures/follow.xml") -    {:ok, [_activity]} = OStatus.handle_incoming(incoming_follow) - -    incoming = File.read!("test/fixtures/unfollow.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) - -    assert activity.data["type"] == "Undo" - -    assert activity.data["id"] == -             "undo:tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00" - -    assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    embedded_object = activity.data["object"] -    assert is_map(embedded_object) -    assert embedded_object["type"] == "Follow" -    assert embedded_object["object"] == "https://pawoo.net/users/pekorino" -    refute activity.local - -    follower = User.get_cached_by_ap_id(activity.data["actor"]) -    followed = User.get_cached_by_ap_id(embedded_object["object"]) - -    refute User.following?(follower, followed) -  end - -  test "it clears `unreachable` federation status of the sender" do -    incoming_reaction_xml = File.read!("test/fixtures/share-gs.xml") -    doc = XML.parse_document(incoming_reaction_xml) -    actor_uri = XML.string_from_xpath("//author/uri[1]", doc) -    reacted_to_author_uri = XML.string_from_xpath("//author/uri[2]", doc) - -    Instances.set_consistently_unreachable(actor_uri) -    Instances.set_consistently_unreachable(reacted_to_author_uri) -    refute Instances.reachable?(actor_uri) -    refute Instances.reachable?(reacted_to_author_uri) - -    {:ok, _} = OStatus.handle_incoming(incoming_reaction_xml) -    assert Instances.reachable?(actor_uri) -    refute Instances.reachable?(reacted_to_author_uri) -  end - -  describe "new remote user creation" do -    test "returns local users" do -      local_user = insert(:user) -      {:ok, user} = OStatus.find_or_make_user(local_user.ap_id) - -      assert user == local_user -    end - -    test "tries to use the information in poco fields" do -      uri = "https://social.heldscal.la/user/23211" - -      {:ok, user} = OStatus.find_or_make_user(uri) - -      user = User.get_cached_by_id(user.id) -      assert user.name == "Constance Variable" -      assert user.nickname == "lambadalambda@social.heldscal.la" -      assert user.local == false -      assert user.info.uri == uri -      assert user.ap_id == uri -      assert user.bio == "Call me Deacon Blues." -      assert user.avatar["type"] == "Image" - -      {:ok, user_again} = OStatus.find_or_make_user(uri) - -      assert user == user_again -    end - -    test "find_or_make_user sets all the nessary input fields" do -      uri = "https://social.heldscal.la/user/23211" -      {:ok, user} = OStatus.find_or_make_user(uri) - -      assert user.info == -               %User.Info{ -                 id: user.info.id, -                 ap_enabled: false, -                 background: %{}, -                 banner: %{}, -                 blocks: [], -                 deactivated: false, -                 default_scope: "public", -                 domain_blocks: [], -                 follower_count: 0, -                 is_admin: false, -                 is_moderator: false, -                 keys: nil, -                 locked: false, -                 no_rich_text: false, -                 note_count: 0, -                 settings: nil, -                 source_data: %{}, -                 hub: "https://social.heldscal.la/main/push/hub", -                 magic_key: -                   "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB", -                 salmon: "https://social.heldscal.la/main/salmon/user/23211", -                 topic: "https://social.heldscal.la/api/statuses/user_timeline/23211.atom", -                 uri: "https://social.heldscal.la/user/23211" -               } -    end - -    test "find_make_or_update_actor takes an author element and returns an updated user" do -      uri = "https://social.heldscal.la/user/23211" - -      {:ok, user} = OStatus.find_or_make_user(uri) -      old_name = user.name -      old_bio = user.bio -      change = Ecto.Changeset.change(user, %{avatar: nil, bio: nil, name: nil}) - -      {:ok, user} = Repo.update(change) -      refute user.avatar - -      doc = XML.parse_document(File.read!("test/fixtures/23211.atom")) -      [author] = :xmerl_xpath.string('//author[1]', doc) -      {:ok, user} = OStatus.find_make_or_update_actor(author) -      assert user.avatar["type"] == "Image" -      assert user.name == old_name -      assert user.bio == old_bio - -      {:ok, user_again} = OStatus.find_make_or_update_actor(author) -      assert user_again == user -    end - -    test "find_or_make_user disallows protocol downgrade" do -      user = insert(:user, %{local: true}) -      {:ok, user} = OStatus.find_or_make_user(user.ap_id) - -      assert User.ap_enabled?(user) - -      user = -        insert(:user, %{ -          ap_id: "https://social.heldscal.la/user/23211", -          info: %{ap_enabled: true}, -          local: false -        }) - -      assert User.ap_enabled?(user) - -      {:ok, user} = OStatus.find_or_make_user(user.ap_id) -      assert User.ap_enabled?(user) -    end - -    test "find_make_or_update_actor disallows protocol downgrade" do -      user = insert(:user, %{local: true}) -      {:ok, user} = OStatus.find_or_make_user(user.ap_id) - -      assert User.ap_enabled?(user) - -      user = -        insert(:user, %{ -          ap_id: "https://social.heldscal.la/user/23211", -          info: %{ap_enabled: true}, -          local: false -        }) - -      assert User.ap_enabled?(user) - -      {:ok, user} = OStatus.find_or_make_user(user.ap_id) -      assert User.ap_enabled?(user) - -      doc = XML.parse_document(File.read!("test/fixtures/23211.atom")) -      [author] = :xmerl_xpath.string('//author[1]', doc) -      {:error, :invalid_protocol} = OStatus.find_make_or_update_actor(author) -    end -  end - -  describe "gathering user info from a user id" do -    test "it returns user info in a hash" do -      user = "shp@social.heldscal.la" - -      # TODO: make test local -      {:ok, data} = OStatus.gather_user_info(user) - -      expected = %{ -        "hub" => "https://social.heldscal.la/main/push/hub", -        "magic_key" => -          "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB", -        "name" => "shp", -        "nickname" => "shp", -        "salmon" => "https://social.heldscal.la/main/salmon/user/29191", -        "subject" => "acct:shp@social.heldscal.la", -        "topic" => "https://social.heldscal.la/api/statuses/user_timeline/29191.atom", -        "uri" => "https://social.heldscal.la/user/29191", -        "host" => "social.heldscal.la", -        "fqn" => user, -        "bio" => "cofe", -        "avatar" => %{ -          "type" => "Image", -          "url" => [ -            %{ -              "href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", -              "mediaType" => "image/jpeg", -              "type" => "Link" -            } -          ] -        }, -        "subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}", -        "ap_id" => nil -      } - -      assert data == expected -    end - -    test "it works with the uri" do -      user = "https://social.heldscal.la/user/29191" - -      # TODO: make test local -      {:ok, data} = OStatus.gather_user_info(user) - -      expected = %{ -        "hub" => "https://social.heldscal.la/main/push/hub", -        "magic_key" => -          "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB", -        "name" => "shp", -        "nickname" => "shp", -        "salmon" => "https://social.heldscal.la/main/salmon/user/29191", -        "subject" => "https://social.heldscal.la/user/29191", -        "topic" => "https://social.heldscal.la/api/statuses/user_timeline/29191.atom", -        "uri" => "https://social.heldscal.la/user/29191", -        "host" => "social.heldscal.la", -        "fqn" => user, -        "bio" => "cofe", -        "avatar" => %{ -          "type" => "Image", -          "url" => [ -            %{ -              "href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", -              "mediaType" => "image/jpeg", -              "type" => "Link" -            } -          ] -        }, -        "subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}", -        "ap_id" => nil -      } - -      assert data == expected -    end -  end - -  describe "fetching a status by it's HTML url" do -    test "it builds a missing status from an html url" do -      capture_log(fn -> -        url = "https://shitposter.club/notice/2827873" -        {:ok, [activity]} = OStatus.fetch_activity_from_url(url) - -        assert activity.data["actor"] == "https://shitposter.club/user/1" - -        assert activity.data["object"] == -                 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" -      end) -    end - -    test "it works for atom notes, too" do -      url = "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056" -      {:ok, [activity]} = OStatus.fetch_activity_from_url(url) -      assert activity.data["actor"] == "https://social.sakamoto.gq/users/eal" -      assert activity.data["object"] == url -    end -  end - -  test "it doesn't add nil in the to field" do -    incoming = File.read!("test/fixtures/nil_mention_entry.xml") -    {:ok, [activity]} = OStatus.handle_incoming(incoming) - -    assert activity.data["to"] == [ -             "http://localhost:4001/users/atarifrosch@social.stopwatchingus-heidelberg.de/followers", -             "https://www.w3.org/ns/activitystreams#Public" -           ] -  end - -  describe "is_representable?" do -    test "Note objects are representable" do -      note_activity = insert(:note_activity) - -      assert OStatus.is_representable?(note_activity) -    end - -    test "Article objects are not representable" do -      note_activity = insert(:note_activity) -      note_object = Object.normalize(note_activity) - -      note_data = -        note_object.data -        |> Map.put("type", "Article") - -      Cachex.clear(:object_cache) - -      cs = Object.change(note_object, %{data: note_data}) -      {:ok, _article_object} = Repo.update(cs) - -      # the underlying object is now an Article instead of a note, so this should fail -      refute OStatus.is_representable?(note_activity) -    end -  end - -  describe "make_user/2" do -    test "creates new user" do -      {:ok, user} = OStatus.make_user("https://social.heldscal.la/user/23211") - -      created_user = -        User -        |> Repo.get_by(ap_id: "https://social.heldscal.la/user/23211") -        |> Map.put(:last_digest_emailed_at, nil) - -      assert user.info -      assert user == created_user -    end -  end -end diff --git a/test/web/ostatus/user_representer_test.exs b/test/web/ostatus/user_representer_test.exs deleted file mode 100644 index e3863d2e9..000000000 --- a/test/web/ostatus/user_representer_test.exs +++ /dev/null @@ -1,38 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatus.UserRepresenterTest do -  use Pleroma.DataCase -  alias Pleroma.Web.OStatus.UserRepresenter - -  import Pleroma.Factory -  alias Pleroma.User - -  test "returns a user with id, uri, name and link" do -    user = insert(:user, %{nickname: "レイン"}) -    tuple = UserRepresenter.to_simple_form(user) - -    res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> to_string - -    expected = """ -    <id>#{user.ap_id}</id> -    <activity:object>http://activitystrea.ms/schema/1.0/person</activity:object> -    <uri>#{user.ap_id}</uri> -    <poco:preferredUsername>#{user.nickname}</poco:preferredUsername> -    <poco:displayName>#{user.name}</poco:displayName> -    <poco:note>#{user.bio}</poco:note> -    <summary>#{user.bio}</summary> -    <name>#{user.nickname}</name> -    <link rel="avatar" href="#{User.avatar_url(user)}" /> -    <link rel="header" href="#{User.banner_url(user)}" /> -    <ap_enabled>true</ap_enabled> -    """ - -    assert clean(res) == clean(expected) -  end - -  defp clean(string) do -    String.replace(string, ~r/\s/, "") -  end -end diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/web/pleroma_api/controllers/mascot_controller_test.exs new file mode 100644 index 000000000..ae9539b04 --- /dev/null +++ b/test/web/pleroma_api/controllers/mascot_controller_test.exs @@ -0,0 +1,77 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.User + +  import Pleroma.Factory + +  test "mascot upload", %{conn: conn} do +    user = insert(:user) + +    non_image_file = %Plug.Upload{ +      content_type: "audio/mpeg", +      path: Path.absname("test/fixtures/sound.mp3"), +      filename: "sound.mp3" +    } + +    conn = +      conn +      |> assign(:user, user) +      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) + +    assert json_response(conn, 415) + +    file = %Plug.Upload{ +      content_type: "image/jpg", +      path: Path.absname("test/fixtures/image.jpg"), +      filename: "an_image.jpg" +    } + +    conn = +      build_conn() +      |> assign(:user, user) +      |> put("/api/v1/pleroma/mascot", %{"file" => file}) + +    assert %{"id" => _, "type" => image} = json_response(conn, 200) +  end + +  test "mascot retrieving", %{conn: conn} do +    user = insert(:user) +    # When user hasn't set a mascot, we should just get pleroma tan back +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/pleroma/mascot") + +    assert %{"url" => url} = json_response(conn, 200) +    assert url =~ "pleroma-fox-tan-smol" + +    # When a user sets their mascot, we should get that back +    file = %Plug.Upload{ +      content_type: "image/jpg", +      path: Path.absname("test/fixtures/image.jpg"), +      filename: "an_image.jpg" +    } + +    conn = +      build_conn() +      |> assign(:user, user) +      |> put("/api/v1/pleroma/mascot", %{"file" => file}) + +    assert json_response(conn, 200) + +    user = User.get_cached_by_id(user.id) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> get("/api/v1/pleroma/mascot") + +    assert %{"url" => url, "type" => "image"} = json_response(conn, 200) +    assert url =~ "an_image" +  end +end diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index 7eaeda4a0..8a6528cbb 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do    alias Pleroma.Conversation.Participation    alias Pleroma.Notification    alias Pleroma.Repo +  alias Pleroma.User    alias Pleroma.Web.CommonAPI    import Pleroma.Factory @@ -73,6 +74,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do      participation = Repo.preload(participation, :recipients) +    user = User.get_cached_by_id(user.id)      assert [user] == participation.recipients      assert other_user not in participation.recipients diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs deleted file mode 100644 index 153ec41ac..000000000 --- a/test/web/salmon/salmon_test.exs +++ /dev/null @@ -1,101 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Salmon.SalmonTest do -  use Pleroma.DataCase -  alias Pleroma.Activity -  alias Pleroma.Keys -  alias Pleroma.Repo -  alias Pleroma.User -  alias Pleroma.Web.Federator.Publisher -  alias Pleroma.Web.Salmon -  import Mock -  import Pleroma.Factory - -  @magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" - -  @wrong_magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAA" - -  @magickey_friendica "RSA.AMwa8FUs2fWEjX0xN7yRQgegQffhBpuKNC6fa5VNSVorFjGZhRrlPMn7TQOeihlc9lBz2OsHlIedbYn2uJ7yCs0.AQAB" - -  setup_all do -    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) -    :ok -  end - -  test "decodes a salmon" do -    {:ok, salmon} = File.read("test/fixtures/salmon.xml") -    {:ok, doc} = Salmon.decode_and_validate(@magickey, salmon) -    assert Regex.match?(~r/xml/, doc) -  end - -  test "errors on wrong magic key" do -    {:ok, salmon} = File.read("test/fixtures/salmon.xml") -    assert Salmon.decode_and_validate(@wrong_magickey, salmon) == :error -  end - -  test "it encodes a magic key from a public key" do -    key = Salmon.decode_key(@magickey) -    magic_key = Salmon.encode_key(key) - -    assert @magickey == magic_key -  end - -  test "it decodes a friendica public key" do -    _key = Salmon.decode_key(@magickey_friendica) -  end - -  test "encodes an xml payload with a private key" do -    doc = File.read!("test/fixtures/incoming_note_activity.xml") -    pem = File.read!("test/fixtures/private_key.pem") -    {:ok, private, public} = Keys.keys_from_pem(pem) - -    # Let's try a roundtrip. -    {:ok, salmon} = Salmon.encode(private, doc) -    {:ok, decoded_doc} = Salmon.decode_and_validate(Salmon.encode_key(public), salmon) - -    assert doc == decoded_doc -  end - -  test "it gets a magic key" do -    salmon = File.read!("test/fixtures/salmon2.xml") -    {:ok, key} = Salmon.fetch_magic_key(salmon) - -    assert key == -             "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB" -  end - -  test_with_mock "it pushes an activity to remote accounts it's addressed to", -                 Publisher, -                 [:passthrough], -                 [] do -    user_data = %{ -      info: %{ -        salmon: "http://test-example.org/salmon" -      }, -      local: false -    } - -    mentioned_user = insert(:user, user_data) -    note = insert(:note) - -    activity_data = %{ -      "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), -      "type" => "Create", -      "actor" => note.data["actor"], -      "to" => note.data["to"] ++ [mentioned_user.ap_id], -      "object" => note.data, -      "published_at" => DateTime.utc_now() |> DateTime.to_iso8601(), -      "context" => note.data["context"] -    } - -    {:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]}) -    user = User.get_cached_by_ap_id(activity.data["actor"]) -    {:ok, user} = User.ensure_keys_present(user) - -    Salmon.publish(user, activity) - -    assert called(Publisher.enqueue_one(Salmon, %{recipient_id: mentioned_user.id})) -  end -end diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index b8fcd41fa..d33eb1e42 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -233,30 +233,68 @@ defmodule Pleroma.Web.StreamerTest do      end    end -  test "it doesn't send to blocked users" do -    user = insert(:user) -    blocked_user = insert(:user) -    {:ok, user} = User.block(user, blocked_user) +  describe "blocks" do +    test "it doesn't send messages involving blocked users" do +      user = insert(:user) +      blocked_user = insert(:user) +      {:ok, user} = User.block(user, blocked_user) -    task = -      Task.async(fn -> -        refute_receive {:text, _}, 1_000 -      end) +      task = +        Task.async(fn -> +          refute_receive {:text, _}, 1_000 +        end) -    fake_socket = %StreamerSocket{ -      transport_pid: task.pid, -      user: user -    } +      fake_socket = %StreamerSocket{ +        transport_pid: task.pid, +        user: user +      } -    {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) +      {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) -    topics = %{ -      "public" => [fake_socket] -    } +      topics = %{ +        "public" => [fake_socket] +      } -    Worker.push_to_socket(topics, "public", activity) +      Worker.push_to_socket(topics, "public", activity) -    Task.await(task) +      Task.await(task) +    end + +    test "it doesn't send messages transitively involving blocked users" do +      blocker = insert(:user) +      blockee = insert(:user) +      friend = insert(:user) + +      task = +        Task.async(fn -> +          refute_receive {:text, _}, 1_000 +        end) + +      fake_socket = %StreamerSocket{ +        transport_pid: task.pid, +        user: blocker +      } + +      topics = %{ +        "public" => [fake_socket] +      } + +      {:ok, blocker} = User.block(blocker, blockee) + +      {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"}) + +      Worker.push_to_socket(topics, "public", activity_one) + +      {:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"}) + +      Worker.push_to_socket(topics, "public", activity_two) + +      {:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"}) + +      Worker.push_to_socket(topics, "public", activity_three) + +      Task.await(task) +    end    end    test "it doesn't send unwanted DMs to list" do diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 56e318182..9d4cb70f0 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -81,19 +81,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert response == "job started"      end -    test "requires 'follow' permission", %{conn: conn} do +    test "requires 'follow' or 'write:follows' permissions", %{conn: conn} do        token1 = insert(:oauth_token, scopes: ["read", "write"])        token2 = insert(:oauth_token, scopes: ["follow"]) +      token3 = insert(:oauth_token, scopes: ["something"])        another_user = insert(:user) -      for token <- [token1, token2] do +      for token <- [token1, token2, token3] do          conn =            conn            |> put_req_header("authorization", "Bearer #{token.token}")            |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) -        if token == token1 do -          assert %{"error" => "Insufficient permissions: follow."} == json_response(conn, 403) +        if token == token3 do +          assert %{"error" => "Insufficient permissions: follow | write:follows."} == +                   json_response(conn, 403)          else            assert json_response(conn, 200)          end diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 696c1bd70..5aa8c73cf 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -45,19 +45,6 @@ defmodule Pleroma.Web.WebFingerTest do        assert {:error, %Jason.DecodeError{}} = WebFinger.finger(user)      end -    test "returns the info for an OStatus user" do -      user = "shp@social.heldscal.la" - -      {:ok, data} = WebFinger.finger(user) - -      assert data["magic_key"] == -               "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB" - -      assert data["topic"] == "https://social.heldscal.la/api/statuses/user_timeline/29191.atom" -      assert data["subject"] == "acct:shp@social.heldscal.la" -      assert data["salmon"] == "https://social.heldscal.la/main/salmon/user/29191" -    end -      test "returns the ActivityPub actor URI for an ActivityPub user" do        user = "framasoft@framatube.org" @@ -72,20 +59,6 @@ defmodule Pleroma.Web.WebFingerTest do        assert data["ap_id"] == "https://gerzilla.de/channel/kaniini"      end -    test "returns the correctly for json ostatus users" do -      user = "winterdienst@gnusocial.de" - -      {:ok, data} = WebFinger.finger(user) - -      assert data["magic_key"] == -               "RSA.qfYaxztz7ZELrE4v5WpJrPM99SKI3iv9Y3Tw6nfLGk-4CRljNYqV8IYX2FXjeucC_DKhPNnlF6fXyASpcSmA_qupX9WC66eVhFhZ5OuyBOeLvJ1C4x7Hi7Di8MNBxY3VdQuQR0tTaS_YAZCwASKp7H6XEid3EJpGt0EQZoNzRd8=.AQAB" - -      assert data["topic"] == "https://gnusocial.de/api/statuses/user_timeline/249296.atom" -      assert data["subject"] == "acct:winterdienst@gnusocial.de" -      assert data["salmon"] == "https://gnusocial.de/main/salmon/user/249296" -      assert data["subscribe_address"] == "https://gnusocial.de/main/ostatussub?profile={uri}" -    end -      test "it work for AP-only user" do        user = "kpherox@mstdn.jp" diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs deleted file mode 100644 index f6d002b3b..000000000 --- a/test/web/websub/websub_controller_test.exs +++ /dev/null @@ -1,86 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Websub.WebsubControllerTest do -  use Pleroma.Web.ConnCase -  import Pleroma.Factory -  alias Pleroma.Repo -  alias Pleroma.Web.Websub -  alias Pleroma.Web.Websub.WebsubClientSubscription - -  clear_config_all([:instance, :federating]) do -    Pleroma.Config.put([:instance, :federating], true) -  end - -  test "websub subscription request", %{conn: conn} do -    user = insert(:user) - -    path = Pleroma.Web.OStatus.pubsub_path(user) - -    data = %{ -      "hub.callback": "http://example.org/sub", -      "hub.mode": "subscribe", -      "hub.topic": Pleroma.Web.OStatus.feed_path(user), -      "hub.secret": "a random secret", -      "hub.lease_seconds": "100" -    } - -    conn = -      conn -      |> post(path, data) - -    assert response(conn, 202) == "Accepted" -  end - -  test "websub subscription confirmation", %{conn: conn} do -    websub = insert(:websub_client_subscription) - -    params = %{ -      "hub.mode" => "subscribe", -      "hub.topic" => websub.topic, -      "hub.challenge" => "some challenge", -      "hub.lease_seconds" => "100" -    } - -    conn = -      conn -      |> get("/push/subscriptions/#{websub.id}", params) - -    websub = Repo.get(WebsubClientSubscription, websub.id) - -    assert response(conn, 200) == "some challenge" -    assert websub.state == "accepted" -    assert_in_delta NaiveDateTime.diff(websub.valid_until, NaiveDateTime.utc_now()), 100, 5 -  end - -  describe "websub_incoming" do -    test "accepts incoming feed updates", %{conn: conn} do -      websub = insert(:websub_client_subscription) -      doc = "some stuff" -      signature = Websub.sign(websub.secret, doc) - -      conn = -        conn -        |> put_req_header("x-hub-signature", "sha1=" <> signature) -        |> put_req_header("content-type", "application/atom+xml") -        |> post("/push/subscriptions/#{websub.id}", doc) - -      assert response(conn, 200) == "OK" -    end - -    test "rejects incoming feed updates with the wrong signature", %{conn: conn} do -      websub = insert(:websub_client_subscription) -      doc = "some stuff" -      signature = Websub.sign("wrong secret", doc) - -      conn = -        conn -        |> put_req_header("x-hub-signature", "sha1=" <> signature) -        |> put_req_header("content-type", "application/atom+xml") -        |> post("/push/subscriptions/#{websub.id}", doc) - -      assert response(conn, 500) == "Error" -    end -  end -end diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs deleted file mode 100644 index 46ca545de..000000000 --- a/test/web/websub/websub_test.exs +++ /dev/null @@ -1,236 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.WebsubTest do -  use Pleroma.DataCase -  use Oban.Testing, repo: Pleroma.Repo - -  alias Pleroma.Tests.ObanHelpers -  alias Pleroma.Web.Router.Helpers -  alias Pleroma.Web.Websub -  alias Pleroma.Web.Websub.WebsubClientSubscription -  alias Pleroma.Web.Websub.WebsubServerSubscription -  alias Pleroma.Workers.SubscriberWorker - -  import Pleroma.Factory -  import Tesla.Mock - -  setup do -    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) -    :ok -  end - -  test "a verification of a request that is accepted" do -    sub = insert(:websub_subscription) -    topic = sub.topic - -    getter = fn _path, _headers, options -> -      %{ -        "hub.challenge": challenge, -        "hub.lease_seconds": seconds, -        "hub.topic": ^topic, -        "hub.mode": "subscribe" -      } = Keyword.get(options, :params) - -      assert String.to_integer(seconds) > 0 - -      {:ok, -       %Tesla.Env{ -         status: 200, -         body: challenge -       }} -    end - -    {:ok, sub} = Websub.verify(sub, getter) -    assert sub.state == "active" -  end - -  test "a verification of a request that doesn't return 200" do -    sub = insert(:websub_subscription) - -    getter = fn _path, _headers, _options -> -      {:ok, -       %Tesla.Env{ -         status: 500, -         body: "" -       }} -    end - -    {:error, sub} = Websub.verify(sub, getter) -    # Keep the current state. -    assert sub.state == "requested" -  end - -  test "an incoming subscription request" do -    user = insert(:user) - -    data = %{ -      "hub.callback" => "http://example.org/sub", -      "hub.mode" => "subscribe", -      "hub.topic" => Pleroma.Web.OStatus.feed_path(user), -      "hub.secret" => "a random secret", -      "hub.lease_seconds" => "100" -    } - -    {:ok, subscription} = Websub.incoming_subscription_request(user, data) -    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user) -    assert subscription.state == "requested" -    assert subscription.secret == "a random secret" -    assert subscription.callback == "http://example.org/sub" -  end - -  test "an incoming subscription request for an existing subscription" do -    user = insert(:user) - -    sub = -      insert(:websub_subscription, state: "accepted", topic: Pleroma.Web.OStatus.feed_path(user)) - -    data = %{ -      "hub.callback" => sub.callback, -      "hub.mode" => "subscribe", -      "hub.topic" => Pleroma.Web.OStatus.feed_path(user), -      "hub.secret" => "a random secret", -      "hub.lease_seconds" => "100" -    } - -    {:ok, subscription} = Websub.incoming_subscription_request(user, data) -    assert subscription.topic == Pleroma.Web.OStatus.feed_path(user) -    assert subscription.state == sub.state -    assert subscription.secret == "a random secret" -    assert subscription.callback == sub.callback -    assert length(Repo.all(WebsubServerSubscription)) == 1 -    assert subscription.id == sub.id -  end - -  def accepting_verifier(subscription) do -    {:ok, %{subscription | state: "accepted"}} -  end - -  test "initiate a subscription for a given user and topic" do -    subscriber = insert(:user) -    user = insert(:user, %{info: %Pleroma.User.Info{topic: "some_topic", hub: "some_hub"}}) - -    {:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1) -    assert websub.subscribers == [subscriber.ap_id] -    assert websub.topic == "some_topic" -    assert websub.hub == "some_hub" -    assert is_binary(websub.secret) -    assert websub.user == user -    assert websub.state == "accepted" -  end - -  test "discovers the hub and canonical url" do -    topic = "https://mastodon.social/users/lambadalambda.atom" - -    {:ok, discovered} = Websub.gather_feed_data(topic) - -    expected = %{ -      "hub" => "https://mastodon.social/api/push", -      "uri" => "https://mastodon.social/users/lambadalambda", -      "nickname" => "lambadalambda", -      "name" => "Critical Value", -      "host" => "mastodon.social", -      "bio" => "a cool dude.", -      "avatar" => %{ -        "type" => "Image", -        "url" => [ -          %{ -            "href" => -              "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244", -            "mediaType" => "image/gif", -            "type" => "Link" -          } -        ] -      } -    } - -    assert expected == discovered -  end - -  test "calls the hub, requests topic" do -    hub = "https://social.heldscal.la/main/push/hub" -    topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom" -    websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) - -    poster = fn ^hub, {:form, data}, _headers -> -      assert Keyword.get(data, :"hub.mode") == "subscribe" - -      assert Keyword.get(data, :"hub.callback") == -               Helpers.websub_url( -                 Pleroma.Web.Endpoint, -                 :websub_subscription_confirmation, -                 websub.id -               ) - -      {:ok, %{status: 202}} -    end - -    task = Task.async(fn -> Websub.request_subscription(websub, poster) end) - -    change = Ecto.Changeset.change(websub, %{state: "accepted"}) -    {:ok, _} = Repo.update(change) - -    {:ok, websub} = Task.await(task) - -    assert websub.state == "accepted" -  end - -  test "rejects the subscription if it can't be accepted" do -    hub = "https://social.heldscal.la/main/push/hub" -    topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom" -    websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) - -    poster = fn ^hub, {:form, _data}, _headers -> -      {:ok, %{status: 202}} -    end - -    {:error, websub} = Websub.request_subscription(websub, poster, 1000) -    assert websub.state == "rejected" - -    websub = insert(:websub_client_subscription, %{hub: hub, topic: topic}) - -    poster = fn ^hub, {:form, _data}, _headers -> -      {:ok, %{status: 400}} -    end - -    {:error, websub} = Websub.request_subscription(websub, poster, 1000) -    assert websub.state == "rejected" -  end - -  test "sign a text" do -    signed = Websub.sign("secret", "text") -    assert signed == "B8392C23690CCF871F37EC270BE1582DEC57A503" |> String.downcase() - -    _signed = Websub.sign("secret", [["て"], ['す']]) -  end - -  describe "renewing subscriptions" do -    test "it renews subscriptions that have less than a day of time left" do -      day = 60 * 60 * 24 -      now = NaiveDateTime.utc_now() - -      still_good = -        insert(:websub_client_subscription, %{ -          valid_until: NaiveDateTime.add(now, 2 * day), -          topic: "http://example.org/still_good", -          hub: "http://example.org/still_good", -          state: "accepted" -        }) - -      needs_refresh = -        insert(:websub_client_subscription, %{ -          valid_until: NaiveDateTime.add(now, day - 100), -          topic: "http://example.org/needs_refresh", -          hub: "http://example.org/needs_refresh", -          state: "accepted" -        }) - -      _refresh = Websub.refresh_subscriptions() -      ObanHelpers.perform(all_enqueued(worker: SubscriberWorker)) - -      assert still_good == Repo.get(WebsubClientSubscription, still_good.id) -      refute needs_refresh == Repo.get(WebsubClientSubscription, needs_refresh.id) -    end -  end -end | 
