Merge branch 'develop' into 'remove-twitter-api'

# Conflicts:
#   lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
This commit is contained in:
lain 2020-05-16 17:07:09 +00:00
commit d15aa9d950
598 changed files with 28836 additions and 10625 deletions

View file

@ -83,7 +83,7 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
assert Enum.member?(topics, "hashtag:bar")
end
test "only converts strinngs to hash tags", %{
test "only converts strings to hash tags", %{
activity: %{object: %{data: data} = object} = activity
} do
tagged_data = Map.put(data, "tag", [2])

View file

@ -11,6 +11,11 @@ defmodule Pleroma.ActivityTest do
alias Pleroma.ThreadMute
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
test "returns an activity by it's AP id" do
activity = insert(:note_activity)
found_activity = Activity.get_by_ap_id(activity.data["id"])
@ -107,8 +112,6 @@ defmodule Pleroma.ActivityTest do
describe "search" do
setup do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
user = insert(:user)
params = %{
@ -125,8 +128,8 @@ defmodule Pleroma.ActivityTest do
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
{:ok, local_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "find me!"})
{:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "更新情報"})
{: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)
@ -225,8 +228,8 @@ defmodule Pleroma.ActivityTest do
test "all_by_actor_and_id/2" do
user = insert(:user)
{:ok, %{id: id1}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofe"})
{:ok, %{id: id2}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofefe"})
{:ok, %{id: id1}} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"})
{:ok, %{id: id2}} = Pleroma.Web.CommonAPI.post(user, %{status: "cofefe"})
assert [] == Activity.all_by_actor_and_id(user, [])

View file

@ -21,8 +21,8 @@ defmodule Pleroma.BBS.HandlerTest do
{:ok, user} = User.follow(user, followed)
{:ok, _first} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, _second} = CommonAPI.post(followed, %{"status" => "hello"})
{:ok, _first} = CommonAPI.post(user, %{status: "hey"})
{:ok, _second} = CommonAPI.post(followed, %{status: "hello"})
output =
capture_io(fn ->
@ -62,7 +62,7 @@ defmodule Pleroma.BBS.HandlerTest do
user = insert(:user)
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{"status" => "this is a test post"})
{:ok, activity} = CommonAPI.post(another_user, %{status: "this is a test post"})
activity_object = Object.normalize(activity)
output =

View file

@ -11,7 +11,7 @@ defmodule Pleroma.BookmarkTest do
describe "create/2" do
test "with valid params" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Some cool information"})
{:ok, activity} = CommonAPI.post(user, %{status: "Some cool information"})
{:ok, bookmark} = Bookmark.create(user.id, activity.id)
assert bookmark.user_id == user.id
assert bookmark.activity_id == activity.id
@ -32,7 +32,7 @@ defmodule Pleroma.BookmarkTest do
test "with valid params" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Some cool information"})
{:ok, activity} = CommonAPI.post(user, %{status: "Some cool information"})
{:ok, _bookmark} = Bookmark.create(user.id, activity.id)
{:ok, _deleted_bookmark} = Bookmark.destroy(user.id, activity.id)
@ -45,7 +45,7 @@ defmodule Pleroma.BookmarkTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
status:
"Scientists Discover The Secret Behind Tenshi Eating A Corndog Being So Cute Science Daily"
})

View file

@ -61,7 +61,7 @@ defmodule Pleroma.CaptchaTest do
assert is_binary(answer)
assert :ok = Native.validate(token, answer, answer)
assert {:error, "Invalid CAPTCHA"} == Native.validate(token, answer, answer <> "foobar")
assert {:error, :invalid} == Native.validate(token, answer, answer <> "foobar")
end
end
@ -78,6 +78,7 @@ defmodule Pleroma.CaptchaTest do
assert is_binary(answer)
assert :ok = Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer)
Cachex.del(:used_captcha_cache, token)
end
test "doesn't validate invalid answer" do
@ -92,7 +93,7 @@ defmodule Pleroma.CaptchaTest do
assert is_binary(answer)
assert {:error, "Invalid answer data"} =
assert {:error, :invalid_answer_data} =
Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer <> "foobar")
end
@ -108,7 +109,7 @@ defmodule Pleroma.CaptchaTest do
assert is_binary(answer)
assert {:error, "Invalid answer data"} =
assert {:error, :invalid_answer_data} =
Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", nil)
end
end

View file

@ -43,11 +43,9 @@ defmodule Pleroma.ConfigDBTest do
{ConfigDB.from_string(saved.key), ConfigDB.from_binary(saved.value)}
]
assert config[:quack] == [
level: :info,
meta: [:none],
webhook_url: "https://hooks.slack.com/services/KEY/some_val"
]
assert config[:quack][:level] == :info
assert config[:quack][:meta] == [:none]
assert config[:quack][:webhook_url] == "https://hooks.slack.com/services/KEY/some_val"
end
describe "update_or_create/1" do

View file

@ -16,6 +16,8 @@ defmodule Pleroma.Config.TransferTaskTest do
refute Application.get_env(:pleroma, :test_key)
refute Application.get_env(:idna, :test_key)
refute Application.get_env(:quack, :test_key)
refute Application.get_env(:postgrex, :test_key)
initial = Application.get_env(:logger, :level)
ConfigDB.create(%{
group: ":pleroma",
@ -35,16 +37,28 @@ defmodule Pleroma.Config.TransferTaskTest do
value: [:test_value1, :test_value2]
})
ConfigDB.create(%{
group: ":postgrex",
key: ":test_key",
value: :value
})
ConfigDB.create(%{group: ":logger", key: ":level", value: :debug})
TransferTask.start_link([])
assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3]
assert Application.get_env(:idna, :test_key) == [live: 15, com: 35]
assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2]
assert Application.get_env(:logger, :level) == :debug
assert Application.get_env(:postgrex, :test_key) == :value
on_exit(fn ->
Application.delete_env(:pleroma, :test_key)
Application.delete_env(:idna, :test_key)
Application.delete_env(:quack, :test_key)
Application.delete_env(:postgrex, :test_key)
Application.put_env(:logger, :level, initial)
end)
end
@ -78,8 +92,8 @@ defmodule Pleroma.Config.TransferTaskTest do
end
test "transfer config values with full subkey update" do
emoji = Application.get_env(:pleroma, :emoji)
assets = Application.get_env(:pleroma, :assets)
clear_config(:emoji)
clear_config(:assets)
ConfigDB.create(%{
group: ":pleroma",
@ -99,11 +113,6 @@ defmodule Pleroma.Config.TransferTaskTest do
assert emoji_env[:groups] == [a: 1, b: 2]
assets_env = Application.get_env(:pleroma, :assets)
assert assets_env[:mascots] == [a: 1, b: 2]
on_exit(fn ->
Application.put_env(:pleroma, :emoji, emoji)
Application.put_env(:pleroma, :assets, assets)
end)
end
describe "pleroma restart" do
@ -112,8 +121,7 @@ defmodule Pleroma.Config.TransferTaskTest do
end
test "don't restart if no reboot time settings were changed" do
emoji = Application.get_env(:pleroma, :emoji)
on_exit(fn -> Application.put_env(:pleroma, :emoji, emoji) end)
clear_config(:emoji)
ConfigDB.create(%{
group: ":pleroma",
@ -128,8 +136,7 @@ defmodule Pleroma.Config.TransferTaskTest do
end
test "on reboot time key" do
chat = Application.get_env(:pleroma, :chat)
on_exit(fn -> Application.put_env(:pleroma, :chat, chat) end)
clear_config(:chat)
ConfigDB.create(%{
group: ":pleroma",
@ -141,8 +148,7 @@ defmodule Pleroma.Config.TransferTaskTest do
end
test "on reboot time subkey" do
captcha = Application.get_env(:pleroma, Pleroma.Captcha)
on_exit(fn -> Application.put_env(:pleroma, Pleroma.Captcha, captcha) end)
clear_config(Pleroma.Captcha)
ConfigDB.create(%{
group: ":pleroma",
@ -154,13 +160,8 @@ defmodule Pleroma.Config.TransferTaskTest do
end
test "don't restart pleroma on reboot time key and subkey if there is false flag" do
chat = Application.get_env(:pleroma, :chat)
captcha = Application.get_env(:pleroma, Pleroma.Captcha)
on_exit(fn ->
Application.put_env(:pleroma, :chat, chat)
Application.put_env(:pleroma, Pleroma.Captcha, captcha)
end)
clear_config(:chat)
clear_config(Pleroma.Captcha)
ConfigDB.create(%{
group: ":pleroma",

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
other_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"})
CommonAPI.post(user, %{status: "Hey @#{other_user.nickname}.", visibility: "direct"})
[participation] = Participation.for_user(user)
@ -30,7 +30,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
other_user = insert(:user)
{:ok, _} =
CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"})
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)
@ -43,9 +43,9 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, _} =
CommonAPI.post(other_user, %{
"status" => "Hey @#{user.nickname}.",
"visibility" => "direct",
"in_reply_to_conversation_id" => participation.id
status: "Hey @#{user.nickname}.",
visibility: "direct",
in_reply_to_conversation_id: participation.id
})
user = User.get_cached_by_id(user.id)
@ -64,7 +64,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
third_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"})
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)
@ -79,9 +79,9 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, _activity} =
CommonAPI.post(user, %{
"in_reply_to_status_id" => activity.id,
"status" => "Hey @#{third_user.nickname}.",
"visibility" => "direct"
in_reply_to_status_id: activity.id,
status: "Hey @#{third_user.nickname}.",
visibility: "direct"
})
[participation] = Participation.for_user(user)
@ -154,14 +154,14 @@ defmodule Pleroma.Conversation.ParticipationTest do
test "gets all the participations for a user, ordered by updated at descending" do
user = insert(:user)
{:ok, activity_one} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
{:ok, activity_two} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
{:ok, activity_one} = CommonAPI.post(user, %{status: "x", visibility: "direct"})
{:ok, activity_two} = CommonAPI.post(user, %{status: "x", visibility: "direct"})
{:ok, activity_three} =
CommonAPI.post(user, %{
"status" => "x",
"visibility" => "direct",
"in_reply_to_status_id" => activity_one.id
status: "x",
visibility: "direct",
in_reply_to_status_id: activity_one.id
})
# Offset participations because the accuracy of updated_at is down to a second
@ -201,7 +201,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
test "Doesn't die when the conversation gets empty" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
{:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
[participation] = Participation.for_user_with_last_activity_id(user)
assert participation.last_activity_id == activity.id
@ -215,7 +215,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, _activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
{:ok, _activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
[participation] = Participation.for_user_with_last_activity_id(user)
participation = Repo.preload(participation, :recipients)
@ -239,26 +239,26 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, _direct1} =
CommonAPI.post(third_user, %{
"status" => "Hi @#{blocker.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}",
visibility: "direct"
})
{:ok, _direct2} =
CommonAPI.post(third_user, %{
"status" => "Hi @#{blocker.nickname}, @#{blocked.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}, @#{blocked.nickname}",
visibility: "direct"
})
{:ok, _direct3} =
CommonAPI.post(blocked, %{
"status" => "Hi @#{blocker.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}",
visibility: "direct"
})
{:ok, _direct4} =
CommonAPI.post(blocked, %{
"status" => "Hi @#{blocker.nickname}, @#{third_user.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}, @#{third_user.nickname}",
visibility: "direct"
})
assert [%{read: false}, %{read: false}, %{read: false}, %{read: false}] =
@ -293,8 +293,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
# When the blocked user is the author
{:ok, _direct1} =
CommonAPI.post(blocked, %{
"status" => "Hi @#{blocker.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}",
visibility: "direct"
})
assert [%{read: true}] = Participation.for_user(blocker)
@ -303,8 +303,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
# When the blocked user is a recipient
{:ok, _direct2} =
CommonAPI.post(third_user, %{
"status" => "Hi @#{blocker.nickname}, @#{blocked.nickname}",
"visibility" => "direct"
status: "Hi @#{blocker.nickname}, @#{blocked.nickname}",
visibility: "direct"
})
assert [%{read: true}, %{read: true}] = Participation.for_user(blocker)
@ -321,8 +321,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, _direct1} =
CommonAPI.post(blocker, %{
"status" => "Hi @#{third_user.nickname}, @#{blocked.nickname}",
"visibility" => "direct"
status: "Hi @#{third_user.nickname}, @#{blocked.nickname}",
visibility: "direct"
})
{:ok, _user_relationship} = User.block(blocker, blocked)
@ -334,9 +334,9 @@ defmodule Pleroma.Conversation.ParticipationTest do
# When it's a reply from the blocked user
{:ok, _direct2} =
CommonAPI.post(blocked, %{
"status" => "reply",
"visibility" => "direct",
"in_reply_to_conversation_id" => blocked_participation.id
status: "reply",
visibility: "direct",
in_reply_to_conversation_id: blocked_participation.id
})
assert [%{read: true}] = Participation.for_user(blocker)
@ -347,9 +347,9 @@ defmodule Pleroma.Conversation.ParticipationTest do
# When it's a reply from the third user
{:ok, _direct3} =
CommonAPI.post(third_user, %{
"status" => "reply",
"visibility" => "direct",
"in_reply_to_conversation_id" => third_user_participation.id
status: "reply",
visibility: "direct",
in_reply_to_conversation_id: third_user_participation.id
})
assert [%{read: true}] = Participation.for_user(blocker)

View file

@ -18,7 +18,7 @@ defmodule Pleroma.ConversationTest do
other_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(user, %{"visibility" => "direct", "status" => "hey @#{other_user.nickname}"})
CommonAPI.post(user, %{visibility: "direct", status: "hey @#{other_user.nickname}"})
Pleroma.Tests.ObanHelpers.perform_all()
@ -46,7 +46,7 @@ defmodule Pleroma.ConversationTest do
test "public posts don't create conversations" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Hey"})
{:ok, activity} = CommonAPI.post(user, %{status: "Hey"})
object = Pleroma.Object.normalize(activity)
context = object.data["context"]
@ -62,7 +62,7 @@ defmodule Pleroma.ConversationTest do
tridi = insert(:user)
{:ok, activity} =
CommonAPI.post(har, %{"status" => "Hey @#{jafnhar.nickname}", "visibility" => "direct"})
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
object = Pleroma.Object.normalize(activity)
context = object.data["context"]
@ -81,9 +81,9 @@ defmodule Pleroma.ConversationTest do
{:ok, activity} =
CommonAPI.post(jafnhar, %{
"status" => "Hey @#{har.nickname}",
"visibility" => "direct",
"in_reply_to_status_id" => activity.id
status: "Hey @#{har.nickname}",
visibility: "direct",
in_reply_to_status_id: activity.id
})
object = Pleroma.Object.normalize(activity)
@ -105,9 +105,9 @@ defmodule Pleroma.ConversationTest do
{:ok, activity} =
CommonAPI.post(tridi, %{
"status" => "Hey @#{har.nickname}",
"visibility" => "direct",
"in_reply_to_status_id" => activity.id
status: "Hey @#{har.nickname}",
visibility: "direct",
in_reply_to_status_id: activity.id
})
object = Pleroma.Object.normalize(activity)
@ -149,14 +149,14 @@ defmodule Pleroma.ConversationTest do
jafnhar = insert(:user, local: false)
{:ok, activity} =
CommonAPI.post(har, %{"status" => "Hey @#{jafnhar.nickname}", "visibility" => "direct"})
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
{:ok, conversation} = Conversation.create_or_bump_for(activity)
assert length(conversation.participations) == 2
{:ok, activity} =
CommonAPI.post(har, %{"status" => "Hey @#{jafnhar.nickname}", "visibility" => "public"})
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "public"})
assert {:error, _} = Conversation.create_or_bump_for(activity)
end

View file

@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emoji.FormatterTest do
alias Pleroma.Emoji
alias Pleroma.Emoji.Formatter
use Pleroma.DataCase
@ -32,30 +31,19 @@ defmodule Pleroma.Emoji.FormatterTest do
end
end
describe "get_emoji" do
describe "get_emoji_map" do
test "it returns the emoji used in the text" do
text = "I love :firefox:"
assert Formatter.get_emoji(text) == [
{"firefox",
%Emoji{
code: "firefox",
file: "/emoji/Firefox.gif",
tags: ["Gif", "Fun"],
safe_code: "firefox",
safe_file: "/emoji/Firefox.gif"
}}
]
assert Formatter.get_emoji_map("I love :firefox:") == %{
"firefox" => "http://localhost:4001/emoji/Firefox.gif"
}
end
test "it returns a nice empty result when no emojis are present" do
text = "I love moominamma"
assert Formatter.get_emoji(text) == []
assert Formatter.get_emoji_map("I love moominamma") == %{}
end
test "it doesn't die when text is absent" do
text = nil
assert Formatter.get_emoji(text) == []
assert Formatter.get_emoji_map(nil) == %{}
end
end
end

View file

@ -141,17 +141,15 @@ defmodule Pleroma.FilterTest do
context: ["home"]
}
query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
changes = %{
phrase: "who",
context: ["home", "timeline"]
}
{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.update(query_two)
{:ok, filter_two} = Pleroma.Filter.update(filter_one, changes)
assert filter_one != filter_two
assert filter_two.phrase == query_two.phrase
assert filter_two.context == query_two.context
assert filter_two.phrase == changes.phrase
assert filter_two.context == changes.context
end
end

View file

@ -7,3 +7,5 @@ config :pleroma, :second_setting, key: "value2", key2: ["Activity"]
config :quack, level: :info
config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox
config :postgrex, :json_library, Poison

BIN
test/fixtures/emoji/packs/blank.png.zip vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,10 @@
{
"finmoji": {
"license": "CC BY-NC-ND 4.0",
"homepage": "https://finland.fi/emoji/",
"description": "Finland is the first country in the world to publish its own set of country themed emojis. The Finland emoji collection contains 56 tongue-in-cheek emotions, which were created to explain some hard-to-describe Finnish emotions, Finnish words and customs.",
"src": "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip",
"src_sha256": "384025A1AC6314473863A11AC7AB38A12C01B851A3F82359B89B4D4211D3291D",
"files": "finmoji.json"
}
}

View file

@ -0,0 +1,3 @@
{
"blank": "blank.png"
}

10
test/fixtures/emoji/packs/manifest.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"blobs.gg": {
"src_sha256": "3a12f3a181678d5b3584a62095411b0d60a335118135910d879920f8ade5a57f",
"src": "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip",
"license": "Apache 2.0",
"homepage": "https://blobs.gg",
"files": "blobs_gg.json",
"description": "Blob Emoji from blobs.gg repacked as apng"
}
}

View file

@ -0,0 +1,112 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"CacheFile": "pt:CacheFile",
"Hashtag": "as:Hashtag",
"Infohash": "pt:Infohash",
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017",
"category": "sc:category",
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"downloadEnabled": {
"@id": "pt:downloadEnabled",
"@type": "sc:Boolean"
},
"expires": "sc:expires",
"fps": {
"@id": "pt:fps",
"@type": "sc:Number"
},
"language": "sc:inLanguage",
"licence": "sc:license",
"originallyPublishedAt": "sc:datePublished",
"position": {
"@id": "pt:position",
"@type": "sc:Number"
},
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org#",
"sensitive": "as:sensitive",
"size": {
"@id": "pt:size",
"@type": "sc:Number"
},
"startTimestamp": {
"@id": "pt:startTimestamp",
"@type": "sc:Number"
},
"state": {
"@id": "pt:state",
"@type": "sc:Number"
},
"stopTimestamp": {
"@id": "pt:stopTimestamp",
"@type": "sc:Number"
},
"subtitleLanguage": "sc:subtitleLanguage",
"support": {
"@id": "pt:support",
"@type": "sc:Text"
},
"uuid": "sc:identifier",
"views": {
"@id": "pt:views",
"@type": "sc:Number"
},
"waitTranscoding": {
"@id": "pt:waitTranscoding",
"@type": "sc:Boolean"
}
},
{
"comments": {
"@id": "as:comments",
"@type": "@id"
},
"dislikes": {
"@id": "as:dislikes",
"@type": "@id"
},
"likes": {
"@id": "as:likes",
"@type": "@id"
},
"playlists": {
"@id": "pt:playlists",
"@type": "@id"
},
"shares": {
"@id": "as:shares",
"@type": "@id"
}
}
],
"endpoints": {
"sharedInbox": "https://peertube.social/inbox"
},
"followers": "https://peertube.social/accounts/craigmaloney/followers",
"following": "https://peertube.social/accounts/craigmaloney/following",
"icon": {
"mediaType": "image/png",
"type": "Image",
"url": "https://peertube.social/lazy-static/avatars/87bd694b-95bc-4066-83f4-bddfcd2b9caa.png"
},
"id": "https://peertube.social/accounts/craigmaloney",
"inbox": "https://peertube.social/accounts/craigmaloney/inbox",
"name": "Craig Maloney",
"outbox": "https://peertube.social/accounts/craigmaloney/outbox",
"playlists": "https://peertube.social/accounts/craigmaloney/playlists",
"preferredUsername": "craigmaloney",
"publicKey": {
"id": "https://peertube.social/accounts/craigmaloney#main-key",
"owner": "https://peertube.social/accounts/craigmaloney",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9qvGIYUW01yc8CCsrwxK\n5OXlV5s7EbNWY8tJr/p1oGuELZwAnG2XKxtdbvgcCT+YxL5uRXIdCFIIIKrzRFr/\nHfS0mOgNT9u3gu+SstCNgtatciT0RVP77yiC3b2NHq1NRRvvVhzQb4cpIWObIxqh\nb2ypDClTc7XaKtgmQCbwZlGyZMT+EKz/vustD6BlpGsglRkm7iES6s1PPGb1BU+n\nS94KhbS2DOFiLcXCVWt0QarokIIuKznp4+xP1axKyP+SkT5AHx08Nd5TYFb2C1Jl\nz0WD/1q0mAN62m7QrA3SQPUgB+wWD+S3Nzf7FwNPiP4srbBgxVEUnji/r9mQ6BXC\nrQIDAQAB\n-----END PUBLIC KEY-----"
},
"summary": null,
"type": "Person",
"url": "https://peertube.social/accounts/craigmaloney"
}

View file

@ -0,0 +1,44 @@
{
"id": "https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871",
"type": "Audio",
"name": "Compositions - Test Audio for Pleroma",
"attributedTo": "https://channels.tests.funkwhale.audio/federation/actors/compositions",
"published": "2020-03-11T10:01:52.714918+00:00",
"to": "https://www.w3.org/ns/activitystreams#Public",
"url": [
{
"type": "Link",
"mimeType": "audio/ogg",
"href": "https://channels.tests.funkwhale.audio/api/v1/listen/3901e5d8-0445-49d5-9711-e096cf32e515/?upload=42342395-0208-4fee-a38d-259a6dae0871&download=false"
},
{
"type": "Link",
"mimeType": "text/html",
"href": "https://channels.tests.funkwhale.audio/library/tracks/74"
}
],
"content": "<p>This is a test Audio for Pleroma.</p>",
"mediaType": "text/html",
"tag": [
{
"type": "Hashtag",
"name": "#funkwhale"
},
{
"type": "Hashtag",
"name": "#test"
},
{
"type": "Hashtag",
"name": "#tests"
}
],
"summary": "#funkwhale #test #tests",
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers"
}
]
}

View file

@ -0,0 +1,44 @@
{
"id": "https://channels.tests.funkwhale.audio/federation/actors/compositions",
"outbox": "https://channels.tests.funkwhale.audio/federation/actors/compositions/outbox",
"inbox": "https://channels.tests.funkwhale.audio/federation/actors/compositions/inbox",
"preferredUsername": "compositions",
"type": "Person",
"name": "Compositions",
"followers": "https://channels.tests.funkwhale.audio/federation/actors/compositions/followers",
"following": "https://channels.tests.funkwhale.audio/federation/actors/compositions/following",
"manuallyApprovesFollowers": false,
"url": [
{
"type": "Link",
"href": "https://channels.tests.funkwhale.audio/channels/compositions",
"mediaType": "text/html"
},
{
"type": "Link",
"href": "https://channels.tests.funkwhale.audio/api/v1/channels/compositions/rss",
"mediaType": "application/rss+xml"
}
],
"icon": {
"type": "Image",
"url": "https://channels.tests.funkwhale.audio/media/attachments/75/b4/f1/nosmile.jpeg",
"mediaType": "image/jpeg"
},
"summary": "<p>I'm testing federation with the fediverse :)</p>",
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers"
}
],
"publicKey": {
"owner": "https://channels.tests.funkwhale.audio/federation/actors/compositions",
"publicKeyPem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAv25u57oZfVLV3KltS+HcsdSx9Op4MmzIes1J8Wu8s0KbdXf2zEwS\nsVqyHgs/XCbnzsR3FqyJTo46D2BVnvZcuU5srNcR2I2HMaqQ0oVdnATE4K6KdcgV\nN+98pMWo56B8LTgE1VpvqbsrXLi9jCTzjrkebVMOP+ZVu+64v1qdgddseblYMnBZ\nct0s7ONbHnqrWlTGf5wES1uIZTVdn5r4MduZG+Uenfi1opBS0lUUxfWdW9r0oF2b\nyneZUyaUCbEroeKbqsweXCWVgnMarUOsgqC42KM4cf95lySSwTSaUtZYIbTw7s9W\n2jveU/rVg8BYZu5JK5obgBoxtlUeUoSswwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
"id": "https://channels.tests.funkwhale.audio/federation/actors/compositions#main-key"
},
"endpoints": {
"sharedInbox": "https://channels.tests.funkwhale.audio/federation/shared/inbox"
}
}

View file

@ -0,0 +1,234 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"CacheFile": "pt:CacheFile",
"Hashtag": "as:Hashtag",
"Infohash": "pt:Infohash",
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017",
"category": "sc:category",
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"downloadEnabled": {
"@id": "pt:downloadEnabled",
"@type": "sc:Boolean"
},
"expires": "sc:expires",
"fps": {
"@id": "pt:fps",
"@type": "sc:Number"
},
"language": "sc:inLanguage",
"licence": "sc:license",
"originallyPublishedAt": "sc:datePublished",
"position": {
"@id": "pt:position",
"@type": "sc:Number"
},
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org#",
"sensitive": "as:sensitive",
"size": {
"@id": "pt:size",
"@type": "sc:Number"
},
"startTimestamp": {
"@id": "pt:startTimestamp",
"@type": "sc:Number"
},
"state": {
"@id": "pt:state",
"@type": "sc:Number"
},
"stopTimestamp": {
"@id": "pt:stopTimestamp",
"@type": "sc:Number"
},
"subtitleLanguage": "sc:subtitleLanguage",
"support": {
"@id": "pt:support",
"@type": "sc:Text"
},
"uuid": "sc:identifier",
"views": {
"@id": "pt:views",
"@type": "sc:Number"
},
"waitTranscoding": {
"@id": "pt:waitTranscoding",
"@type": "sc:Boolean"
}
},
{
"comments": {
"@id": "as:comments",
"@type": "@id"
},
"dislikes": {
"@id": "as:dislikes",
"@type": "@id"
},
"likes": {
"@id": "as:likes",
"@type": "@id"
},
"playlists": {
"@id": "pt:playlists",
"@type": "@id"
},
"shares": {
"@id": "as:shares",
"@type": "@id"
}
}
],
"attributedTo": [
{
"id": "https://peertube.social/accounts/craigmaloney",
"type": "Person"
},
{
"id": "https://peertube.social/video-channels/9909c7d9-6b5b-4aae-9164-c1af7229c91c",
"type": "Group"
}
],
"category": {
"identifier": "15",
"name": "Science & Technology"
},
"cc": [
"https://peertube.social/accounts/craigmaloney/followers"
],
"comments": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe/comments",
"commentsEnabled": true,
"content": "Support this and our other Michigan!/usr/group videos and meetings. Learn more at http://mug.org/membership\n\nTwenty Years in Jail: FreeBSD's Jails, Then and Now\n\nJails started as a limited virtualization system, but over the last two years they've...",
"dislikes": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe/dislikes",
"downloadEnabled": true,
"duration": "PT5151S",
"icon": {
"height": 122,
"mediaType": "image/jpeg",
"type": "Image",
"url": "https://peertube.social/static/thumbnails/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe.jpg",
"width": 223
},
"id": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe",
"language": {
"identifier": "en",
"name": "English"
},
"licence": {
"identifier": "1",
"name": "Attribution"
},
"likes": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe/likes",
"mediaType": "text/markdown",
"name": "Twenty Years in Jail: FreeBSD's Jails, Then and Now",
"originallyPublishedAt": "2019-08-13T00:00:00.000Z",
"published": "2020-02-12T01:06:08.054Z",
"sensitive": false,
"shares": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe/announces",
"state": 1,
"subtitleLanguage": [],
"support": "Learn more at http://mug.org",
"tag": [
{
"name": "linux",
"type": "Hashtag"
},
{
"name": "mug.org",
"type": "Hashtag"
},
{
"name": "open",
"type": "Hashtag"
},
{
"name": "oss",
"type": "Hashtag"
},
{
"name": "source",
"type": "Hashtag"
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"type": "Video",
"updated": "2020-02-15T15:01:09.474Z",
"url": [
{
"href": "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe",
"mediaType": "text/html",
"type": "Link"
},
{
"fps": 30,
"height": 240,
"href": "https://peertube.social/static/webseed/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-240.mp4",
"mediaType": "video/mp4",
"size": 119465800,
"type": "Link"
},
{
"height": 240,
"href": "https://peertube.social/static/torrents/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-240.torrent",
"mediaType": "application/x-bittorrent",
"type": "Link"
},
{
"height": 240,
"href": "magnet:?xs=https%3A%2F%2Fpeertube.social%2Fstatic%2Ftorrents%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-240.torrent&xt=urn:btih:b3365331a8543bf48d09add56d7fe4b1cbbb5659&dn=Twenty+Years+in+Jail%3A+FreeBSD's+Jails%2C+Then+and+Now&tr=wss%3A%2F%2Fpeertube.social%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.social%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.social%2Fstatic%2Fwebseed%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-240.mp4",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"type": "Link"
},
{
"fps": 30,
"height": 360,
"href": "https://peertube.social/static/webseed/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-360.mp4",
"mediaType": "video/mp4",
"size": 143930318,
"type": "Link"
},
{
"height": 360,
"href": "https://peertube.social/static/torrents/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-360.torrent",
"mediaType": "application/x-bittorrent",
"type": "Link"
},
{
"height": 360,
"href": "magnet:?xs=https%3A%2F%2Fpeertube.social%2Fstatic%2Ftorrents%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-360.torrent&xt=urn:btih:0d37b23c98cb0d89e28b5dc8f49b3c97a041e569&dn=Twenty+Years+in+Jail%3A+FreeBSD's+Jails%2C+Then+and+Now&tr=wss%3A%2F%2Fpeertube.social%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.social%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.social%2Fstatic%2Fwebseed%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-360.mp4",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"type": "Link"
},
{
"fps": 30,
"height": 480,
"href": "https://peertube.social/static/webseed/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-480.mp4",
"mediaType": "video/mp4",
"size": 130530754,
"type": "Link"
},
{
"height": 480,
"href": "https://peertube.social/static/torrents/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-480.torrent",
"mediaType": "application/x-bittorrent",
"type": "Link"
},
{
"height": 480,
"href": "magnet:?xs=https%3A%2F%2Fpeertube.social%2Fstatic%2Ftorrents%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-480.torrent&xt=urn:btih:3a13ff822ad9494165eff6167183ddaaabc1372a&dn=Twenty+Years+in+Jail%3A+FreeBSD's+Jails%2C+Then+and+Now&tr=wss%3A%2F%2Fpeertube.social%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.social%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.social%2Fstatic%2Fwebseed%2F278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe-480.mp4",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"type": "Link"
}
],
"uuid": "278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe",
"views": 2,
"waitTranscoding": false
}

41
test/fixtures/users_mock/localhost.json vendored Normal file
View file

@ -0,0 +1,41 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"http://localhost:4001/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"attachment": [],
"endpoints": {
"oauthAuthorizationEndpoint": "http://localhost:4001/oauth/authorize",
"oauthRegistrationEndpoint": "http://localhost:4001/api/v1/apps",
"oauthTokenEndpoint": "http://localhost:4001/oauth/token",
"sharedInbox": "http://localhost:4001/inbox"
},
"followers": "http://localhost:4001/users/{{nickname}}/followers",
"following": "http://localhost:4001/users/{{nickname}}/following",
"icon": {
"type": "Image",
"url": "http://localhost:4001/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"
},
"id": "http://localhost:4001/users/{{nickname}}",
"image": {
"type": "Image",
"url": "http://localhost:4001/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"
},
"inbox": "http://localhost:4001/users/{{nickname}}/inbox",
"manuallyApprovesFollowers": false,
"name": "{{nickname}}",
"outbox": "http://localhost:4001/users/{{nickname}}/outbox",
"preferredUsername": "{{nickname}}",
"publicKey": {
"id": "http://localhost:4001/users/{{nickname}}#main-key",
"owner": "http://localhost:4001/users/{{nickname}}",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"
},
"summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts",
"tag": [],
"type": "Person",
"url": "http://localhost:4001/users/{{nickname}}"
}

View file

@ -0,0 +1 @@
21.1

View file

@ -0,0 +1 @@
22.1

View file

@ -0,0 +1 @@
22.4

View file

@ -0,0 +1 @@
23.0

View file

@ -15,28 +15,28 @@ defmodule Pleroma.FollowingRelationshipTest do
test "returns following addresses without internal.fetch" do
user = insert(:user)
fetch_actor = InternalFetchActor.get_actor()
FollowingRelationship.follow(fetch_actor, user, "accept")
FollowingRelationship.follow(fetch_actor, user, :follow_accept)
assert FollowingRelationship.following(fetch_actor) == [user.follower_address]
end
test "returns following addresses without relay" do
user = insert(:user)
relay_actor = Relay.get_actor()
FollowingRelationship.follow(relay_actor, user, "accept")
FollowingRelationship.follow(relay_actor, user, :follow_accept)
assert FollowingRelationship.following(relay_actor) == [user.follower_address]
end
test "returns following addresses without remote user" do
user = insert(:user)
actor = insert(:user, local: false)
FollowingRelationship.follow(actor, user, "accept")
FollowingRelationship.follow(actor, user, :follow_accept)
assert FollowingRelationship.following(actor) == [user.follower_address]
end
test "returns following addresses with local user" do
user = insert(:user)
actor = insert(:user, local: true)
FollowingRelationship.follow(actor, user, "accept")
FollowingRelationship.follow(actor, user, :follow_accept)
assert FollowingRelationship.following(actor) == [
actor.follower_address,

View file

@ -140,7 +140,7 @@ defmodule Pleroma.FormatterTest do
archaeme =
insert(:user,
nickname: "archa_eme_",
source_data: %{"url" => "https://archeme/@archa_eme_"}
uri: "https://archeme/@archa_eme_"
)
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
@ -150,13 +150,13 @@ defmodule Pleroma.FormatterTest do
assert length(mentions) == 3
expected_text =
~s(<span class="h-card"><a data-user="#{gsimg.id}" class="u-url mention" href="#{
~s(<span class="h-card"><a class="u-url mention" data-user="#{gsimg.id}" href="#{
gsimg.ap_id
}" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a data-user="#{
}" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a class="u-url mention" data-user="#{
archaeme.id
}" class="u-url mention" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a data-user="#{
}" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a class="u-url mention" data-user="#{
archaeme_remote.id
}" class="u-url mention" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>)
}" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>)
assert expected_text == text
end
@ -171,7 +171,7 @@ defmodule Pleroma.FormatterTest do
assert length(mentions) == 1
expected_text =
~s(<span class="h-card"><a data-user="#{mike.id}" class="u-url mention" href="#{
~s(<span class="h-card"><a class="u-url mention" data-user="#{mike.id}" href="#{
mike.ap_id
}" rel="ugc">@<span>mike</span></a></span> test)
@ -187,7 +187,7 @@ defmodule Pleroma.FormatterTest do
assert length(mentions) == 1
expected_text =
~s(<span class="h-card"><a data-user="#{o.id}" class="u-url mention" href="#{o.ap_id}" rel="ugc">@<span>o</span></a></span> hi)
~s(<span class="h-card"><a class="u-url mention" data-user="#{o.id}" href="#{o.ap_id}" rel="ugc">@<span>o</span></a></span> hi)
assert expected_text == text
end
@ -209,17 +209,13 @@ defmodule Pleroma.FormatterTest do
assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}]
assert expected_text ==
~s(<span class="h-card"><a data-user="#{user.id}" class="u-url mention" href="#{
~s(<span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="#{
user.ap_id
}" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a data-user="#{
}" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{
other_user.id
}" class="u-url mention" href="#{other_user.ap_id}" rel="ugc">@<span>#{
other_user.nickname
}</span></a></span> hey dudes i hate <span class="h-card"><a data-user="#{
}" href="#{other_user.ap_id}" rel="ugc">@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class="h-card"><a class="u-url mention" data-user="#{
third_user.id
}" class="u-url mention" href="#{third_user.ap_id}" rel="ugc">@<span>#{
third_user.nickname
}</span></a></span>)
}" href="#{third_user.ap_id}" rel="ugc">@<span>#{third_user.nickname}</span></a></span>)
end
test "given the 'safe_mention' option, it will still work without any mention" do

View file

@ -171,7 +171,7 @@ defmodule Pleroma.HTMLTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
status:
"I think I just found the best github repo https://github.com/komeiji-satori/Dress"
})
@ -186,7 +186,7 @@ defmodule Pleroma.HTMLTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
status:
"@#{other_user.nickname} install misskey! https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md"
})
@ -203,8 +203,7 @@ defmodule Pleroma.HTMLTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
"#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"
status: "#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"
})
object = Object.normalize(activity)
@ -218,9 +217,9 @@ defmodule Pleroma.HTMLTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
status:
"<a href=\"https://pleroma.gov/tags/cofe\" rel=\"tag\">#cofe</a> https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140",
"content_type" => "text/html"
content_type: "text/html"
})
object = Object.normalize(activity)
@ -232,8 +231,7 @@ defmodule Pleroma.HTMLTest do
test "does not crash when there is an HTML entity in a link" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{"status" => "\"http://cofe.com/?boomer=ok&foo=bar\""})
{:ok, activity} = CommonAPI.post(user, %{status: "\"http://cofe.com/?boomer=ok&foo=bar\""})
object = Object.normalize(activity)

View file

@ -0,0 +1,258 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.GunTest do
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
import Mox
alias Pleroma.Config
alias Pleroma.Gun.Conn
alias Pleroma.HTTP.AdapterHelper.Gun
alias Pleroma.Pool.Connections
setup :verify_on_exit!
defp gun_mock(_) do
gun_mock()
:ok
end
defp gun_mock do
Pleroma.GunMock
|> stub(:open, fn _, _, _ -> Task.start_link(fn -> Process.sleep(1000) end) end)
|> stub(:await_up, fn _, _ -> {:ok, :http} end)
|> stub(:set_owner, fn _, _ -> :ok end)
end
describe "options/1" do
setup do: clear_config([:http, :adapter], a: 1, b: 2)
test "https url with default port" do
uri = URI.parse("https://example.com")
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
assert opts[:tls_opts][:log_level] == :warning
end
test "https ipv4 with default port" do
uri = URI.parse("https://127.0.0.1")
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
assert opts[:tls_opts][:log_level] == :warning
end
test "https ipv6 with default port" do
uri = URI.parse("https://[2a03:2880:f10c:83:face:b00c:0:25de]")
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
assert opts[:tls_opts][:log_level] == :warning
end
test "https url with non standart port" do
uri = URI.parse("https://example.com:115")
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
end
test "get conn on next request" do
gun_mock()
level = Application.get_env(:logger, :level)
Logger.configure(level: :debug)
on_exit(fn -> Logger.configure(level: level) end)
uri = URI.parse("http://some-domain2.com")
opts = Gun.options(uri)
assert opts[:conn] == nil
assert opts[:close_conn] == nil
Process.sleep(50)
opts = Gun.options(uri)
assert is_pid(opts[:conn])
assert opts[:close_conn] == false
end
test "merges with defaul http adapter config" do
defaults = Gun.options([receive_conn: false], URI.parse("https://example.com"))
assert Keyword.has_key?(defaults, :a)
assert Keyword.has_key?(defaults, :b)
end
test "default ssl adapter opts with connection" do
gun_mock()
uri = URI.parse("https://some-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
assert opts[:certificates_verification]
refute opts[:tls_opts] == []
assert opts[:close_conn] == false
assert is_pid(opts[:conn])
end
test "parses string proxy host & port" do
proxy = Config.get([:http, :proxy_url])
Config.put([:http, :proxy_url], "localhost:8123")
on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
assert opts[:proxy] == {'localhost', 8123}
end
test "parses tuple proxy scheme host and port" do
proxy = Config.get([:http, :proxy_url])
Config.put([:http, :proxy_url], {:socks, 'localhost', 1234})
on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
assert opts[:proxy] == {:socks, 'localhost', 1234}
end
test "passed opts have more weight than defaults" do
proxy = Config.get([:http, :proxy_url])
Config.put([:http, :proxy_url], {:socks5, 'localhost', 1234})
on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri)
assert opts[:proxy] == {'example.com', 4321}
end
end
describe "options/1 with receive_conn parameter" do
setup :gun_mock
test "receive conn by default" do
uri = URI.parse("http://another-domain.com")
:ok = Conn.open(uri, :gun_connections)
received_opts = Gun.options(uri)
assert received_opts[:close_conn] == false
assert is_pid(received_opts[:conn])
end
test "don't receive conn if receive_conn is false" do
uri = URI.parse("http://another-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = [receive_conn: false]
received_opts = Gun.options(opts, uri)
assert received_opts[:close_conn] == nil
assert received_opts[:conn] == nil
end
end
describe "after_request/1" do
setup :gun_mock
test "body_as not chunks" do
uri = URI.parse("http://some-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
:ok = Gun.after_request(opts)
conn = opts[:conn]
assert %Connections{
conns: %{
"http:some-domain.com:80" => %Pleroma.Gun.Conn{
conn: ^conn,
conn_state: :idle,
used_by: []
}
}
} = Connections.get_state(:gun_connections)
end
test "body_as chunks" do
uri = URI.parse("http://some-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options([body_as: :chunks], uri)
:ok = Gun.after_request(opts)
conn = opts[:conn]
self = self()
assert %Connections{
conns: %{
"http:some-domain.com:80" => %Pleroma.Gun.Conn{
conn: ^conn,
conn_state: :active,
used_by: [{^self, _}]
}
}
} = Connections.get_state(:gun_connections)
end
test "with no connection" do
uri = URI.parse("http://uniq-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options([body_as: :chunks], uri)
conn = opts[:conn]
opts = Keyword.delete(opts, :conn)
self = self()
:ok = Gun.after_request(opts)
assert %Connections{
conns: %{
"http:uniq-domain.com:80" => %Pleroma.Gun.Conn{
conn: ^conn,
conn_state: :active,
used_by: [{^self, _}]
}
}
} = Connections.get_state(:gun_connections)
end
test "with ipv4" do
uri = URI.parse("http://127.0.0.1")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
:ok = Gun.after_request(opts)
conn = opts[:conn]
assert %Connections{
conns: %{
"http:127.0.0.1:80" => %Pleroma.Gun.Conn{
conn: ^conn,
conn_state: :idle,
used_by: []
}
}
} = Connections.get_state(:gun_connections)
end
test "with ipv6" do
uri = URI.parse("http://[2a03:2880:f10c:83:face:b00c:0:25de]")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
:ok = Gun.after_request(opts)
conn = opts[:conn]
assert %Connections{
conns: %{
"http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Pleroma.Gun.Conn{
conn: ^conn,
conn_state: :idle,
used_by: []
}
}
} = Connections.get_state(:gun_connections)
end
end
end

View file

@ -0,0 +1,47 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
alias Pleroma.HTTP.AdapterHelper.Hackney
setup_all do
uri = URI.parse("http://domain.com")
{:ok, uri: uri}
end
describe "options/2" do
setup do: clear_config([:http, :adapter], a: 1, b: 2)
test "add proxy and opts from config", %{uri: uri} do
opts = Hackney.options([proxy: "localhost:8123"], uri)
assert opts[:a] == 1
assert opts[:b] == 2
assert opts[:proxy] == "localhost:8123"
end
test "respect connection opts and no proxy", %{uri: uri} do
opts = Hackney.options([a: 2, b: 1], uri)
assert opts[:a] == 2
assert opts[:b] == 1
refute Keyword.has_key?(opts, :proxy)
end
test "add opts for https" do
uri = URI.parse("https://domain.com")
opts = Hackney.options(uri)
assert opts[:ssl_options] == [
partial_chain: &:hackney_connect.partial_chain/1,
versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
server_name_indication: 'domain.com'
]
end
end
end

View file

@ -0,0 +1,28 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelperTest do
use ExUnit.Case, async: true
alias Pleroma.HTTP.AdapterHelper
describe "format_proxy/1" do
test "with nil" do
assert AdapterHelper.format_proxy(nil) == nil
end
test "with string" do
assert AdapterHelper.format_proxy("127.0.0.1:8123") == {{127, 0, 0, 1}, 8123}
end
test "localhost with port" do
assert AdapterHelper.format_proxy("localhost:8123") == {'localhost', 8123}
end
test "tuple" do
assert AdapterHelper.format_proxy({:socks4, :localhost, 9050}) ==
{:socks4, 'localhost', 9050}
end
end
end

View file

@ -0,0 +1,135 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.ConnectionTest do
use ExUnit.Case
use Pleroma.Tests.Helpers
import ExUnit.CaptureLog
alias Pleroma.Config
alias Pleroma.HTTP.Connection
describe "parse_host/1" do
test "as atom to charlist" do
assert Connection.parse_host(:localhost) == 'localhost'
end
test "as string to charlist" do
assert Connection.parse_host("localhost.com") == 'localhost.com'
end
test "as string ip to tuple" do
assert Connection.parse_host("127.0.0.1") == {127, 0, 0, 1}
end
end
describe "parse_proxy/1" do
test "ip with port" do
assert Connection.parse_proxy("127.0.0.1:8123") == {:ok, {127, 0, 0, 1}, 8123}
end
test "host with port" do
assert Connection.parse_proxy("localhost:8123") == {:ok, 'localhost', 8123}
end
test "as tuple" do
assert Connection.parse_proxy({:socks4, :localhost, 9050}) ==
{:ok, :socks4, 'localhost', 9050}
end
test "as tuple with string host" do
assert Connection.parse_proxy({:socks5, "localhost", 9050}) ==
{:ok, :socks5, 'localhost', 9050}
end
end
describe "parse_proxy/1 errors" do
test "ip without port" do
capture_log(fn ->
assert Connection.parse_proxy("127.0.0.1") == {:error, :invalid_proxy}
end) =~ "parsing proxy fail \"127.0.0.1\""
end
test "host without port" do
capture_log(fn ->
assert Connection.parse_proxy("localhost") == {:error, :invalid_proxy}
end) =~ "parsing proxy fail \"localhost\""
end
test "host with bad port" do
capture_log(fn ->
assert Connection.parse_proxy("localhost:port") == {:error, :invalid_proxy_port}
end) =~ "parsing port in proxy fail \"localhost:port\""
end
test "ip with bad port" do
capture_log(fn ->
assert Connection.parse_proxy("127.0.0.1:15.9") == {:error, :invalid_proxy_port}
end) =~ "parsing port in proxy fail \"127.0.0.1:15.9\""
end
test "as tuple without port" do
capture_log(fn ->
assert Connection.parse_proxy({:socks5, :localhost}) == {:error, :invalid_proxy}
end) =~ "parsing proxy fail {:socks5, :localhost}"
end
test "with nil" do
assert Connection.parse_proxy(nil) == nil
end
end
describe "options/3" do
setup do: clear_config([:http, :proxy_url])
test "without proxy_url in config" do
Config.delete([:http, :proxy_url])
opts = Connection.options(%URI{})
refute Keyword.has_key?(opts, :proxy)
end
test "parses string proxy host & port" do
Config.put([:http, :proxy_url], "localhost:8123")
opts = Connection.options(%URI{})
assert opts[:proxy] == {'localhost', 8123}
end
test "parses tuple proxy scheme host and port" do
Config.put([:http, :proxy_url], {:socks, 'localhost', 1234})
opts = Connection.options(%URI{})
assert opts[:proxy] == {:socks, 'localhost', 1234}
end
test "passed opts have more weight than defaults" do
Config.put([:http, :proxy_url], {:socks5, 'localhost', 1234})
opts = Connection.options(%URI{}, proxy: {'example.com', 4321})
assert opts[:proxy] == {'example.com', 4321}
end
end
describe "format_host/1" do
test "with domain" do
assert Connection.format_host("example.com") == 'example.com'
end
test "with idna domain" do
assert Connection.format_host("ですexample.com") == 'xn--example-183fne.com'
end
test "with ipv4" do
assert Connection.format_host("127.0.0.1") == '127.0.0.1'
end
test "with ipv6" do
assert Connection.format_host("2a03:2880:f10c:83:face:b00c:0:25de") ==
'2a03:2880:f10c:83:face:b00c:0:25de'
end
end
end

View file

@ -3,57 +3,38 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.RequestBuilderTest do
use ExUnit.Case, async: true
use ExUnit.Case
use Pleroma.Tests.Helpers
alias Pleroma.HTTP.Request
alias Pleroma.HTTP.RequestBuilder
describe "headers/2" do
setup do: clear_config([:http, :send_user_agent])
setup do: clear_config([:http, :user_agent])
test "don't send pleroma user agent" do
assert RequestBuilder.headers(%{}, []) == %{headers: []}
assert RequestBuilder.headers(%Request{}, []) == %Request{headers: []}
end
test "send pleroma user agent" do
Pleroma.Config.put([:http, :send_user_agent], true)
Pleroma.Config.put([:http, :user_agent], :default)
clear_config([:http, :send_user_agent], true)
clear_config([:http, :user_agent], :default)
assert RequestBuilder.headers(%{}, []) == %{
headers: [{"User-Agent", Pleroma.Application.user_agent()}]
assert RequestBuilder.headers(%Request{}, []) == %Request{
headers: [{"user-agent", Pleroma.Application.user_agent()}]
}
end
test "send custom user agent" do
Pleroma.Config.put([:http, :send_user_agent], true)
Pleroma.Config.put([:http, :user_agent], "totally-not-pleroma")
clear_config([:http, :send_user_agent], true)
clear_config([:http, :user_agent], "totally-not-pleroma")
assert RequestBuilder.headers(%{}, []) == %{
headers: [{"User-Agent", "totally-not-pleroma"}]
assert RequestBuilder.headers(%Request{}, []) == %Request{
headers: [{"user-agent", "totally-not-pleroma"}]
}
end
end
describe "add_optional_params/3" do
test "don't add if keyword is empty" do
assert RequestBuilder.add_optional_params(%{}, %{}, []) == %{}
end
test "add query parameter" do
assert RequestBuilder.add_optional_params(
%{},
%{query: :query, body: :body, another: :val},
[
{:query, "param1=val1&param2=val2"},
{:body, "some body"}
]
) == %{query: "param1=val1&param2=val2", body: "some body"}
end
end
describe "add_param/4" do
test "add file parameter" do
%{
%Request{
body: %Tesla.Multipart{
boundary: _,
content_type_params: [],
@ -70,7 +51,7 @@ defmodule Pleroma.HTTP.RequestBuilderTest do
}
]
}
} = RequestBuilder.add_param(%{}, :file, "filename.png", "some-path/filename.png")
} = RequestBuilder.add_param(%Request{}, :file, "filename.png", "some-path/filename.png")
end
test "add key to body" do
@ -82,7 +63,7 @@ defmodule Pleroma.HTTP.RequestBuilderTest do
%Tesla.Multipart.Part{
body: "\"someval\"",
dispositions: [name: "somekey"],
headers: ["Content-Type": "application/json"]
headers: [{"content-type", "application/json"}]
}
]
}

View file

@ -3,8 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTPTest do
use Pleroma.DataCase
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
import Tesla.Mock
alias Pleroma.HTTP
setup do
mock(fn
@ -27,7 +29,7 @@ defmodule Pleroma.HTTPTest do
describe "get/1" do
test "returns successfully result" do
assert Pleroma.HTTP.get("http://example.com/hello") == {
assert HTTP.get("http://example.com/hello") == {
:ok,
%Tesla.Env{status: 200, body: "hello"}
}
@ -36,7 +38,7 @@ defmodule Pleroma.HTTPTest do
describe "get/2 (with headers)" do
test "returns successfully result for json content-type" do
assert Pleroma.HTTP.get("http://example.com/hello", [{"content-type", "application/json"}]) ==
assert HTTP.get("http://example.com/hello", [{"content-type", "application/json"}]) ==
{
:ok,
%Tesla.Env{
@ -50,7 +52,7 @@ defmodule Pleroma.HTTPTest do
describe "post/2" do
test "returns successfully result" do
assert Pleroma.HTTP.post("http://example.com/world", "") == {
assert HTTP.post("http://example.com/world", "") == {
:ok,
%Tesla.Env{status: 200, body: "world"}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

View file

@ -0,0 +1,13 @@
{
"pack": {
"license": "Test license",
"homepage": "https://pleroma.social",
"description": "Test description",
"can-download": true,
"share-files": true,
"download-sha256": "57482F30674FD3DE821FF48C81C00DA4D4AF1F300209253684ABA7075E5FC238"
},
"files": {
"blank": "blank.png"
}
}

View file

@ -1,13 +1,11 @@
{
"pack": {
"license": "Test license",
"homepage": "https://pleroma.social",
"description": "Test description",
"share-files": true
},
"files": {
"blank": "blank.png"
},
"pack": {
"description": "Test description",
"homepage": "https://pleroma.social",
"license": "Test license",
"share-files": true
}
}
}

View file

@ -3,14 +3,11 @@
"license": "Test license",
"homepage": "https://pleroma.social",
"description": "Test description",
"fallback-src": "https://nonshared-pack",
"fallback-src-sha256": "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF",
"share-files": false
},
"files": {
"blank": "blank.png"
}
}
}

View file

@ -12,17 +12,14 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth
@moduletag needs_streamer: true, capture_log: true
@path Pleroma.Web.Endpoint.url()
|> URI.parse()
|> Map.put(:scheme, "ws")
|> Map.put(:path, "/api/v1/streaming")
|> URI.to_string()
setup_all do
start_supervised(Pleroma.Web.Streamer.supervisor())
:ok
end
def start_socket(qs \\ nil, headers \\ []) do
path =
case qs do
@ -35,7 +32,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
test "refuses invalid requests" do
capture_log(fn ->
assert {:error, {400, _}} = start_socket()
assert {:error, {404, _}} = start_socket()
assert {:error, {404, _}} = start_socket("?stream=ncjdk")
Process.sleep(30)
end)
@ -43,8 +40,8 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
test "requires authentication and a valid token for protected streams" do
capture_log(fn ->
assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa")
assert {:error, {403, _}} = start_socket("?stream=user")
assert {:error, {401, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa")
assert {:error, {401, _}} = start_socket("?stream=user")
Process.sleep(30)
end)
end
@ -58,7 +55,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
test "receives well formatted events" do
user = insert(:user)
{:ok, _} = start_socket("?stream=public")
{:ok, activity} = CommonAPI.post(user, %{"status" => "nice echo chamber"})
{:ok, activity} = CommonAPI.post(user, %{status: "nice echo chamber"})
assert_receive {:text, raw_json}, 1_000
assert {:ok, json} = Jason.decode(raw_json)
@ -103,7 +100,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")
assert capture_log(fn ->
assert {:error, {403, "Forbidden"}} = start_socket("?stream=user")
assert {:error, {401, _}} = start_socket("?stream=user")
Process.sleep(30)
end) =~ ":badarg"
end
@ -112,7 +109,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")
assert capture_log(fn ->
assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification")
assert {:error, {401, _}} = start_socket("?stream=user:notification")
Process.sleep(30)
end) =~ ":badarg"
end
@ -121,7 +118,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
assert capture_log(fn ->
assert {:error, {403, "Forbidden"}} =
assert {:error, {401, _}} =
start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
Process.sleep(30)

View file

@ -8,12 +8,39 @@ defmodule Pleroma.MarkerTest do
import Pleroma.Factory
describe "multi_set_unread_count/3" do
test "returns multi" do
user = insert(:user)
assert %Ecto.Multi{
operations: [marker: {:run, _}, counters: {:run, _}]
} =
Marker.multi_set_last_read_id(
Ecto.Multi.new(),
user,
"notifications"
)
end
test "return empty multi" do
user = insert(:user)
multi = Ecto.Multi.new()
assert Marker.multi_set_last_read_id(multi, user, "home") == multi
end
end
describe "get_markers/2" do
test "returns user markers" do
user = insert(:user)
marker = insert(:marker, user: user)
insert(:notification, user: user)
insert(:notification, user: user)
insert(:marker, timeline: "home", user: user)
assert Marker.get_markers(user, ["notifications"]) == [refresh_record(marker)]
assert Marker.get_markers(
user,
["notifications"]
) == [%Marker{refresh_record(marker) | unread_count: 2}]
end
end

View file

@ -0,0 +1,11 @@
defmodule Pleroma.MFA.BackupCodesTest do
use Pleroma.DataCase
alias Pleroma.MFA.BackupCodes
test "generate backup codes" do
codes = BackupCodes.generate(number_of_codes: 2, length: 4)
assert [<<_::bytes-size(4)>>, <<_::bytes-size(4)>>] = codes
end
end

17
test/mfa/totp_test.exs Normal file
View file

@ -0,0 +1,17 @@
defmodule Pleroma.MFA.TOTPTest do
use Pleroma.DataCase
alias Pleroma.MFA.TOTP
test "create provisioning_uri to generate qrcode" do
uri =
TOTP.provisioning_uri("test-secrcet", "test@example.com",
issuer: "Plerome-42",
digits: 8,
period: 60
)
assert uri ==
"otpauth://totp/test@example.com?digits=8&issuer=Plerome-42&period=60&secret=test-secrcet"
end
end

52
test/mfa_test.exs Normal file
View file

@ -0,0 +1,52 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFATest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.MFA
describe "mfa_settings" do
test "returns settings user's" do
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: "xx", confirmed: true}
}
)
settings = MFA.mfa_settings(user)
assert match?(^settings, %{enabled: true, totp: true})
end
end
describe "generate backup codes" do
test "returns backup codes" do
user = insert(:user)
{:ok, [code1, code2]} = MFA.generate_backup_codes(user)
updated_user = refresh_record(user)
[hash1, hash2] = updated_user.multi_factor_authentication_settings.backup_codes
assert Pbkdf2.verify_pass(code1, hash1)
assert Pbkdf2.verify_pass(code2, hash2)
end
end
describe "invalidate_backup_code" do
test "invalid used code" do
user = insert(:user)
{:ok, _} = MFA.generate_backup_codes(user)
user = refresh_record(user)
assert length(user.multi_factor_authentication_settings.backup_codes) == 2
[hash_code | _] = user.multi_factor_authentication_settings.backup_codes
{:ok, user} = MFA.invalidate_backup_code(user, hash_code)
assert length(user.multi_factor_authentication_settings.backup_codes) == 1
end
end
end

View file

@ -6,12 +6,18 @@ defmodule Pleroma.NotificationTest do
use Pleroma.DataCase
import Pleroma.Factory
import Mock
alias Pleroma.FollowingRelationship
alias Pleroma.Notification
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.Push
alias Pleroma.Web.Streamer
describe "create_notifications" do
@ -19,8 +25,8 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"})
{:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "")
{:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
{:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "")
{:ok, [notification]} = Notification.create_notifications(activity)
@ -34,7 +40,7 @@ defmodule Pleroma.NotificationTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
})
{:ok, [notification, other_notification]} = Notification.create_notifications(activity)
@ -43,6 +49,9 @@ defmodule Pleroma.NotificationTest do
assert notified_ids == [other_user.id, third_user.id]
assert notification.activity_id == activity.id
assert other_notification.activity_id == activity.id
assert [%Pleroma.Marker{unread_count: 2}] =
Pleroma.Marker.get_markers(other_user, ["notifications"])
end
test "it creates a notification for subscribed users" do
@ -51,7 +60,7 @@ defmodule Pleroma.NotificationTest do
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
{:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
{:ok, [notification]} = Notification.create_notifications(status)
assert notification.user_id == subscriber.id
@ -64,12 +73,12 @@ defmodule Pleroma.NotificationTest do
User.subscribe(subscriber, other_user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
{:ok, _reply_activity} =
CommonAPI.post(other_user, %{
"status" => "test reply",
"in_reply_to_status_id" => activity.id
status: "test reply",
in_reply_to_status_id: activity.id
})
user_notifications = Notification.for_user(user)
@ -80,18 +89,96 @@ defmodule Pleroma.NotificationTest do
end
end
describe "CommonApi.post/2 notification-related functionality" do
test_with_mock "creates but does NOT send notification to blocker user",
Push,
[:passthrough],
[] do
user = insert(:user)
blocker = insert(:user)
{:ok, _user_relationship} = User.block(blocker, user)
{:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
blocker_id = blocker.id
assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
refute called(Push.send(:_))
end
test_with_mock "creates but does NOT send notification to notification-muter user",
Push,
[:passthrough],
[] do
user = insert(:user)
muter = insert(:user)
{:ok, _user_relationships} = User.mute(muter, user)
{:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
muter_id = muter.id
assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
refute called(Push.send(:_))
end
test_with_mock "creates but does NOT send notification to thread-muter user",
Push,
[:passthrough],
[] do
user = insert(:user)
thread_muter = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
{:ok, _} = CommonAPI.add_mute(thread_muter, activity)
{:ok, _same_context_activity} =
CommonAPI.post(user, %{
status: "hey-hey-hey @#{thread_muter.nickname}!",
in_reply_to_status_id: activity.id
})
[pre_mute_notification, post_mute_notification] =
Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
pre_mute_notification_id = pre_mute_notification.id
post_mute_notification_id = post_mute_notification.id
assert called(
Push.send(
:meck.is(fn
%Notification{id: ^pre_mute_notification_id} -> true
_ -> false
end)
)
)
refute called(
Push.send(
:meck.is(fn
%Notification{id: ^post_mute_notification_id} -> true
_ -> false
end)
)
)
end
end
describe "create_notification" do
@tag needs_streamer: true
test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
user = insert(:user)
task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
task_user_notification = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
Streamer.add_socket("user", %{transport_pid: task.pid, assigns: %{user: user}})
Streamer.add_socket(
"user:notification",
%{transport_pid: task_user_notification.pid, assigns: %{user: user}}
)
task =
Task.async(fn ->
Streamer.get_topic_and_add_socket("user", user)
assert_receive {:render_with_user, _, _, _}, 4_000
end)
task_user_notification =
Task.async(fn ->
Streamer.get_topic_and_add_socket("user:notification", user)
assert_receive {:render_with_user, _, _, _}, 4_000
end)
activity = insert(:note_activity)
@ -115,7 +202,7 @@ defmodule Pleroma.NotificationTest do
muted = insert(:user)
{:ok, _} = User.mute(muter, muted)
muter = Repo.get(User, muter.id)
{:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
{:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
assert Notification.create_notification(activity, muter)
end
@ -126,7 +213,7 @@ defmodule Pleroma.NotificationTest do
{:ok, _user_relationships} = User.mute(muter, muted, false)
{:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
{:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
assert Notification.create_notification(activity, muter)
end
@ -134,13 +221,13 @@ defmodule Pleroma.NotificationTest do
test "it creates a notification for an activity from a muted thread" do
muter = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"})
{:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
CommonAPI.add_mute(muter, activity)
{:ok, activity} =
CommonAPI.post(other_user, %{
"status" => "Hi @#{muter.nickname}",
"in_reply_to_status_id" => activity.id
status: "Hi @#{muter.nickname}",
in_reply_to_status_id: activity.id
})
assert Notification.create_notification(activity, muter)
@ -153,7 +240,7 @@ defmodule Pleroma.NotificationTest do
insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
User.follow(follower, followed)
{:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
{:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
refute Notification.create_notification(activity, followed)
end
@ -165,7 +252,7 @@ defmodule Pleroma.NotificationTest do
notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
)
{:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
{:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
refute Notification.create_notification(activity, followed)
end
@ -176,7 +263,7 @@ defmodule Pleroma.NotificationTest do
followed = insert(:user)
User.follow(follower, followed)
follower = Repo.get(User, follower.id)
{:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
{:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
refute Notification.create_notification(activity, follower)
end
@ -185,7 +272,7 @@ defmodule Pleroma.NotificationTest do
insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
followed = insert(:user)
{:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
{:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
refute Notification.create_notification(activity, follower)
end
@ -196,23 +283,13 @@ defmodule Pleroma.NotificationTest do
refute Notification.create_notification(activity, author)
end
test "it doesn't create a notification for follow-unfollow-follow chains" do
user = insert(:user)
followed_user = insert(:user)
{:ok, _, _, activity} = CommonAPI.follow(user, followed_user)
Notification.create_notification(activity, followed_user)
CommonAPI.unfollow(user, followed_user)
{:ok, _, _, activity_dupe} = CommonAPI.follow(user, followed_user)
refute Notification.create_notification(activity_dupe, followed_user)
end
test "it doesn't create duplicate notifications for follow+subscribed users" do
user = insert(:user)
subscriber = insert(:user)
{:ok, _, _, _} = CommonAPI.follow(subscriber, user)
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
{:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
{:ok, [_notif]} = Notification.create_notifications(status)
end
@ -222,18 +299,78 @@ defmodule Pleroma.NotificationTest do
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{"status" => "inwisible", "visibility" => "direct"})
{:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
assert {:ok, []} == Notification.create_notifications(status)
end
end
describe "follow / follow_request notifications" do
test "it creates `follow` notification for approved Follow activity" do
user = insert(:user)
followed_user = insert(:user, locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
assert %{type: "follow"} =
NotificationView.render("show.json", %{
notification: notification,
for: followed_user
})
end
test "it creates `follow_request` notification for pending Follow activity" do
user = insert(:user)
followed_user = insert(:user, locked: true)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
refute FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
render_opts = %{notification: notification, for: followed_user}
assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
# After request is accepted, the same notification is rendered with type "follow":
assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
notification_id = notification.id
assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
assert %{type: "follow"} = NotificationView.render("show.json", render_opts)
end
test "it doesn't create a notification for follow-unfollow-follow chains" do
user = insert(:user)
followed_user = insert(:user, locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
CommonAPI.unfollow(user, followed_user)
{:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
notification_id = notification.id
assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
end
test "dismisses the notification on follow request rejection" do
user = insert(:user, locked: true)
follower = insert(:user)
{:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
assert [notification] = Notification.for_user(user)
{:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
assert [] = Notification.for_user(user)
end
end
describe "get notification" do
test "it gets a notification that belongs to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.get(other_user, notification.id)
@ -245,7 +382,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.get(user, notification.id)
@ -257,7 +394,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.dismiss(other_user, notification.id)
@ -269,7 +406,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.dismiss(user, notification.id)
@ -284,14 +421,14 @@ defmodule Pleroma.NotificationTest do
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
})
{:ok, _notifs} = Notification.create_notifications(activity)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
})
{:ok, _notifs} = Notification.create_notifications(activity)
@ -309,12 +446,12 @@ defmodule Pleroma.NotificationTest do
{:ok, _activity} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname}!"
status: "hey @#{other_user.nickname}!"
})
{:ok, _activity} =
CommonAPI.post(user, %{
"status" => "hey again @#{other_user.nickname}!"
status: "hey again @#{other_user.nickname}!"
})
[n2, n1] = notifs = Notification.for_user(other_user)
@ -324,7 +461,7 @@ defmodule Pleroma.NotificationTest do
{:ok, _activity} =
CommonAPI.post(user, %{
"status" => "hey yet again @#{other_user.nickname}!"
status: "hey yet again @#{other_user.nickname}!"
})
Notification.set_read_up_to(other_user, n2.id)
@ -334,6 +471,16 @@ defmodule Pleroma.NotificationTest do
assert n1.seen == true
assert n2.seen == true
assert n3.seen == false
assert %Pleroma.Marker{} =
m =
Pleroma.Repo.get_by(
Pleroma.Marker,
user_id: other_user.id,
timeline: "notifications"
)
assert m.last_read_id == to_string(n2.id)
end
end
@ -353,7 +500,7 @@ defmodule Pleroma.NotificationTest do
Enum.each(0..10, fn i ->
{:ok, _activity} =
CommonAPI.post(user1, %{
"status" => "hey ##{i} @#{user2.nickname}!"
status: "hey ##{i} @#{user2.nickname}!"
})
end)
@ -382,17 +529,19 @@ defmodule Pleroma.NotificationTest do
end
end
describe "notification target determination" do
describe "notification target determination / get_notified_from_activity/2" do
test "it sends notifications to addressed users in new messages" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname}!"
status: "hey @#{other_user.nickname}!"
})
assert other_user in Notification.get_notified_from_activity(activity)
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
assert other_user in enabled_receivers
end
test "it sends notifications to mentioned users in new messages" do
@ -420,7 +569,9 @@ defmodule Pleroma.NotificationTest do
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
assert other_user in Notification.get_notified_from_activity(activity)
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
assert other_user in enabled_receivers
end
test "it does not send notifications to users who are only cc in new messages" do
@ -442,7 +593,9 @@ defmodule Pleroma.NotificationTest do
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
assert other_user not in Notification.get_notified_from_activity(activity)
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
assert other_user not in enabled_receivers
end
test "it does not send notification to mentioned users in likes" do
@ -452,12 +605,37 @@ defmodule Pleroma.NotificationTest do
{:ok, activity_one} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname}!"
status: "hey @#{other_user.nickname}!"
})
{:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
{:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
assert other_user not in Notification.get_notified_from_activity(activity_two)
{enabled_receivers, _disabled_receivers} =
Notification.get_notified_from_activity(activity_two)
assert other_user not in enabled_receivers
end
test "it only notifies the post's author in likes" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, like_data, _} = Builder.like(third_user, activity_one.object)
{:ok, like, _} =
like_data
|> Map.put("to", [other_user.ap_id | like_data["to"]])
|> ActivityPub.persist(local: true)
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
assert other_user not in enabled_receivers
end
test "it does not send notification to mentioned users in announces" do
@ -467,12 +645,93 @@ defmodule Pleroma.NotificationTest do
{:ok, activity_one} =
CommonAPI.post(user, %{
"status" => "hey @#{other_user.nickname}!"
status: "hey @#{other_user.nickname}!"
})
{:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user)
assert other_user not in Notification.get_notified_from_activity(activity_two)
{enabled_receivers, _disabled_receivers} =
Notification.get_notified_from_activity(activity_two)
assert other_user not in enabled_receivers
end
test "it returns blocking recipient in disabled recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, _user_relationship} = User.block(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
assert [other_user] == disabled_receivers
end
test "it returns notification-muting recipient in disabled recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, _user_relationships} = User.mute(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
assert [other_user] == disabled_receivers
end
test "it returns thread-muting recipient in disabled recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{:ok, _} = CommonAPI.add_mute(other_user, activity)
{:ok, same_context_activity} =
CommonAPI.post(user, %{
status: "hey-hey-hey @#{other_user.nickname}!",
in_reply_to_status_id: activity.id
})
{enabled_receivers, disabled_receivers} =
Notification.get_notified_from_activity(same_context_activity)
assert [other_user] == disabled_receivers
refute other_user in enabled_receivers
end
test "it returns non-following domain-blocking recipient in disabled recipients list" do
blocked_domain = "blocked.domain"
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
other_user = insert(:user)
{:ok, other_user} = User.block_domain(other_user, blocked_domain)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
assert [other_user] == disabled_receivers
end
test "it returns following domain-blocking recipient in enabled recipients list" do
blocked_domain = "blocked.domain"
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
other_user = insert(:user)
{:ok, other_user} = User.block_domain(other_user, blocked_domain)
{:ok, other_user} = User.follow(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
assert [other_user] == enabled_receivers
assert [] == disabled_receivers
end
end
@ -481,11 +740,11 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
{:ok, _} = CommonAPI.favorite(other_user, activity.id)
assert length(Notification.for_user(user)) == 1
@ -498,15 +757,15 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
{:ok, _} = CommonAPI.favorite(other_user, activity.id)
assert length(Notification.for_user(user)) == 1
{:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user)
{:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
@ -515,7 +774,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
@ -532,7 +791,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
@ -540,7 +799,7 @@ defmodule Pleroma.NotificationTest do
assert length(Notification.for_user(user)) == 1
{:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user)
{:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
@ -549,7 +808,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
@ -557,7 +816,7 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user))
{:error, _} = CommonAPI.favorite(activity.id, other_user)
{:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
assert Enum.empty?(Notification.for_user(user))
end
@ -566,7 +825,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
@ -583,13 +842,13 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
{:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
{:ok, _reply_activity} =
CommonAPI.post(other_user, %{
"status" => "test reply",
"in_reply_to_status_id" => activity.id
status: "test reply",
in_reply_to_status_id: activity.id
})
assert Enum.empty?(Notification.for_user(user))
@ -600,7 +859,7 @@ defmodule Pleroma.NotificationTest do
other_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}", "visibility" => "direct"})
CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
refute Enum.empty?(Notification.for_user(other_user))
@ -649,12 +908,20 @@ defmodule Pleroma.NotificationTest do
"object" => remote_user.ap_id
}
remote_user_url = remote_user.ap_id
Tesla.Mock.mock(fn
%{method: :get, url: ^remote_user_url} ->
%Tesla.Env{status: 404, body: ""}
end)
{:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
ObanHelpers.perform_all()
assert Enum.empty?(Notification.for_user(local_user))
end
@tag capture_log: true
test "move activity generates a notification" do
%{ap_id: old_ap_id} = old_user = insert(:user)
%{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
@ -664,6 +931,18 @@ defmodule Pleroma.NotificationTest do
User.follow(follower, old_user)
User.follow(other_follower, old_user)
old_user_url = old_user.ap_id
body =
File.read!("test/fixtures/users_mock/localhost.json")
|> String.replace("{{nickname}}", old_user.nickname)
|> Jason.encode!()
Tesla.Mock.mock(fn
%{method: :get, url: ^old_user_url} ->
%Tesla.Env{status: 200, body: body}
end)
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
ObanHelpers.perform_all()
@ -691,7 +970,7 @@ defmodule Pleroma.NotificationTest do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted, false)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
assert length(Notification.for_user(user)) == 1
end
@ -701,7 +980,7 @@ defmodule Pleroma.NotificationTest do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
@ -711,26 +990,38 @@ defmodule Pleroma.NotificationTest do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
test "it doesn't return notificatitons for blocked domain" do
test "it doesn't return notifications for domain-blocked non-followed user" do
user = insert(:user)
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
test "it returns notifications for domain-blocked but followed user" do
user = insert(:user)
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _} = User.follow(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert length(Notification.for_user(user)) == 1
end
test "it doesn't return notifications for muted thread" do
user = insert(:user)
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
{:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
assert Notification.for_user(user) == []
@ -741,7 +1032,7 @@ defmodule Pleroma.NotificationTest do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
assert length(Notification.for_user(user, %{with_muted: true})) == 1
end
@ -751,17 +1042,18 @@ defmodule Pleroma.NotificationTest do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end
test "it doesn't return notifications from a domain-blocked user when with_muted is set" do
test "when with_muted is set, " <>
"it doesn't return notifications from a domain-blocked non-followed user" do
user = insert(:user)
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end
@ -770,7 +1062,7 @@ defmodule Pleroma.NotificationTest do
user = insert(:user)
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
{:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
assert length(Notification.for_user(user, %{with_muted: true})) == 1

View file

@ -380,7 +380,8 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
activity = Activity.get_create_by_object_ap_id(object.data["id"])
{:ok, _activity, object} = CommonAPI.favorite(activity.id, user)
{:ok, activity} = CommonAPI.favorite(user, activity.id)
object = Object.get_by_ap_id(activity.data["object"])
assert object.data["like_count"] == 1

42
test/otp_version_test.exs Normal file
View file

@ -0,0 +1,42 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.OTPVersionTest do
use ExUnit.Case, async: true
alias Pleroma.OTPVersion
describe "check/1" do
test "22.4" do
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/22.4"]) ==
"22.4"
end
test "22.1" do
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/22.1"]) ==
"22.1"
end
test "21.1" do
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/21.1"]) ==
"21.1"
end
test "23.0" do
assert OTPVersion.get_version_from_files(["test/fixtures/warnings/otp_version/23.0"]) ==
"23.0"
end
test "with non existance file" do
assert OTPVersion.get_version_from_files([
"test/fixtures/warnings/otp_version/non-exising",
"test/fixtures/warnings/otp_version/22.4"
]) == "22.4"
end
test "empty paths" do
assert OTPVersion.get_version_from_files([]) == nil
end
end
end

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
use Pleroma.Web.ConnCase, async: true
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.PlugHelper
alias Pleroma.User
import ExUnit.CaptureLog
@ -14,7 +16,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
user = %User{
id: 1,
name: "dude",
password_hash: Comeonin.Pbkdf2.hashpwsalt("guy")
password_hash: Pbkdf2.hash_pwd_salt("guy")
}
conn =
@ -36,13 +38,16 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
assert ret_conn == conn
end
test "with a correct password in the credentials, it assigns the auth_user", %{conn: conn} do
test "with a correct password in the credentials, " <>
"it assigns the auth_user and marks OAuthScopesPlug as skipped",
%{conn: conn} do
conn =
conn
|> assign(:auth_credentials, %{password: "guy"})
|> AuthenticationPlug.call(%{})
assert conn.assigns.user == conn.assigns.auth_user
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
test "with a wrong password in the credentials, it does nothing", %{conn: conn} do
@ -74,6 +79,13 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
assert AuthenticationPlug.checkpw("password", hash)
end
test "check bcrypt hash" do
hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
assert AuthenticationPlug.checkpw("password", hash)
refute AuthenticationPlug.checkpw("password1", hash)
end
test "it returns false when hash invalid" do
hash =
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"

View file

@ -20,34 +20,61 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do
conn = assign(conn, :user, %User{})
ret_conn = EnsureAuthenticatedPlug.call(conn, %{})
assert ret_conn == conn
refute ret_conn.halted
end
end
test "it halts if user is assigned and MFA enabled", %{conn: conn} do
conn =
conn
|> assign(:user, %User{multi_factor_authentication_settings: %{enabled: true}})
|> assign(:auth_credentials, %{password: "xd-42"})
|> EnsureAuthenticatedPlug.call(%{})
assert conn.status == 403
assert conn.halted == true
assert conn.resp_body ==
"{\"error\":\"Two-factor authentication enabled, you must use a access token.\"}"
end
test "it continues if user is assigned and MFA disabled", %{conn: conn} do
conn =
conn
|> assign(:user, %User{multi_factor_authentication_settings: %{enabled: false}})
|> assign(:auth_credentials, %{password: "xd-42"})
|> EnsureAuthenticatedPlug.call(%{})
refute conn.status == 403
refute conn.halted
end
describe "with :if_func / :unless_func options" do
setup do
%{
true_fn: fn -> true end,
false_fn: fn -> false end
true_fn: fn _conn -> true end,
false_fn: fn _conn -> false end
}
end
test "it continues if a user is assigned", %{conn: conn, true_fn: true_fn, false_fn: false_fn} do
conn = assign(conn, :user, %User{})
assert EnsureAuthenticatedPlug.call(conn, if_func: true_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, unless_func: false_fn) == conn
refute EnsureAuthenticatedPlug.call(conn, if_func: true_fn).halted
refute EnsureAuthenticatedPlug.call(conn, if_func: false_fn).halted
refute EnsureAuthenticatedPlug.call(conn, unless_func: true_fn).halted
refute EnsureAuthenticatedPlug.call(conn, unless_func: false_fn).halted
end
test "it continues if a user is NOT assigned but :if_func evaluates to `false`",
%{conn: conn, false_fn: false_fn} do
assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn
ret_conn = EnsureAuthenticatedPlug.call(conn, if_func: false_fn)
refute ret_conn.halted
end
test "it continues if a user is NOT assigned but :unless_func evaluates to `true`",
%{conn: conn, true_fn: true_fn} do
assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn
ret_conn = EnsureAuthenticatedPlug.call(conn, unless_func: true_fn)
refute ret_conn.halted
end
test "it halts if a user is NOT assigned and :if_func evaluates to `true`",

View file

@ -29,7 +29,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do
conn
|> EnsurePublicOrAuthenticatedPlug.call(%{})
assert ret_conn == conn
refute ret_conn.halted
end
test "it continues if a user is assigned, even if not public", %{conn: conn} do
@ -43,6 +43,6 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do
conn
|> EnsurePublicOrAuthenticatedPlug.call(%{})
assert ret_conn == conn
refute ret_conn.halted
end
end

View file

@ -8,6 +8,8 @@ defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do
import Pleroma.Factory
alias Pleroma.Plugs.LegacyAuthenticationPlug
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.PlugHelper
alias Pleroma.User
setup do
@ -36,7 +38,8 @@ defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do
end
@tag :skip_on_mac
test "it authenticates the auth_user if present and password is correct and resets the password",
test "if `auth_user` is present and password is correct, " <>
"it authenticates the user, resets the password, marks OAuthScopesPlug as skipped",
%{
conn: conn,
user: user
@ -49,6 +52,7 @@ defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do
conn = LegacyAuthenticationPlug.call(conn, %{})
assert conn.assigns.user.id == user.id
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
@tag :skip_on_mac

View file

@ -5,15 +5,22 @@
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
setup_with_mocks([{EnsurePublicOrAuthenticatedPlug, [], [call: fn conn, _ -> conn end]}]) do
:ok
test "is not performed if marked as skipped", %{conn: conn} do
with_mock OAuthScopesPlug, [:passthrough], perform: &passthrough([&1, &2]) do
conn =
conn
|> OAuthScopesPlug.skip_plug()
|> OAuthScopesPlug.call(%{scopes: ["random_scope"]})
refute called(OAuthScopesPlug.perform(:_, :_))
refute conn.halted
end
end
test "if `token.scopes` fulfills specified 'any of' conditions, " <>
@ -48,7 +55,7 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
describe "with `fallback: :proceed_unauthenticated` option, " do
test "if `token.scopes` doesn't fulfill specified conditions, " <>
"clears :user and :token assigns and calls EnsurePublicOrAuthenticatedPlug",
"clears :user and :token assigns",
%{conn: conn} do
user = insert(:user)
token1 = insert(:oauth_token, scopes: ["read", "write"], user: user)
@ -67,35 +74,6 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
refute ret_conn.halted
refute ret_conn.assigns[:user]
refute ret_conn.assigns[:token]
assert called(EnsurePublicOrAuthenticatedPlug.call(ret_conn, :_))
end
end
test "with :skip_instance_privacy_check option, " <>
"if `token.scopes` doesn't fulfill specified conditions, " <>
"clears :user and :token assigns and does NOT call EnsurePublicOrAuthenticatedPlug",
%{conn: conn} do
user = insert(:user)
token1 = insert(:oauth_token, scopes: ["read:statuses", "write"], user: user)
for token <- [token1, nil], op <- [:|, :&] do
ret_conn =
conn
|> assign(:user, user)
|> assign(:token, token)
|> OAuthScopesPlug.call(%{
scopes: ["read"],
op: op,
fallback: :proceed_unauthenticated,
skip_instance_privacy_check: true
})
refute ret_conn.halted
refute ret_conn.assigns[:user]
refute ret_conn.assigns[:token]
refute called(EnsurePublicOrAuthenticatedPlug.call(ret_conn, :_))
end
end
end

View file

@ -5,8 +5,10 @@
defmodule Pleroma.Plugs.RateLimiterTest do
use Pleroma.Web.ConnCase
alias Phoenix.ConnTest
alias Pleroma.Config
alias Pleroma.Plugs.RateLimiter
alias Plug.Conn
import Pleroma.Factory
import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
@ -36,8 +38,15 @@ defmodule Pleroma.Plugs.RateLimiterTest do
end
test "it is disabled if it remote ip plug is enabled but no remote ip is found" do
Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
assert RateLimiter.disabled?(Plug.Conn.assign(build_conn(), :remote_ip_found, false))
assert RateLimiter.disabled?(Conn.assign(build_conn(), :remote_ip_found, false))
end
test "it is enabled if remote ip found" do
refute RateLimiter.disabled?(Conn.assign(build_conn(), :remote_ip_found, true))
end
test "it is enabled if remote_ip_found flag doesn't exist" do
refute RateLimiter.disabled?(build_conn())
end
test "it restricts based on config values" do
@ -58,7 +67,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
end
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
Process.sleep(50)
@ -68,7 +77,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
conn = RateLimiter.call(conn, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
refute conn.status == Plug.Conn.Status.code(:too_many_requests)
refute conn.status == Conn.Status.code(:too_many_requests)
refute conn.resp_body
refute conn.halted
end
@ -98,7 +107,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
plug_opts = RateLimiter.init(name: limiter_name, params: ["id"])
conn = build_conn(:get, "/?id=1")
conn = Plug.Conn.fetch_query_params(conn)
conn = Conn.fetch_query_params(conn)
conn_2 = build_conn(:get, "/?id=2")
RateLimiter.call(conn, plug_opts)
@ -119,7 +128,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
id = "100"
conn = build_conn(:get, "/?id=#{id}")
conn = Plug.Conn.fetch_query_params(conn)
conn = Conn.fetch_query_params(conn)
conn_2 = build_conn(:get, "/?id=#{101}")
RateLimiter.call(conn, plug_opts)
@ -147,13 +156,13 @@ defmodule Pleroma.Plugs.RateLimiterTest do
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
conn_2 = RateLimiter.call(conn_2, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
refute conn_2.status == Conn.Status.code(:too_many_requests)
refute conn_2.resp_body
refute conn_2.halted
end
@ -187,7 +196,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
end
@ -210,12 +219,12 @@ defmodule Pleroma.Plugs.RateLimiterTest do
end
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
conn_2 = RateLimiter.call(conn_2, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
refute conn_2.status == Conn.Status.code(:too_many_requests)
refute conn_2.resp_body
refute conn_2.halted
end

View file

@ -0,0 +1,760 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Pool.ConnectionsTest do
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
import ExUnit.CaptureLog
import Mox
alias Pleroma.Gun.Conn
alias Pleroma.GunMock
alias Pleroma.Pool.Connections
setup :verify_on_exit!
setup_all do
name = :test_connections
{:ok, pid} = Connections.start_link({name, [checkin_timeout: 150]})
{:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
on_exit(fn ->
if Process.alive?(pid), do: GenServer.stop(name)
end)
{:ok, name: name}
end
defp open_mock(num \\ 1) do
GunMock
|> expect(:open, num, &start_and_register(&1, &2, &3))
|> expect(:await_up, num, fn _, _ -> {:ok, :http} end)
|> expect(:set_owner, num, fn _, _ -> :ok end)
end
defp connect_mock(mock) do
mock
|> expect(:connect, &connect(&1, &2))
|> expect(:await, &await(&1, &2))
end
defp info_mock(mock), do: expect(mock, :info, &info(&1))
defp start_and_register('gun-not-up.com', _, _), do: {:error, :timeout}
defp start_and_register(host, port, _) do
{:ok, pid} = Task.start_link(fn -> Process.sleep(1000) end)
scheme =
case port do
443 -> "https"
_ -> "http"
end
Registry.register(GunMock, pid, %{
origin_scheme: scheme,
origin_host: host,
origin_port: port
})
{:ok, pid}
end
defp info(pid) do
[{_, info}] = Registry.lookup(GunMock, pid)
info
end
defp connect(pid, _) do
ref = make_ref()
Registry.register(GunMock, ref, pid)
ref
end
defp await(pid, ref) do
[{_, ^pid}] = Registry.lookup(GunMock, ref)
{:response, :fin, 200, []}
end
defp now, do: :os.system_time(:second)
describe "alive?/2" do
test "is alive", %{name: name} do
assert Connections.alive?(name)
end
test "returns false if not started" do
refute Connections.alive?(:some_random_name)
end
end
test "opens connection and reuse it on next request", %{name: name} do
open_mock()
url = "http://some-domain.com"
key = "http:some-domain.com:80"
refute Connections.checkin(url, name)
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
assert is_pid(conn)
assert Process.alive?(conn)
self = self()
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert conn == reused_conn
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}, {^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
:ok = Connections.checkout(conn, self, name)
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
:ok = Connections.checkout(conn, self, name)
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [],
conn_state: :idle
}
}
} = Connections.get_state(name)
end
test "reuse connection for idna domains", %{name: name} do
open_mock()
url = "http://ですsome-domain.com"
refute Connections.checkin(url, name)
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
assert is_pid(conn)
assert Process.alive?(conn)
self = self()
%Connections{
conns: %{
"http:ですsome-domain.com:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert conn == reused_conn
end
test "reuse for ipv4", %{name: name} do
open_mock()
url = "http://127.0.0.1"
refute Connections.checkin(url, name)
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
assert is_pid(conn)
assert Process.alive?(conn)
self = self()
%Connections{
conns: %{
"http:127.0.0.1:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert conn == reused_conn
:ok = Connections.checkout(conn, self, name)
:ok = Connections.checkout(reused_conn, self, name)
%Connections{
conns: %{
"http:127.0.0.1:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [],
conn_state: :idle
}
}
} = Connections.get_state(name)
end
test "reuse for ipv6", %{name: name} do
open_mock()
url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
refute Connections.checkin(url, name)
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
assert is_pid(conn)
assert Process.alive?(conn)
self = self()
%Connections{
conns: %{
"http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert conn == reused_conn
end
test "up and down ipv4", %{name: name} do
open_mock()
|> info_mock()
|> allow(self(), name)
self = self()
url = "http://127.0.0.1"
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
send(name, {:gun_down, conn, nil, nil, nil})
send(name, {:gun_up, conn, nil})
%Connections{
conns: %{
"http:127.0.0.1:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
end
test "up and down ipv6", %{name: name} do
self = self()
open_mock()
|> info_mock()
|> allow(self, name)
url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
send(name, {:gun_down, conn, nil, nil, nil})
send(name, {:gun_up, conn, nil})
%Connections{
conns: %{
"http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}],
conn_state: :active
}
}
} = Connections.get_state(name)
end
test "reuses connection based on protocol", %{name: name} do
open_mock(2)
http_url = "http://some-domain.com"
http_key = "http:some-domain.com:80"
https_url = "https://some-domain.com"
https_key = "https:some-domain.com:443"
refute Connections.checkin(http_url, name)
:ok = Conn.open(http_url, name)
conn = Connections.checkin(http_url, name)
assert is_pid(conn)
assert Process.alive?(conn)
refute Connections.checkin(https_url, name)
:ok = Conn.open(https_url, name)
https_conn = Connections.checkin(https_url, name)
refute conn == https_conn
reused_https = Connections.checkin(https_url, name)
refute conn == reused_https
assert reused_https == https_conn
%Connections{
conns: %{
^http_key => %Conn{
conn: ^conn,
gun_state: :up
},
^https_key => %Conn{
conn: ^https_conn,
gun_state: :up
}
}
} = Connections.get_state(name)
end
test "connection can't get up", %{name: name} do
expect(GunMock, :open, &start_and_register(&1, &2, &3))
url = "http://gun-not-up.com"
assert capture_log(fn ->
refute Conn.open(url, name)
refute Connections.checkin(url, name)
end) =~
"Opening connection to http://gun-not-up.com failed with error {:error, :timeout}"
end
test "process gun_down message and then gun_up", %{name: name} do
self = self()
open_mock()
|> info_mock()
|> allow(self, name)
url = "http://gun-down-and-up.com"
key = "http:gun-down-and-up.com:80"
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
assert is_pid(conn)
assert Process.alive?(conn)
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up,
used_by: [{^self, _}]
}
}
} = Connections.get_state(name)
send(name, {:gun_down, conn, :http, nil, nil})
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :down,
used_by: [{^self, _}]
}
}
} = Connections.get_state(name)
send(name, {:gun_up, conn, :http})
conn2 = Connections.checkin(url, name)
assert conn == conn2
assert is_pid(conn2)
assert Process.alive?(conn2)
%Connections{
conns: %{
^key => %Conn{
conn: _,
gun_state: :up,
used_by: [{^self, _}, {^self, _}]
}
}
} = Connections.get_state(name)
end
test "async processes get same conn for same domain", %{name: name} do
open_mock()
url = "http://some-domain.com"
:ok = Conn.open(url, name)
tasks =
for _ <- 1..5 do
Task.async(fn ->
Connections.checkin(url, name)
end)
end
tasks_with_results = Task.yield_many(tasks)
results =
Enum.map(tasks_with_results, fn {task, res} ->
res || Task.shutdown(task, :brutal_kill)
end)
conns = for {:ok, value} <- results, do: value
%Connections{
conns: %{
"http:some-domain.com:80" => %Conn{
conn: conn,
gun_state: :up
}
}
} = Connections.get_state(name)
assert Enum.all?(conns, fn res -> res == conn end)
end
test "remove frequently used and idle", %{name: name} do
open_mock(3)
self = self()
http_url = "http://some-domain.com"
https_url = "https://some-domain.com"
:ok = Conn.open(https_url, name)
:ok = Conn.open(http_url, name)
conn1 = Connections.checkin(https_url, name)
[conn2 | _conns] =
for _ <- 1..4 do
Connections.checkin(http_url, name)
end
http_key = "http:some-domain.com:80"
%Connections{
conns: %{
^http_key => %Conn{
conn: ^conn2,
gun_state: :up,
conn_state: :active,
used_by: [{^self, _}, {^self, _}, {^self, _}, {^self, _}]
},
"https:some-domain.com:443" => %Conn{
conn: ^conn1,
gun_state: :up,
conn_state: :active,
used_by: [{^self, _}]
}
}
} = Connections.get_state(name)
:ok = Connections.checkout(conn1, self, name)
another_url = "http://another-domain.com"
:ok = Conn.open(another_url, name)
conn = Connections.checkin(another_url, name)
%Connections{
conns: %{
"http:another-domain.com:80" => %Conn{
conn: ^conn,
gun_state: :up
},
^http_key => %Conn{
conn: _,
gun_state: :up
}
}
} = Connections.get_state(name)
end
describe "with proxy" do
test "as ip", %{name: name} do
open_mock()
|> connect_mock()
url = "http://proxy-string.com"
key = "http:proxy-string.com:80"
:ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
^key => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
test "as host", %{name: name} do
open_mock()
|> connect_mock()
url = "http://proxy-tuple-atom.com"
:ok = Conn.open(url, name, proxy: {'localhost', 9050})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
"http:proxy-tuple-atom.com:80" => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
test "as ip and ssl", %{name: name} do
open_mock()
|> connect_mock()
url = "https://proxy-string.com"
:ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
"https:proxy-string.com:443" => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
test "as host and ssl", %{name: name} do
open_mock()
|> connect_mock()
url = "https://proxy-tuple-atom.com"
:ok = Conn.open(url, name, proxy: {'localhost', 9050})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
"https:proxy-tuple-atom.com:443" => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
test "with socks type", %{name: name} do
open_mock()
url = "http://proxy-socks.com"
:ok = Conn.open(url, name, proxy: {:socks5, 'localhost', 1234})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
"http:proxy-socks.com:80" => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
test "with socks4 type and ssl", %{name: name} do
open_mock()
url = "https://proxy-socks.com"
:ok = Conn.open(url, name, proxy: {:socks4, 'localhost', 1234})
conn = Connections.checkin(url, name)
%Connections{
conns: %{
"https:proxy-socks.com:443" => %Conn{
conn: ^conn,
gun_state: :up
}
}
} = Connections.get_state(name)
reused_conn = Connections.checkin(url, name)
assert reused_conn == conn
end
end
describe "crf/3" do
setup do
crf = Connections.crf(1, 10, 1)
{:ok, crf: crf}
end
test "more used will have crf higher", %{crf: crf} do
# used 3 times
crf1 = Connections.crf(1, 10, crf)
crf1 = Connections.crf(1, 10, crf1)
# used 2 times
crf2 = Connections.crf(1, 10, crf)
assert crf1 > crf2
end
test "recently used will have crf higher on equal references", %{crf: crf} do
# used 3 sec ago
crf1 = Connections.crf(3, 10, crf)
# used 4 sec ago
crf2 = Connections.crf(4, 10, crf)
assert crf1 > crf2
end
test "equal crf on equal reference and time", %{crf: crf} do
# used 2 times
crf1 = Connections.crf(1, 10, crf)
# used 2 times
crf2 = Connections.crf(1, 10, crf)
assert crf1 == crf2
end
test "recently used will have higher crf", %{crf: crf} do
crf1 = Connections.crf(2, 10, crf)
crf1 = Connections.crf(1, 10, crf1)
crf2 = Connections.crf(3, 10, crf)
crf2 = Connections.crf(4, 10, crf2)
assert crf1 > crf2
end
end
describe "get_unused_conns/1" do
test "crf is equalent, sorting by reference", %{name: name} do
Connections.add_conn(name, "1", %Conn{
conn_state: :idle,
last_reference: now() - 1
})
Connections.add_conn(name, "2", %Conn{
conn_state: :idle,
last_reference: now()
})
assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
end
test "reference is equalent, sorting by crf", %{name: name} do
Connections.add_conn(name, "1", %Conn{
conn_state: :idle,
crf: 1.999
})
Connections.add_conn(name, "2", %Conn{
conn_state: :idle,
crf: 2
})
assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
end
test "higher crf and lower reference", %{name: name} do
Connections.add_conn(name, "1", %Conn{
conn_state: :idle,
crf: 3,
last_reference: now() - 1
})
Connections.add_conn(name, "2", %Conn{
conn_state: :idle,
crf: 2,
last_reference: now()
})
assert [{"2", _unused_conn} | _others] = Connections.get_unused_conns(name)
end
test "lower crf and lower reference", %{name: name} do
Connections.add_conn(name, "1", %Conn{
conn_state: :idle,
crf: 1.99,
last_reference: now() - 1
})
Connections.add_conn(name, "2", %Conn{
conn_state: :idle,
crf: 2,
last_reference: now()
})
assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
end
end
test "count/1" do
name = :test_count
{:ok, _} = Connections.start_link({name, [checkin_timeout: 150]})
assert Connections.count(name) == 0
Connections.add_conn(name, "1", %Conn{conn: self()})
assert Connections.count(name) == 1
Connections.remove_conn(name, "1")
assert Connections.count(name) == 0
end
end

View file

@ -4,13 +4,16 @@
defmodule Pleroma.ReverseProxyTest do
use Pleroma.Web.ConnCase, async: true
import ExUnit.CaptureLog
import Mox
alias Pleroma.ReverseProxy
alias Pleroma.ReverseProxy.ClientMock
alias Plug.Conn
setup_all do
{:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.ReverseProxy.ClientMock)
{:ok, _} = Registry.start_link(keys: :unique, name: ClientMock)
:ok
end
@ -21,7 +24,7 @@ defmodule Pleroma.ReverseProxyTest do
ClientMock
|> expect(:request, fn :get, url, _, _, _ ->
Registry.register(Pleroma.ReverseProxy.ClientMock, url, 0)
Registry.register(ClientMock, url, 0)
{:ok, 200,
[
@ -29,14 +32,14 @@ defmodule Pleroma.ReverseProxyTest do
{"content-length", byte_size(json) |> to_string()}
], %{url: url}}
end)
|> expect(:stream_body, invokes, fn %{url: url} ->
case Registry.lookup(Pleroma.ReverseProxy.ClientMock, url) do
|> expect(:stream_body, invokes, fn %{url: url} = client ->
case Registry.lookup(ClientMock, url) do
[{_, 0}] ->
Registry.update_value(Pleroma.ReverseProxy.ClientMock, url, &(&1 + 1))
{:ok, json}
Registry.update_value(ClientMock, url, &(&1 + 1))
{:ok, json, client}
[{_, 1}] ->
Registry.unregister(Pleroma.ReverseProxy.ClientMock, url)
Registry.unregister(ClientMock, url)
:done
end
end)
@ -78,7 +81,39 @@ defmodule Pleroma.ReverseProxyTest do
assert conn.halted
end
describe "max_body " do
defp stream_mock(invokes, with_close? \\ false) do
ClientMock
|> expect(:request, fn :get, "/stream-bytes/" <> length, _, _, _ ->
Registry.register(ClientMock, "/stream-bytes/" <> length, 0)
{:ok, 200, [{"content-type", "application/octet-stream"}],
%{url: "/stream-bytes/" <> length}}
end)
|> expect(:stream_body, invokes, fn %{url: "/stream-bytes/" <> length} = client ->
max = String.to_integer(length)
case Registry.lookup(ClientMock, "/stream-bytes/" <> length) do
[{_, current}] when current < max ->
Registry.update_value(
ClientMock,
"/stream-bytes/" <> length,
&(&1 + 10)
)
{:ok, "0123456789", client}
[{_, ^max}] ->
Registry.unregister(ClientMock, "/stream-bytes/" <> length)
:done
end
end)
if with_close? do
expect(ClientMock, :close, fn _ -> :ok end)
end
end
describe "max_body" do
test "length returns error if content-length more than option", %{conn: conn} do
user_agent_mock("hackney/1.15.1", 0)
@ -94,38 +129,6 @@ defmodule Pleroma.ReverseProxyTest do
end) == ""
end
defp stream_mock(invokes, with_close? \\ false) do
ClientMock
|> expect(:request, fn :get, "/stream-bytes/" <> length, _, _, _ ->
Registry.register(Pleroma.ReverseProxy.ClientMock, "/stream-bytes/" <> length, 0)
{:ok, 200, [{"content-type", "application/octet-stream"}],
%{url: "/stream-bytes/" <> length}}
end)
|> expect(:stream_body, invokes, fn %{url: "/stream-bytes/" <> length} ->
max = String.to_integer(length)
case Registry.lookup(Pleroma.ReverseProxy.ClientMock, "/stream-bytes/" <> length) do
[{_, current}] when current < max ->
Registry.update_value(
Pleroma.ReverseProxy.ClientMock,
"/stream-bytes/" <> length,
&(&1 + 10)
)
{:ok, "0123456789"}
[{_, ^max}] ->
Registry.unregister(Pleroma.ReverseProxy.ClientMock, "/stream-bytes/" <> length)
:done
end
end)
if with_close? do
expect(ClientMock, :close, fn _ -> :ok end)
end
end
test "max_body_length returns error if streaming body more than that option", %{conn: conn} do
stream_mock(3, true)
@ -214,24 +217,24 @@ defmodule Pleroma.ReverseProxyTest do
conn = ReverseProxy.call(conn, "/stream-bytes/200")
assert conn.state == :chunked
assert byte_size(conn.resp_body) == 200
assert Plug.Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
end
defp headers_mock(_) do
ClientMock
|> expect(:request, fn :get, "/headers", headers, _, _ ->
Registry.register(Pleroma.ReverseProxy.ClientMock, "/headers", 0)
Registry.register(ClientMock, "/headers", 0)
{:ok, 200, [{"content-type", "application/json"}], %{url: "/headers", headers: headers}}
end)
|> expect(:stream_body, 2, fn %{url: url, headers: headers} ->
case Registry.lookup(Pleroma.ReverseProxy.ClientMock, url) do
|> expect(:stream_body, 2, fn %{url: url, headers: headers} = client ->
case Registry.lookup(ClientMock, url) do
[{_, 0}] ->
Registry.update_value(Pleroma.ReverseProxy.ClientMock, url, &(&1 + 1))
Registry.update_value(ClientMock, url, &(&1 + 1))
headers = for {k, v} <- headers, into: %{}, do: {String.capitalize(k), v}
{:ok, Jason.encode!(%{headers: headers})}
{:ok, Jason.encode!(%{headers: headers}), client}
[{_, 1}] ->
Registry.unregister(Pleroma.ReverseProxy.ClientMock, url)
Registry.unregister(ClientMock, url)
:done
end
end)
@ -244,7 +247,7 @@ defmodule Pleroma.ReverseProxyTest do
test "header passes", %{conn: conn} do
conn =
Plug.Conn.put_req_header(
Conn.put_req_header(
conn,
"accept",
"text/html"
@ -257,7 +260,7 @@ defmodule Pleroma.ReverseProxyTest do
test "header is filtered", %{conn: conn} do
conn =
Plug.Conn.put_req_header(
Conn.put_req_header(
conn,
"accept-language",
"en-US"
@ -290,18 +293,18 @@ defmodule Pleroma.ReverseProxyTest do
defp disposition_headers_mock(headers) do
ClientMock
|> expect(:request, fn :get, "/disposition", _, _, _ ->
Registry.register(Pleroma.ReverseProxy.ClientMock, "/disposition", 0)
Registry.register(ClientMock, "/disposition", 0)
{:ok, 200, headers, %{url: "/disposition"}}
end)
|> expect(:stream_body, 2, fn %{url: "/disposition"} ->
case Registry.lookup(Pleroma.ReverseProxy.ClientMock, "/disposition") do
|> expect(:stream_body, 2, fn %{url: "/disposition"} = client ->
case Registry.lookup(ClientMock, "/disposition") do
[{_, 0}] ->
Registry.update_value(Pleroma.ReverseProxy.ClientMock, "/disposition", &(&1 + 1))
{:ok, ""}
Registry.update_value(ClientMock, "/disposition", &(&1 + 1))
{:ok, "", client}
[{_, 1}] ->
Registry.unregister(Pleroma.ReverseProxy.ClientMock, "/disposition")
Registry.unregister(ClientMock, "/disposition")
:done
end
end)

View file

@ -19,12 +19,7 @@ defmodule Pleroma.SignatureTest do
@private_key "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA48qb4v6kqigZutO9Ot0wkp27GIF2LiVaADgxQORZozZR63jH\nTaoOrS3Xhngbgc8SSOhfXET3omzeCLqaLNfXnZ8OXmuhJfJSU6mPUvmZ9QdT332j\nfN/g3iWGhYMf/M9ftCKh96nvFVO/tMruzS9xx7tkrfJjehdxh/3LlJMMImPtwcD7\nkFXwyt1qZTAU6Si4oQAJxRDQXHp1ttLl3Ob829VM7IKkrVmY8TD+JSlV0jtVJPj6\n1J19ytKTx/7UaucYvb9HIiBpkuiy5n/irDqKLVf5QEdZoNCdojOZlKJmTLqHhzKP\n3E9TxsUjhrf4/EqegNc/j982RvOxeu4i40zMQwIDAQABAoIBAQDH5DXjfh21i7b4\ncXJuw0cqget617CDUhemdakTDs9yH+rHPZd3mbGDWuT0hVVuFe4vuGpmJ8c+61X0\nRvugOlBlavxK8xvYlsqTzAmPgKUPljyNtEzQ+gz0I+3mH2jkin2rL3D+SksZZgKm\nfiYMPIQWB2WUF04gB46DDb2mRVuymGHyBOQjIx3WC0KW2mzfoFUFRlZEF+Nt8Ilw\nT+g/u0aZ1IWoszbsVFOEdghgZET0HEarum0B2Je/ozcPYtwmU10iBANGMKdLqaP/\nj954BPunrUf6gmlnLZKIKklJj0advx0NA+cL79+zeVB3zexRYSA5o9q0WPhiuTwR\n/aedWHnBAoGBAP0sDWBAM1Y4TRAf8ZI9PcztwLyHPzfEIqzbObJJnx1icUMt7BWi\n+/RMOnhrlPGE1kMhOqSxvXYN3u+eSmWTqai2sSH5Hdw2EqnrISSTnwNUPINX7fHH\njEkgmXQ6ixE48SuBZnb4w1EjdB/BA6/sjL+FNhggOc87tizLTkMXmMtTAoGBAOZV\n+wPuAMBDBXmbmxCuDIjoVmgSlgeRunB1SA8RCPAFAiUo3+/zEgzW2Oz8kgI+xVwM\n33XkLKrWG1Orhpp6Hm57MjIc5MG+zF4/YRDpE/KNG9qU1tiz0UD5hOpIU9pP4bR/\ngxgPxZzvbk4h5BfHWLpjlk8UUpgk6uxqfti48c1RAoGBALBOKDZ6HwYRCSGMjUcg\n3NPEUi84JD8qmFc2B7Tv7h2he2ykIz9iFAGpwCIyETQsJKX1Ewi0OlNnD3RhEEAy\nl7jFGQ+mkzPSeCbadmcpYlgIJmf1KN/x7fDTAepeBpCEzfZVE80QKbxsaybd3Dp8\nCfwpwWUFtBxr4c7J+gNhAGe/AoGAPn8ZyqkrPv9wXtyfqFjxQbx4pWhVmNwrkBPi\nZ2Qh3q4dNOPwTvTO8vjghvzIyR8rAZzkjOJKVFgftgYWUZfM5gE7T2mTkBYq8W+U\n8LetF+S9qAM2gDnaDx0kuUTCq7t87DKk6URuQ/SbI0wCzYjjRD99KxvChVGPBHKo\n1DjqMuECgYEAgJGNm7/lJCS2wk81whfy/ttKGsEIkyhPFYQmdGzSYC5aDc2gp1R3\nxtOkYEvdjfaLfDGEa4UX8CHHF+w3t9u8hBtcdhMH6GYb9iv6z0VBTt4A/11HUR49\n3Z7TQ18Iyh3jAUCzFV9IJlLIExq5Y7P4B3ojWFBN607sDCt8BMPbDYs=\n-----END RSA PRIVATE KEY-----"
@public_key %{
"id" => "https://mastodon.social/users/lambadalambda#main-key",
"owner" => "https://mastodon.social/users/lambadalambda",
"publicKeyPem" =>
"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0P/Tq4gb4G/QVuMGbJo\nC/AfMNcv+m7NfrlOwkVzcU47jgESuYI4UtJayissCdBycHUnfVUd9qol+eznSODz\nCJhfJloqEIC+aSnuEPGA0POtWad6DU0E6/Ho5zQn5WAWUwbRQqowbrsm/GHo2+3v\neR5jGenwA6sYhINg/c3QQbksyV0uJ20Umyx88w8+TJuv53twOfmyDWuYNoQ3y5cc\nHKOZcLHxYOhvwg3PFaGfFHMFiNmF40dTXt9K96r7sbzc44iLD+VphbMPJEjkMuf8\nPGEFOBzy8pm3wJZw2v32RNW2VESwMYyqDzwHXGSq1a73cS7hEnc79gXlELsK04L9\nQQIDAQAB\n-----END PUBLIC KEY-----\n"
}
@public_key "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0P/Tq4gb4G/QVuMGbJo\nC/AfMNcv+m7NfrlOwkVzcU47jgESuYI4UtJayissCdBycHUnfVUd9qol+eznSODz\nCJhfJloqEIC+aSnuEPGA0POtWad6DU0E6/Ho5zQn5WAWUwbRQqowbrsm/GHo2+3v\neR5jGenwA6sYhINg/c3QQbksyV0uJ20Umyx88w8+TJuv53twOfmyDWuYNoQ3y5cc\nHKOZcLHxYOhvwg3PFaGfFHMFiNmF40dTXt9K96r7sbzc44iLD+VphbMPJEjkMuf8\nPGEFOBzy8pm3wJZw2v32RNW2VESwMYyqDzwHXGSq1a73cS7hEnc79gXlELsK04L9\nQQIDAQAB\n-----END PUBLIC KEY-----\n"
@rsa_public_key {
:RSAPublicKey,
@ -42,19 +37,20 @@ defmodule Pleroma.SignatureTest do
test "it returns key" do
expected_result = {:ok, @rsa_public_key}
user = insert(:user, source_data: %{"publicKey" => @public_key})
user = insert(:user, public_key: @public_key)
assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == expected_result
end
test "it returns error when not found user" do
assert capture_log(fn ->
assert Signature.fetch_public_key(make_fake_conn("test-ap_id")) == {:error, :error}
assert Signature.fetch_public_key(make_fake_conn("https://test-ap-id")) ==
{:error, :error}
end) =~ "[error] Could not decode user"
end
test "it returns error if public key is empty" do
user = insert(:user, source_data: %{"publicKey" => %{}})
test "it returns error if public key is nil" do
user = insert(:user, public_key: nil)
assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == {:error, :error}
end
@ -69,7 +65,7 @@ defmodule Pleroma.SignatureTest do
test "it returns error when not found user" do
assert capture_log(fn ->
{:error, _} = Signature.refetch_public_key(make_fake_conn("test-ap_id"))
{:error, _} = Signature.refetch_public_key(make_fake_conn("https://test-ap_id"))
end) =~ "[error] Could not decode user"
end
end
@ -105,12 +101,21 @@ defmodule Pleroma.SignatureTest do
describe "key_id_to_actor_id/1" do
test "it properly deduces the actor id for misskey" do
assert Signature.key_id_to_actor_id("https://example.com/users/1234/publickey") ==
"https://example.com/users/1234"
{:ok, "https://example.com/users/1234"}
end
test "it properly deduces the actor id for mastodon and pleroma" do
assert Signature.key_id_to_actor_id("https://example.com/users/1234#main-key") ==
"https://example.com/users/1234"
{:ok, "https://example.com/users/1234"}
end
test "it calls webfinger for 'acct:' accounts" do
with_mock(Pleroma.Web.WebFinger,
finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end
) do
assert Signature.key_id_to_actor_id("acct:raymoo@gensokyo.2hu") ==
{:ok, "https://gensokyo.2hu/users/raymoo"}
end
end
end

View file

@ -2,36 +2,46 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.StateTest do
defmodule Pleroma.StatsTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.CommonAPI
describe "user count" do
test "it ignores internal users" do
_user = insert(:user, local: true)
_internal = insert(:user, local: true, nickname: nil)
_internal = Pleroma.Web.ActivityPub.Relay.get_actor()
assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data())
end
end
describe "status visibility count" do
test "on new status" do
user = insert(:user)
other_user = insert(:user)
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
CommonAPI.post(user, %{visibility: "public", status: "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
"visibility" => "unlisted",
"status" => "hey"
visibility: "unlisted",
status: "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "hey @#{other_user.nickname}"
visibility: "direct",
status: "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
"visibility" => "private",
"status" => "hey"
visibility: "private",
status: "hey"
})
end)
@ -41,7 +51,7 @@ defmodule Pleroma.StateTest do
test "on status delete" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
assert %{public: 1} = Pleroma.Stats.get_status_visibility_count()
CommonAPI.delete(activity.id, user)
assert %{public: 0} = Pleroma.Stats.get_status_visibility_count()
@ -49,18 +59,18 @@ defmodule Pleroma.StateTest do
test "on status visibility update" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
assert %{public: 1, private: 0} = Pleroma.Stats.get_status_visibility_count()
{:ok, _} = CommonAPI.update_activity_scope(activity.id, %{"visibility" => "private"})
{:ok, _} = CommonAPI.update_activity_scope(activity.id, %{visibility: "private"})
assert %{public: 0, private: 1} = Pleroma.Stats.get_status_visibility_count()
end
test "doesn't count unrelated activities" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
_ = CommonAPI.follow(user, other_user)
CommonAPI.favorite(activity.id, other_user)
CommonAPI.favorite(other_user, activity.id)
CommonAPI.repeat(activity.id, other_user)
assert %{direct: 0, private: 0, public: 1, unlisted: 0} =

View file

@ -0,0 +1,57 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Tests.ApiSpecHelpers do
@moduledoc """
OpenAPI spec test helpers
"""
import ExUnit.Assertions
alias OpenApiSpex.Cast.Error
alias OpenApiSpex.Reference
alias OpenApiSpex.Schema
def assert_schema(value, schema) do
api_spec = Pleroma.Web.ApiSpec.spec()
case OpenApiSpex.cast_value(value, schema, api_spec) do
{:ok, data} ->
data
{:error, errors} ->
errors =
Enum.map(errors, fn error ->
message = Error.message(error)
path = Error.path_to_string(error)
"#{message} at #{path}"
end)
flunk(
"Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{
inspect(value)
}"
)
end
end
def resolve_schema(%Schema{} = schema), do: schema
def resolve_schema(%Reference{} = ref) do
schemas = Pleroma.Web.ApiSpec.spec().components.schemas
Reference.resolve_schema(ref, schemas)
end
def api_operations do
paths = Pleroma.Web.ApiSpec.spec().paths
Enum.flat_map(paths, fn {_, path_item} ->
path_item
|> Map.take([:delete, :get, :head, :options, :patch, :post, :put, :trace])
|> Map.values()
|> Enum.reject(&is_nil/1)
|> Enum.uniq()
end)
end
end

View file

@ -21,7 +21,15 @@ defmodule Pleroma.Builders.ActivityBuilder do
def insert(data \\ %{}, opts \\ %{}) do
activity = build(data, opts)
ActivityPub.insert(activity)
case ActivityPub.insert(activity) do
ok = {:ok, activity} ->
ActivityPub.notify_and_stream(activity)
ok
error ->
error
end
end
def insert_list(times, data \\ %{}, opts \\ %{}) do

View file

@ -7,10 +7,11 @@ defmodule Pleroma.Builders.UserBuilder do
email: "test@example.org",
name: "Test Name",
nickname: "testname",
password_hash: Comeonin.Pbkdf2.hashpwsalt("test"),
password_hash: Pbkdf2.hash_pwd_salt("test"),
bio: "A tester.",
ap_id: "some id",
last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
multi_factor_authentication_settings: %Pleroma.MFA.Settings{},
notification_settings: %Pleroma.User.NotificationSetting{}
}

View file

@ -6,12 +6,16 @@ defmodule Pleroma.Captcha.Mock do
alias Pleroma.Captcha.Service
@behaviour Service
@solution "63615261b77f5354fb8c4e4986477555"
def solution, do: @solution
@impl Service
def new,
do: %{
type: :mock,
token: "afa1815e14e29355e6c8f6b143a39fa2",
answer_data: "63615261b77f5354fb8c4e4986477555",
answer_data: @solution,
url: "https://example.org/captcha.png"
}

View file

@ -51,6 +51,60 @@ defmodule Pleroma.Web.ConnCase do
%{user: user, token: token, conn: conn}
end
defp request_content_type(%{conn: conn}) do
conn = put_req_header(conn, "content-type", "multipart/form-data")
[conn: conn]
end
defp json_response_and_validate_schema(
%{
private: %{
open_api_spex: %{operation_id: op_id, operation_lookup: lookup, spec: spec}
}
} = conn,
status
) do
content_type =
conn
|> Plug.Conn.get_resp_header("content-type")
|> List.first()
|> String.split(";")
|> List.first()
status = Plug.Conn.Status.code(status)
unless lookup[op_id].responses[status] do
err = "Response schema not found for #{status} #{conn.method} #{conn.request_path}"
flunk(err)
end
schema = lookup[op_id].responses[status].content[content_type].schema
json = json_response(conn, status)
case OpenApiSpex.cast_value(json, schema, spec) do
{:ok, _data} ->
json
{:error, errors} ->
errors =
Enum.map(errors, fn error ->
message = OpenApiSpex.Cast.Error.message(error)
path = OpenApiSpex.Cast.Error.path_to_string(error)
"#{message} at #{path}"
end)
flunk(
"Response does not conform to schema of #{op_id} operation: #{
Enum.join(errors, "\n")
}\n#{inspect(json)}"
)
end
end
defp json_response_and_validate_schema(conn, _status) do
flunk("Response schema not found for #{conn.method} #{conn.request_path} #{conn.status}")
end
defp ensure_federating_or_authenticated(conn, url, user) do
initial_setting = Config.get([:instance, :federating])
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)
@ -85,7 +139,11 @@ defmodule Pleroma.Web.ConnCase do
end
if tags[:needs_streamer] do
start_supervised(Pleroma.Web.Streamer.supervisor())
start_supervised(%{
id: Pleroma.Web.Streamer.registry(),
start:
{Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]}
})
end
{:ok, conn: Phoenix.ConnTest.build_conn()}

View file

@ -40,7 +40,11 @@ defmodule Pleroma.DataCase do
end
if tags[:needs_streamer] do
start_supervised(Pleroma.Web.Streamer.supervisor())
start_supervised(%{
id: Pleroma.Web.Streamer.registry(),
start:
{Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]}
})
end
:ok

View file

@ -29,10 +29,12 @@ defmodule Pleroma.Factory do
name: sequence(:name, &"Test テスト User #{&1}"),
email: sequence(:email, &"user#{&1}@example.com"),
nickname: sequence(:nickname, &"nick#{&1}"),
password_hash: Comeonin.Pbkdf2.hashpwsalt("test"),
password_hash: Pbkdf2.hash_pwd_salt("test"),
bio: sequence(:bio, &"Tester Number #{&1}"),
last_digest_emailed_at: NaiveDateTime.utc_now(),
notification_settings: %Pleroma.User.NotificationSetting{}
last_refreshed_at: NaiveDateTime.utc_now(),
notification_settings: %Pleroma.User.NotificationSetting{},
multi_factor_authentication_settings: %Pleroma.MFA.Settings{}
}
%{
@ -294,7 +296,7 @@ defmodule Pleroma.Factory do
def oauth_app_factory do
%Pleroma.Web.OAuth.App{
client_name: "Some client",
client_name: sequence(:client_name, &"Some client #{&1}"),
redirect_uris: "https://example.com/callback",
scopes: ["read", "write", "follow", "push", "admin"],
website: "https://example.com",
@ -421,4 +423,13 @@ defmodule Pleroma.Factory do
last_read_id: "1"
}
end
def mfa_token_factory do
%Pleroma.MFA.Token{
token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false),
authorization: build(:oauth_authorization),
valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10),
user: build(:user)
}
end
end

View file

@ -40,12 +40,18 @@ defmodule Pleroma.Tests.Helpers do
clear_config: 2
]
def to_datetime(naive_datetime) do
def to_datetime(%NaiveDateTime{} = naive_datetime) do
naive_datetime
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.truncate(:second)
end
def to_datetime(datetime) when is_binary(datetime) do
datetime
|> NaiveDateTime.from_iso8601!()
|> to_datetime()
end
def collect_ids(collection) do
collection
|> Enum.map(& &1.id)

View file

@ -107,7 +107,7 @@ defmodule HttpRequestMock do
"https://osada.macgirvin.com/.well-known/webfinger?resource=acct:mike@osada.macgirvin.com",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -120,7 +120,7 @@ defmodule HttpRequestMock do
"https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/29191",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -141,7 +141,7 @@ defmodule HttpRequestMock do
"https://pawoo.net/.well-known/webfinger?resource=acct:https://pawoo.net/users/pekorino",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -167,7 +167,7 @@ defmodule HttpRequestMock do
"https://social.stopwatchingus-heidelberg.de/.well-known/webfinger?resource=acct:https://social.stopwatchingus-heidelberg.de/user/18330",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -188,7 +188,7 @@ defmodule HttpRequestMock do
"https://mamot.fr/.well-known/webfinger?resource=acct:https://mamot.fr/users/Skruyb",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -201,7 +201,7 @@ defmodule HttpRequestMock do
"https://social.heldscal.la/.well-known/webfinger?resource=nonexistant@social.heldscal.la",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -211,10 +211,10 @@ defmodule HttpRequestMock do
end
def get(
"https://squeet.me/xrd/?uri=lain@squeet.me",
"https://squeet.me/xrd/?uri=acct:lain@squeet.me",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -227,7 +227,7 @@ defmodule HttpRequestMock do
"https://mst3k.interlinked.me/users/luciferMysticus",
_,
_,
Accept: "application/activity+json"
[{"accept", "application/activity+json"}]
) do
{:ok,
%Tesla.Env{
@ -248,7 +248,7 @@ defmodule HttpRequestMock do
"https://hubzilla.example.org/channel/kaniini",
_,
_,
Accept: "application/activity+json"
[{"accept", "application/activity+json"}]
) do
{:ok,
%Tesla.Env{
@ -257,7 +257,7 @@ defmodule HttpRequestMock do
}}
end
def get("https://niu.moe/users/rye", _, _, Accept: "application/activity+json") do
def get("https://niu.moe/users/rye", _, _, [{"accept", "application/activity+json"}]) do
{:ok,
%Tesla.Env{
status: 200,
@ -265,7 +265,7 @@ defmodule HttpRequestMock do
}}
end
def get("https://n1u.moe/users/rye", _, _, Accept: "application/activity+json") do
def get("https://n1u.moe/users/rye", _, _, [{"accept", "application/activity+json"}]) do
{:ok,
%Tesla.Env{
status: 200,
@ -284,7 +284,7 @@ defmodule HttpRequestMock do
}}
end
def get("https://puckipedia.com/", _, _, Accept: "application/activity+json") do
def get("https://puckipedia.com/", _, _, [{"accept", "application/activity+json"}]) do
{:ok,
%Tesla.Env{
status: 200,
@ -308,9 +308,25 @@ defmodule HttpRequestMock do
}}
end
def get("https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39", _, _,
Accept: "application/activity+json"
) do
def get("https://peertube.social/accounts/craigmaloney", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/tesla_mock/craigmaloney.json")
}}
end
def get("https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/tesla_mock/peertube-social.json")
}}
end
def get("https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39", _, _, [
{"accept", "application/activity+json"}
]) do
{:ok,
%Tesla.Env{
status: 200,
@ -318,7 +334,7 @@ defmodule HttpRequestMock do
}}
end
def get("https://mobilizon.org/@tcit", _, _, Accept: "application/activity+json") do
def get("https://mobilizon.org/@tcit", _, _, [{"accept", "application/activity+json"}]) do
{:ok,
%Tesla.Env{
status: 200,
@ -358,7 +374,7 @@ defmodule HttpRequestMock do
}}
end
def get("http://mastodon.example.org/users/admin", _, _, Accept: "application/activity+json") do
def get("http://mastodon.example.org/users/admin", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
@ -366,7 +382,9 @@ defmodule HttpRequestMock do
}}
end
def get("http://mastodon.example.org/users/relay", _, _, Accept: "application/activity+json") do
def get("http://mastodon.example.org/users/relay", _, _, [
{"accept", "application/activity+json"}
]) do
{:ok,
%Tesla.Env{
status: 200,
@ -374,7 +392,9 @@ defmodule HttpRequestMock do
}}
end
def get("http://mastodon.example.org/users/gargron", _, _, Accept: "application/activity+json") do
def get("http://mastodon.example.org/users/gargron", _, _, [
{"accept", "application/activity+json"}
]) do
{:error, :nxdomain}
end
@ -557,7 +577,7 @@ defmodule HttpRequestMock do
"http://mastodon.example.org/@admin/99541947525187367",
_,
_,
Accept: "application/activity+json"
_
) do
{:ok,
%Tesla.Env{
@ -582,7 +602,7 @@ defmodule HttpRequestMock do
}}
end
def get("https://mstdn.io/users/mayuutann", _, _, Accept: "application/activity+json") do
def get("https://mstdn.io/users/mayuutann", _, _, [{"accept", "application/activity+json"}]) do
{:ok,
%Tesla.Env{
status: 200,
@ -594,7 +614,7 @@ defmodule HttpRequestMock do
"https://mstdn.io/users/mayuutann/statuses/99568293732299394",
_,
_,
Accept: "application/activity+json"
[{"accept", "application/activity+json"}]
) do
{:ok,
%Tesla.Env{
@ -614,7 +634,7 @@ defmodule HttpRequestMock do
}}
end
def get(url, _, _, Accept: "application/xrd+xml,application/jrd+json")
def get(url, _, _, [{"accept", "application/xrd+xml,application/jrd+json"}])
when url in [
"https://pleroma.soykaf.com/.well-known/webfinger?resource=acct:https://pleroma.soykaf.com/users/lain",
"https://pleroma.soykaf.com/.well-known/webfinger?resource=https://pleroma.soykaf.com/users/lain"
@ -641,7 +661,7 @@ defmodule HttpRequestMock do
"https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/1",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -685,7 +705,7 @@ defmodule HttpRequestMock do
"https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/5381",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -738,7 +758,7 @@ defmodule HttpRequestMock do
"https://social.sakamoto.gq/.well-known/webfinger?resource=https://social.sakamoto.gq/users/eal",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -751,7 +771,7 @@ defmodule HttpRequestMock do
"https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056",
_,
_,
Accept: "application/atom+xml"
[{"accept", "application/atom+xml"}]
) do
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sakamoto.atom")}}
end
@ -768,7 +788,7 @@ defmodule HttpRequestMock do
"https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/lambadalambda",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -790,7 +810,7 @@ defmodule HttpRequestMock do
"http://gs.example.org/.well-known/webfinger?resource=http://gs.example.org:4040/index.php/user/1",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -804,7 +824,7 @@ defmodule HttpRequestMock do
"http://gs.example.org:4040/index.php/user/1",
_,
_,
Accept: "application/activity+json"
[{"accept", "application/activity+json"}]
) do
{:ok, %Tesla.Env{status: 406, body: ""}}
end
@ -840,7 +860,7 @@ defmodule HttpRequestMock do
"https://squeet.me/xrd?uri=lain@squeet.me",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -850,10 +870,10 @@ defmodule HttpRequestMock do
end
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la",
"https://social.heldscal.la/.well-known/webfinger?resource=acct:shp@social.heldscal.la",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -863,10 +883,10 @@ defmodule HttpRequestMock do
end
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=invalid_content@social.heldscal.la",
"https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok, %Tesla.Env{status: 200, body: ""}}
end
@ -880,10 +900,10 @@ defmodule HttpRequestMock do
end
def get(
"http://framatube.org/main/xrd?uri=framasoft@framatube.org",
"http://framatube.org/main/xrd?uri=acct:framasoft@framatube.org",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -905,7 +925,7 @@ defmodule HttpRequestMock do
"http://gnusocial.de/main/xrd?uri=winterdienst@gnusocial.de",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -939,10 +959,10 @@ defmodule HttpRequestMock do
end
def get(
"https://gerzilla.de/xrd/?uri=kaniini@gerzilla.de",
"https://gerzilla.de/xrd/?uri=acct:kaniini@gerzilla.de",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -1005,7 +1025,7 @@ defmodule HttpRequestMock do
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json")}}
end
def get("https://social.heldscal.la/user/23211", _, _, Accept: "application/activity+json") do
def get("https://social.heldscal.la/user/23211", _, _, [{"accept", "application/activity+json"}]) do
{:ok, Tesla.Mock.json(%{"id" => "https://social.heldscal.la/user/23211"}, status: 200)}
end
@ -1135,10 +1155,10 @@ defmodule HttpRequestMock do
end
def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=lain@zetsubou.xn--q9jyb4c",
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:lain@zetsubou.xn--q9jyb4c",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -1148,10 +1168,10 @@ defmodule HttpRequestMock do
end
def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=https://zetsubou.xn--q9jyb4c/users/lain",
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:https://zetsubou.xn--q9jyb4c/users/lain",
_,
_,
Accept: "application/xrd+xml,application/jrd+json"
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
{:ok,
%Tesla.Env{
@ -1173,7 +1193,9 @@ defmodule HttpRequestMock do
}}
end
def get("https://info.pleroma.site/activity.json", _, _, Accept: "application/activity+json") do
def get("https://info.pleroma.site/activity.json", _, _, [
{"accept", "application/activity+json"}
]) do
{:ok,
%Tesla.Env{
status: 200,
@ -1185,7 +1207,9 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 404, body: ""}}
end
def get("https://info.pleroma.site/activity2.json", _, _, Accept: "application/activity+json") do
def get("https://info.pleroma.site/activity2.json", _, _, [
{"accept", "application/activity+json"}
]) do
{:ok,
%Tesla.Env{
status: 200,
@ -1197,7 +1221,9 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 404, body: ""}}
end
def get("https://info.pleroma.site/activity3.json", _, _, Accept: "application/activity+json") do
def get("https://info.pleroma.site/activity3.json", _, _, [
{"accept", "application/activity+json"}
]) do
{:ok,
%Tesla.Env{
status: 200,
@ -1273,6 +1299,21 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}}
end
def get(
"https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871",
_,
_,
_
) do
{:ok,
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json")}}
end
def get("https://channels.tests.funkwhale.audio/federation/actors/compositions", _, _, _) do
{:ok,
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")}}
end
def get("http://example.com/rel_me/error", _, _, _) do
{:ok, %Tesla.Env{status: 404, body: ""}}
end

65
test/tasks/app_test.exs Normal file
View file

@ -0,0 +1,65 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.AppTest do
use Pleroma.DataCase, async: true
setup_all do
Mix.shell(Mix.Shell.Process)
on_exit(fn ->
Mix.shell(Mix.Shell.IO)
end)
end
describe "creates new app" do
test "with default scopes" do
name = "Some name"
redirect = "https://example.com"
Mix.Tasks.Pleroma.App.run(["create", "-n", name, "-r", redirect])
assert_app(name, redirect, ["read", "write", "follow", "push"])
end
test "with custom scopes" do
name = "Another name"
redirect = "https://example.com"
Mix.Tasks.Pleroma.App.run([
"create",
"-n",
name,
"-r",
redirect,
"-s",
"read,write,follow,push,admin"
])
assert_app(name, redirect, ["read", "write", "follow", "push", "admin"])
end
end
test "with errors" do
Mix.Tasks.Pleroma.App.run(["create"])
{:mix_shell, :error, ["Creating failed:"]}
{:mix_shell, :error, ["name: can't be blank"]}
{:mix_shell, :error, ["redirect_uris: can't be blank"]}
end
defp assert_app(name, redirect, scopes) do
app = Repo.get_by(Pleroma.Web.OAuth.App, client_name: name)
assert_received {:mix_shell, :info, [message]}
assert message == "#{name} successfully created:"
assert_received {:mix_shell, :info, [message]}
assert message == "App client_id: #{app.client_id}"
assert_received {:mix_shell, :info, [message]}
assert message == "App client_secret: #{app.client_secret}"
assert app.scopes == scopes
assert app.redirect_uris == redirect
end
end

View file

@ -38,7 +38,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
on_exit(fn -> Application.put_env(:quack, :level, initial) end)
end
test "settings are migrated to db" do
test "filtered settings are migrated to db" do
assert Repo.all(ConfigDB) == []
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
@ -47,6 +47,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"})
assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]]
assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]]

View file

@ -13,11 +13,11 @@ defmodule Mix.Tasks.Pleroma.CountStatusesTest do
test "counts statuses" do
user = insert(:user)
{:ok, _} = CommonAPI.post(user, %{"status" => "test"})
{:ok, _} = CommonAPI.post(user, %{"status" => "test2"})
{:ok, _} = CommonAPI.post(user, %{status: "test"})
{:ok, _} = CommonAPI.post(user, %{status: "test2"})
user2 = insert(:user)
{:ok, _} = CommonAPI.post(user2, %{"status" => "test3"})
{:ok, _} = CommonAPI.post(user2, %{status: "test3"})
user = refresh_record(user)
user2 = refresh_record(user2)

View file

@ -26,7 +26,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
describe "running remove_embedded_objects" do
test "it replaces objects with references" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
{:ok, activity} = CommonAPI.post(user, %{status: "test"})
new_data = Map.put(activity.data, "object", activity.object.data)
{:ok, activity} =
@ -99,10 +99,10 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
test "it turns OrderedCollection likes into empty arrays" do
[user, user2] = insert_pair(:user)
{:ok, %{id: id, object: object}} = CommonAPI.post(user, %{"status" => "test"})
{:ok, %{object: object2}} = CommonAPI.post(user, %{"status" => "test test"})
{:ok, %{id: id, object: object}} = CommonAPI.post(user, %{status: "test"})
{:ok, %{object: object2}} = CommonAPI.post(user, %{status: "test test"})
CommonAPI.favorite(id, user2)
CommonAPI.favorite(user2, id)
likes = %{
"first" =>

View file

@ -25,7 +25,7 @@ defmodule Mix.Tasks.Pleroma.DigestTest do
Enum.each(0..10, fn i ->
{:ok, _activity} =
CommonAPI.post(user1, %{
"status" => "hey ##{i} @#{user2.nickname}!"
status: "hey ##{i} @#{user2.nickname}!"
})
end)

226
test/tasks/emoji_test.exs Normal file
View file

@ -0,0 +1,226 @@
defmodule Mix.Tasks.Pleroma.EmojiTest do
use ExUnit.Case, async: true
import ExUnit.CaptureIO
import Tesla.Mock
alias Mix.Tasks.Pleroma.Emoji
describe "ls-packs" do
test "with default manifest as url" do
mock(fn
%{
method: :get,
url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
}
end)
capture_io(fn -> Emoji.run(["ls-packs"]) end) =~
"https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
end
test "with passed manifest as file" do
capture_io(fn ->
Emoji.run(["ls-packs", "-m", "test/fixtures/emoji/packs/manifest.json"])
end) =~ "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip"
end
end
describe "get-packs" do
test "download pack from default manifest" do
mock(fn
%{
method: :get,
url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
}
%{
method: :get,
url: "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/blank.png.zip")
}
%{
method: :get,
url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/finmoji.json"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/finmoji.json")
}
end)
assert capture_io(fn -> Emoji.run(["get-packs", "finmoji"]) end) =~ "Writing pack.json for"
emoji_path =
Path.join(
Pleroma.Config.get!([:instance, :static_dir]),
"emoji"
)
assert File.exists?(Path.join([emoji_path, "finmoji", "pack.json"]))
on_exit(fn -> File.rm_rf!("test/instance_static/emoji/finmoji") end)
end
test "pack not found" do
mock(fn
%{
method: :get,
url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
}
end)
assert capture_io(fn -> Emoji.run(["get-packs", "not_found"]) end) =~
"No pack named \"not_found\" found"
end
test "raise on bad sha256" do
mock(fn
%{
method: :get,
url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip"
} ->
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/emoji/packs/blank.png.zip")
}
end)
assert_raise RuntimeError, ~r/^Bad SHA256 for blobs.gg/, fn ->
capture_io(fn ->
Emoji.run(["get-packs", "blobs.gg", "-m", "test/fixtures/emoji/packs/manifest.json"])
end)
end
end
end
describe "gen-pack" do
setup do
url = "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
mock(fn %{
method: :get,
url: ^url
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/emoji/packs/blank.png.zip")}
end)
{:ok, url: url}
end
test "with default extensions", %{url: url} do
name = "pack1"
pack_json = "#{name}.json"
files_json = "#{name}_file.json"
refute File.exists?(pack_json)
refute File.exists?(files_json)
captured =
capture_io(fn ->
Emoji.run([
"gen-pack",
url,
"--name",
name,
"--license",
"license",
"--homepage",
"homepage",
"--description",
"description",
"--files",
files_json,
"--extensions",
".png .gif"
])
end)
assert captured =~ "#{pack_json} has been created with the pack1 pack"
assert captured =~ "Using .png .gif extensions"
assert File.exists?(pack_json)
assert File.exists?(files_json)
on_exit(fn ->
File.rm!(pack_json)
File.rm!(files_json)
end)
end
test "with custom extensions and update existing files", %{url: url} do
name = "pack2"
pack_json = "#{name}.json"
files_json = "#{name}_file.json"
refute File.exists?(pack_json)
refute File.exists?(files_json)
captured =
capture_io(fn ->
Emoji.run([
"gen-pack",
url,
"--name",
name,
"--license",
"license",
"--homepage",
"homepage",
"--description",
"description",
"--files",
files_json,
"--extensions",
" .png .gif .jpeg "
])
end)
assert captured =~ "#{pack_json} has been created with the pack2 pack"
assert captured =~ "Using .png .gif .jpeg extensions"
assert File.exists?(pack_json)
assert File.exists?(files_json)
captured =
capture_io(fn ->
Emoji.run([
"gen-pack",
url,
"--name",
name,
"--license",
"license",
"--homepage",
"homepage",
"--description",
"description",
"--files",
files_json,
"--extensions",
" .png .gif .jpeg "
])
end)
assert captured =~ "#{pack_json} has been updated with the pack2 pack"
on_exit(fn ->
File.rm!(pack_json)
File.rm!(files_json)
end)
end
end
end

View file

@ -12,26 +12,26 @@ defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do
user = insert(:user)
other_user = insert(:user)
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
CommonAPI.post(user, %{visibility: "public", status: "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
"visibility" => "unlisted",
"status" => "hey"
visibility: "unlisted",
status: "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "hey @#{other_user.nickname}"
visibility: "direct",
status: "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
"visibility" => "private",
"status" => "hey"
visibility: "private",
status: "hey"
})
end)

View file

@ -3,15 +3,21 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.UserTest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
import ExUnit.CaptureIO
import Mock
import Pleroma.Factory
setup_all do
Mix.shell(Mix.Shell.Process)
@ -87,12 +93,39 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "user is deleted" do
user = insert(:user)
Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
ObanHelpers.perform_all()
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
assert %{deactivated: true} = User.get_by_nickname(user.nickname)
refute User.get_by_nickname(user.nickname)
assert called(Pleroma.Web.Federator.publish(:_))
end
end
test "a remote user's create activity is deleted when the object has been pruned" do
user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "uguu"})
object = Object.normalize(post)
Object.prune(object)
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
ObanHelpers.perform_all()
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
assert %{deactivated: true} = User.get_by_nickname(user.nickname)
assert called(Pleroma.Web.Federator.publish(:_))
end
refute Activity.get_by_id(post.id)
end
test "no user to delete" do
@ -140,7 +173,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "user is unsubscribed" do
followed = insert(:user)
user = insert(:user)
User.follow(user, followed, "accept")
User.follow(user, followed, :follow_accept)
Mix.Tasks.Pleroma.User.run(["unsubscribe", user.nickname])

View file

@ -6,7 +6,10 @@ os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [
ExUnit.start(exclude: [:federated | os_exclude])
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
Mox.defmock(Pleroma.GunMock, for: Pleroma.Gun)
{:ok, _} = Application.ensure_all_started(:ex_machina)
ExUnit.after_suite(fn _results ->

View file

@ -58,7 +58,7 @@ defmodule Pleroma.Uploaders.S3Test do
name: "image-tet.jpg",
content_type: "image/jpg",
path: "test_folder/image-tet.jpg",
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
tempfile: Path.absname("test/instance_static/add/shortcode.png")
}
[file_upload: file_upload]

View file

@ -4,7 +4,6 @@
defmodule Pleroma.UserInviteTokenTest do
use ExUnit.Case, async: true
use Pleroma.DataCase
alias Pleroma.UserInviteToken
describe "valid_invite?/1 one time invites" do
@ -64,7 +63,6 @@ defmodule Pleroma.UserInviteTokenTest do
test "expires yesterday returns false", %{invite: invite} do
invite = %{invite | expires_at: Date.add(Date.utc_today(), -1)}
invite = Repo.insert!(invite)
refute UserInviteToken.valid_invite?(invite)
end
end
@ -82,7 +80,6 @@ defmodule Pleroma.UserInviteTokenTest do
test "overdue date and less uses returns false", %{invite: invite} do
invite = %{invite | expires_at: Date.add(Date.utc_today(), -1)}
invite = Repo.insert!(invite)
refute UserInviteToken.valid_invite?(invite)
end
@ -93,7 +90,6 @@ defmodule Pleroma.UserInviteTokenTest do
test "overdue date with more uses returns false", %{invite: invite} do
invite = %{invite | expires_at: Date.add(Date.utc_today(), -1), uses: 5}
invite = Repo.insert!(invite)
refute UserInviteToken.valid_invite?(invite)
end
end

View file

@ -172,6 +172,7 @@ defmodule Pleroma.UserSearchTest do
|> Map.put(:search_rank, nil)
|> Map.put(:search_type, nil)
|> Map.put(:last_digest_emailed_at, nil)
|> Map.put(:multi_factor_authentication_settings, nil)
|> Map.put(:notification_settings, nil)
assert user == expected

View file

@ -15,7 +15,6 @@ defmodule Pleroma.UserTest do
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import Mock
import Pleroma.Factory
import ExUnit.CaptureLog
@ -86,7 +85,7 @@ defmodule Pleroma.UserTest do
{:ok, user: insert(:user)}
end
test "outgoing_relations_ap_ids/1", %{user: user} do
test "outgoing_relationships_ap_ids/1", %{user: user} do
rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
ap_ids_by_rel =
@ -124,10 +123,10 @@ defmodule Pleroma.UserTest do
assert ap_ids_by_rel[:inverse_subscription] ==
Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
outgoing_relations_ap_ids = User.outgoing_relations_ap_ids(user, rel_types)
outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
assert ap_ids_by_rel ==
Enum.into(outgoing_relations_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
end
end
@ -194,7 +193,8 @@ defmodule Pleroma.UserTest do
CommonAPI.follow(pending_follower, locked)
CommonAPI.follow(pending_follower, locked)
CommonAPI.follow(accepted_follower, locked)
Pleroma.FollowingRelationship.update(accepted_follower, locked, "accept")
Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
assert [^pending_follower] = User.get_follow_requests(locked)
end
@ -319,7 +319,7 @@ defmodule Pleroma.UserTest do
following_address: "http://localhost:4001/users/fuser2/following"
})
{:ok, user} = User.follow(user, followed, "accept")
{:ok, user} = User.follow(user, followed, :follow_accept)
{:ok, user, _activity} = User.unfollow(user, followed)
@ -332,7 +332,7 @@ defmodule Pleroma.UserTest do
followed = insert(:user)
user = insert(:user)
{:ok, user} = User.follow(user, followed, "accept")
{:ok, user} = User.follow(user, followed, :follow_accept)
assert User.following(user) == [user.follower_address, followed.follower_address]
@ -353,7 +353,7 @@ defmodule Pleroma.UserTest do
test "test if a user is following another user" do
followed = insert(:user)
user = insert(:user)
User.follow(user, followed, "accept")
User.follow(user, followed, :follow_accept)
assert User.following?(user, followed)
refute User.following?(followed, user)
@ -581,7 +581,7 @@ defmodule Pleroma.UserTest do
{:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
assert user.source_data["endpoints"]
assert user.inbox
refute user.last_refreshed_at == orig_user.last_refreshed_at
end
@ -609,7 +609,7 @@ defmodule Pleroma.UserTest do
) <> "/followers"
end
describe "remote user creation changeset" do
describe "remote user changeset" do
@valid_remote %{
bio: "hello",
name: "Someone",
@ -621,28 +621,28 @@ defmodule Pleroma.UserTest do
setup do: clear_config([:instance, :user_name_length])
test "it confirms validity" do
cs = User.remote_user_creation(@valid_remote)
cs = User.remote_user_changeset(@valid_remote)
assert cs.valid?
end
test "it sets the follower_adress" do
cs = User.remote_user_creation(@valid_remote)
cs = User.remote_user_changeset(@valid_remote)
# remote users get a fake local follower address
assert cs.changes.follower_address ==
User.ap_followers(%User{nickname: @valid_remote[:nickname]})
end
test "it enforces the fqn format for nicknames" do
cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
assert Ecto.Changeset.get_field(cs, :local) == false
assert cs.changes.avatar
refute cs.valid?
end
test "it has required fields" do
[:name, :ap_id]
[:ap_id]
|> Enum.each(fn field ->
cs = User.remote_user_creation(Map.delete(@valid_remote, field))
cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
refute cs.valid?
end)
end
@ -755,8 +755,8 @@ defmodule Pleroma.UserTest do
]
{:ok, job} = User.follow_import(user1, identifiers)
result = ObanHelpers.perform(job)
assert {:ok, result} = ObanHelpers.perform(job)
assert is_list(result)
assert result == [user2, user3]
end
@ -978,14 +978,26 @@ defmodule Pleroma.UserTest do
]
{:ok, job} = User.blocks_import(user1, identifiers)
result = ObanHelpers.perform(job)
assert {:ok, result} = ObanHelpers.perform(job)
assert is_list(result)
assert result == [user2, user3]
end
end
describe "get_recipients_from_activity" do
test "works for announces" do
actor = insert(:user)
user = insert(:user, local: true)
{:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
recipients = User.get_recipients_from_activity(announce)
assert user in recipients
end
test "get recipients" do
actor = insert(:user)
user = insert(:user, local: true)
@ -995,7 +1007,7 @@ defmodule Pleroma.UserTest do
{:ok, activity} =
CommonAPI.post(actor, %{
"status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
})
assert Enum.map([actor, addressed], & &1.ap_id) --
@ -1017,7 +1029,7 @@ defmodule Pleroma.UserTest do
{:ok, activity} =
CommonAPI.post(actor, %{
"status" => "hey @#{addressed.nickname}"
status: "hey @#{addressed.nickname}"
})
assert Enum.map([actor, addressed], & &1.ap_id) --
@ -1078,7 +1090,7 @@ defmodule Pleroma.UserTest do
{:ok, user2} = User.follow(user2, user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}"})
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
activity = Repo.preload(activity, :bookmark)
@ -1114,24 +1126,15 @@ defmodule Pleroma.UserTest do
setup do: clear_config([:instance, :federating])
test ".delete_user_activities deletes all create activities", %{user: user} do
{:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
{:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
User.delete_user_activities(user)
# TODO: Remove favorites, repeats, delete activities.
# TODO: Test removal favorites, repeats, delete activities.
refute Activity.get_by_id(activity.id)
end
test "it deletes deactivated user" do
{:ok, user} = insert(:user, deactivated: true) |> User.set_cache()
{:ok, job} = User.delete(user)
{:ok, _user} = ObanHelpers.perform(job)
refute User.get_by_id(user.id)
end
test "it deletes a user, all follow relationships and all activities", %{user: user} do
test "it deactivates a user, all follow relationships and all activities", %{user: user} do
follower = insert(:user)
{:ok, follower} = User.follow(follower, user)
@ -1141,8 +1144,8 @@ defmodule Pleroma.UserTest do
object_two = insert(:note, user: follower)
activity_two = insert(:note_activity, user: follower, note: object_two)
{:ok, like, _} = CommonAPI.favorite(activity_two.id, user)
{:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
{:ok, like} = CommonAPI.favorite(user, activity_two.id)
{:ok, like_two} = CommonAPI.favorite(follower, activity.id)
{:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
{:ok, job} = User.delete(user)
@ -1151,8 +1154,7 @@ defmodule Pleroma.UserTest do
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, user)
refute User.get_by_id(user.id)
assert {:ok, nil} == Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
assert %{deactivated: true} = User.get_by_id(user.id)
user_activities =
user.ap_id
@ -1167,89 +1169,12 @@ defmodule Pleroma.UserTest do
refute Activity.get_by_id(like_two.id)
refute Activity.get_by_id(repeat.id)
end
test_with_mock "it sends out User Delete activity",
%{user: user},
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
Pleroma.Config.put([:instance, :federating], true)
{:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
{:ok, _} = User.follow(follower, user)
{:ok, job} = User.delete(user)
{:ok, _user} = ObanHelpers.perform(job)
assert ObanHelpers.member?(
%{
"op" => "publish_one",
"params" => %{
"inbox" => "http://mastodon.example.org/inbox",
"id" => "pleroma:fakeid"
}
},
all_enqueued(worker: Pleroma.Workers.PublisherWorker)
)
end
end
test "get_public_key_for_ap_id fetches a user that's not in the db" do
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
end
describe "insert or update a user from given data" do
test "with normal data" do
user = insert(:user, %{nickname: "nick@name.de"})
data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
assert {:ok, %User{}} = User.insert_or_update_user(data)
end
test "with overly long fields" do
current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255)
user = insert(:user, nickname: "nickname@supergood.domain")
data = %{
ap_id: user.ap_id,
name: user.name,
nickname: user.nickname,
fields: [
%{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}
]
}
assert {:ok, %User{}} = User.insert_or_update_user(data)
end
test "with an overly long bio" do
current_max_length = Pleroma.Config.get([:instance, :user_bio_length], 5000)
user = insert(:user, nickname: "nickname@supergood.domain")
data = %{
ap_id: user.ap_id,
name: user.name,
nickname: user.nickname,
bio: String.duplicate("h", current_max_length + 1)
}
assert {:ok, %User{}} = User.insert_or_update_user(data)
end
test "with an overly long display name" do
current_max_length = Pleroma.Config.get([:instance, :user_name_length], 100)
user = insert(:user, nickname: "nickname@supergood.domain")
data = %{
ap_id: user.ap_id,
name: String.duplicate("h", current_max_length + 1),
nickname: user.nickname
}
assert {:ok, %User{}} = User.insert_or_update_user(data)
end
end
describe "per-user rich-text filtering" do
test "html_filter_policy returns default policies, when rich-text is enabled" do
user = insert(:user)
@ -1404,7 +1329,7 @@ defmodule Pleroma.UserTest do
bio = "A.k.a. @nick@domain.com"
expected_text =
~s(A.k.a. <span class="h-card"><a data-user="#{remote_user.id}" class="u-url mention" href="#{
~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
remote_user.ap_id
}" rel="ugc">@<span>nick@domain.com</span></a></span>)
@ -1486,7 +1411,7 @@ defmodule Pleroma.UserTest do
{:ok, _} =
CommonAPI.post(user, %{
"status" => "hey @#{to.nickname}"
status: "hey @#{to.nickname}"
})
end)
@ -1518,12 +1443,12 @@ defmodule Pleroma.UserTest do
Enum.each(recipients, fn to ->
{:ok, _} =
CommonAPI.post(sender, %{
"status" => "hey @#{to.nickname}"
status: "hey @#{to.nickname}"
})
{:ok, _} =
CommonAPI.post(sender, %{
"status" => "hey again @#{to.nickname}"
status: "hey again @#{to.nickname}"
})
end)

View file

@ -341,7 +341,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "cached purged after activity deletion", %{conn: conn} do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "cofe"})
{:ok, activity} = CommonAPI.post(user, %{status: "cofe"})
uuid = String.split(activity.data["id"], "/") |> List.last()
@ -765,51 +765,110 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
end
describe "POST /users/:nickname/outbox" do
test "it rejects posts from other users / unauuthenticated users", %{conn: conn} do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
describe "POST /users/:nickname/outbox (C2S)" do
setup do
[
activity: %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"object" => %{"type" => "Note", "content" => "AP C2S test"},
"to" => "https://www.w3.org/ns/activitystreams#Public",
"cc" => []
}
]
end
test "it rejects posts from other users / unauthenticated users", %{
conn: conn,
activity: activity
} do
user = insert(:user)
other_user = insert(:user)
conn = put_req_header(conn, "content-type", "application/activity+json")
conn
|> post("/users/#{user.nickname}/outbox", data)
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(403)
conn
|> assign(:user, other_user)
|> post("/users/#{user.nickname}/outbox", data)
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(403)
end
test "it inserts an incoming create activity into the database", %{conn: conn} do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
test "it inserts an incoming create activity into the database", %{
conn: conn,
activity: activity
} do
user = insert(:user)
conn =
result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
result = json_response(conn, 201)
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(201)
assert Activity.get_by_ap_id(result["id"])
assert result["object"]
assert %Object{data: object} = Object.normalize(result["object"])
assert object["content"] == activity["object"]["content"]
end
test "it rejects an incoming activity with bogus type", %{conn: conn} do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do
user = insert(:user)
data =
data
|> Map.put("type", "BadType")
activity =
activity
|> put_in(["object", "type"], "Benis")
_result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(400)
end
test "it inserts an incoming sensitive activity into the database", %{
conn: conn,
activity: activity
} do
user = insert(:user)
conn = assign(conn, :user, user)
object = Map.put(activity["object"], "sensitive", true)
activity = Map.put(activity, "object", object)
response =
conn
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(201)
assert Activity.get_by_ap_id(response["id"])
assert response["object"]
assert %Object{data: response_object} = Object.normalize(response["object"])
assert response_object["sensitive"] == true
assert response_object["content"] == activity["object"]["content"]
representation =
conn
|> put_req_header("accept", "application/activity+json")
|> get(response["id"])
|> json_response(200)
assert representation["object"]["sensitive"] == true
end
test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do
user = insert(:user)
activity = Map.put(activity, "type", "BadType")
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
|> post("/users/#{user.nickname}/outbox", activity)
assert json_response(conn, 400)
end
@ -1019,12 +1078,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert result["totalItems"] == 15
end
test "returns 403 if requester is not logged in", %{conn: conn} do
test "does not require authentication", %{conn: conn} do
user = insert(:user)
conn
|> get("/users/#{user.nickname}/followers")
|> json_response(403)
|> json_response(200)
end
end
@ -1116,12 +1175,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert result["totalItems"] == 15
end
test "returns 403 if requester is not logged in", %{conn: conn} do
test "does not require authentication", %{conn: conn} do
user = insert(:user)
conn
|> get("/users/#{user.nickname}/following")
|> json_response(403)
|> json_response(200)
end
end
@ -1239,16 +1298,56 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
filename: "an_image.jpg"
}
conn =
object =
conn
|> assign(:user, user)
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|> json_response(:created)
assert object = json_response(conn, :created)
assert object["name"] == desc
assert object["type"] == "Document"
assert object["actor"] == user.ap_id
assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"]
assert is_binary(object_href)
assert object_mediatype == "image/jpeg"
activity_request = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"object" => %{
"type" => "Note",
"content" => "AP C2S test, attachment",
"attachment" => [object]
},
"to" => "https://www.w3.org/ns/activitystreams#Public",
"cc" => []
}
activity_response =
conn
|> assign(:user, user)
|> post("/users/#{user.nickname}/outbox", activity_request)
|> json_response(:created)
assert activity_response["id"]
assert activity_response["object"]
assert activity_response["actor"] == user.ap_id
assert %Object{data: %{"attachment" => [attachment]}} =
Object.normalize(activity_response["object"])
assert attachment["type"] == "Document"
assert attachment["name"] == desc
assert [
%{
"href" => ^object_href,
"type" => "Link",
"mediaType" => ^object_mediatype
}
] = attachment["url"]
# Fails if unauthenticated
conn
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|> json_response(403)

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
@ -110,6 +110,15 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
end
describe "with unknown actors" do
setup do
Tesla.Mock.mock(fn
%{method: :get, url: "http://invalid.actor"} ->
%Tesla.Env{status: 500, body: ""}
end)
:ok
end
test "it rejects posts without links" do
message =
@linkless_message

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrependedTest do

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicyTest do

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
@ -20,26 +20,38 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
:ok
end
defp get_old_message do
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
end
defp get_new_message do
old_message = get_old_message()
new_object =
old_message
|> Map.get("object")
|> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601())
old_message
|> Map.put("object", new_object)
end
describe "with reject action" do
test "it rejects an old post" do
Config.put([:mrf_object_age, :actions], [:reject])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
data = get_old_message()
{:reject, _} = ObjectAgePolicy.filter(data)
assert match?({:reject, _}, ObjectAgePolicy.filter(data))
end
test "it allows a new post" do
Config.put([:mrf_object_age, :actions], [:reject])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
|> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601())
data = get_new_message()
{:ok, _} = ObjectAgePolicy.filter(data)
assert match?({:ok, _}, ObjectAgePolicy.filter(data))
end
end
@ -47,9 +59,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
test "it delists an old post" do
Config.put([:mrf_object_age, :actions], [:delist])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
data = get_old_message()
{:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"])
@ -61,14 +71,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
test "it allows a new post" do
Config.put([:mrf_object_age, :actions], [:delist])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
|> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601())
data = get_new_message()
{:ok, _user} = User.get_or_fetch_by_ap_id(data["actor"])
{:ok, ^data} = ObjectAgePolicy.filter(data)
assert match?({:ok, ^data}, ObjectAgePolicy.filter(data))
end
end
@ -76,9 +83,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
test "it strips followers collections from an old post" do
Config.put([:mrf_object_age, :actions], [:strip_followers])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
data = get_old_message()
{:ok, user} = User.get_or_fetch_by_ap_id(data["actor"])
@ -91,14 +96,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
test "it allows a new post" do
Config.put([:mrf_object_age, :actions], [:strip_followers])
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
|> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601())
data = get_new_message()
{:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"])
{:ok, ^data} = ObjectAgePolicy.filter(data)
assert match?({:ok, ^data}, ObjectAgePolicy.filter(data))
end
end
end

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
@ -17,7 +17,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
reject: [],
accept: [],
avatar_removal: [],
banner_removal: []
banner_removal: [],
reject_deletes: []
)
describe "when :media_removal" do
@ -382,6 +383,66 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
end
describe "when :reject_deletes is empty" do
setup do: Config.put([:mrf_simple, :reject_deletes], [])
test "it accepts deletions even from rejected servers" do
Config.put([:mrf_simple, :reject], ["remote.instance"])
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
end
test "it accepts deletions even from non-whitelisted servers" do
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
end
end
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"])
test "it accepts deletions even from rejected servers" do
Config.put([:mrf_simple, :reject], ["remote.instance"])
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
end
test "it accepts deletions even from non-whitelisted servers" do
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
end
end
describe "when :reject_deletes has a matching host" do
setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"])
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:reject, nil}
end
end
describe "when :reject_deletes match with wildcard domain" do
setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"])
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
assert SimplePolicy.filter(deletion_message) == {:reject, nil}
end
end
defp build_local_message do
%{
"actor" => "#{Pleroma.Web.base_url()}/users/alice",
@ -408,4 +469,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
"type" => "Person"
}
end
defp build_remote_deletion_message do
%{
"type" => "Delete",
"actor" => "https://remote.instance/users/bob"
}
end
end

View file

@ -0,0 +1,283 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
use Pleroma.DataCase
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
describe "EmojiReacts" do
setup do
user = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
object = Pleroma.Object.get_by_ap_id(post_activity.data["object"])
{:ok, valid_emoji_react, []} = Builder.emoji_react(user, object, "👌")
%{user: user, post_activity: post_activity, valid_emoji_react: valid_emoji_react}
end
test "it validates a valid EmojiReact", %{valid_emoji_react: valid_emoji_react} do
assert {:ok, _, _} = ObjectValidator.validate(valid_emoji_react, [])
end
test "it is not valid without a 'content' field", %{valid_emoji_react: valid_emoji_react} do
without_content =
valid_emoji_react
|> Map.delete("content")
{:error, cng} = ObjectValidator.validate(without_content, [])
refute cng.valid?
assert {:content, {"can't be blank", [validation: :required]}} in cng.errors
end
test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do
without_emoji_content =
valid_emoji_react
|> Map.put("content", "x")
{:error, cng} = ObjectValidator.validate(without_emoji_content, [])
refute cng.valid?
assert {:content, {"must be a single character emoji", []}} in cng.errors
end
end
describe "Undos" do
setup do
user = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
{:ok, like} = CommonAPI.favorite(user, post_activity.id)
{:ok, valid_like_undo, []} = Builder.undo(user, like)
%{user: user, like: like, valid_like_undo: valid_like_undo}
end
test "it validates a basic like undo", %{valid_like_undo: valid_like_undo} do
assert {:ok, _, _} = ObjectValidator.validate(valid_like_undo, [])
end
test "it does not validate if the actor of the undo is not the actor of the object", %{
valid_like_undo: valid_like_undo
} do
other_user = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo")
bad_actor =
valid_like_undo
|> Map.put("actor", other_user.ap_id)
{:error, cng} = ObjectValidator.validate(bad_actor, [])
assert {:actor, {"not the same as object actor", []}} in cng.errors
end
test "it does not validate if the object is missing", %{valid_like_undo: valid_like_undo} do
missing_object =
valid_like_undo
|> Map.put("object", "https://gensokyo.2hu/objects/1")
{:error, cng} = ObjectValidator.validate(missing_object, [])
assert {:object, {"can't find object", []}} in cng.errors
assert length(cng.errors) == 1
end
end
describe "deletes" do
setup do
user = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "cancel me daddy"})
{:ok, valid_post_delete, _} = Builder.delete(user, post_activity.data["object"])
{:ok, valid_user_delete, _} = Builder.delete(user, user.ap_id)
%{user: user, valid_post_delete: valid_post_delete, valid_user_delete: valid_user_delete}
end
test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete} do
{:ok, valid_post_delete, _} = ObjectValidator.validate(valid_post_delete, [])
assert valid_post_delete["deleted_activity_id"]
end
test "it is invalid if the object isn't in a list of certain types", %{
valid_post_delete: valid_post_delete
} do
object = Object.get_by_ap_id(valid_post_delete["object"])
data =
object.data
|> Map.put("type", "Like")
{:ok, _object} =
object
|> Ecto.Changeset.change(%{data: data})
|> Object.update_and_set_cache()
{:error, cng} = ObjectValidator.validate(valid_post_delete, [])
assert {:object, {"object not in allowed types", []}} in cng.errors
end
test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do
assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, []))
end
test "it's invalid if the id is missing", %{valid_post_delete: valid_post_delete} do
no_id =
valid_post_delete
|> Map.delete("id")
{:error, cng} = ObjectValidator.validate(no_id, [])
assert {:id, {"can't be blank", [validation: :required]}} in cng.errors
end
test "it's invalid if the object doesn't exist", %{valid_post_delete: valid_post_delete} do
missing_object =
valid_post_delete
|> Map.put("object", "http://does.not/exist")
{:error, cng} = ObjectValidator.validate(missing_object, [])
assert {:object, {"can't find object", []}} in cng.errors
end
test "it's invalid if the actor of the object and the actor of delete are from different domains",
%{valid_post_delete: valid_post_delete} do
valid_user = insert(:user)
valid_other_actor =
valid_post_delete
|> Map.put("actor", valid_user.ap_id)
assert match?({:ok, _, _}, ObjectValidator.validate(valid_other_actor, []))
invalid_other_actor =
valid_post_delete
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
{:error, cng} = ObjectValidator.validate(invalid_other_actor, [])
assert {:actor, {"is not allowed to delete object", []}} in cng.errors
end
test "it's valid if the actor of the object is a local superuser",
%{valid_post_delete: valid_post_delete} do
user =
insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo")
valid_other_actor =
valid_post_delete
|> Map.put("actor", user.ap_id)
{:ok, _, meta} = ObjectValidator.validate(valid_other_actor, [])
assert meta[:do_not_federate]
end
end
describe "likes" do
setup do
user = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
valid_like = %{
"to" => [user.ap_id],
"cc" => [],
"type" => "Like",
"id" => Utils.generate_activity_id(),
"object" => post_activity.data["object"],
"actor" => user.ap_id,
"context" => "a context"
}
%{valid_like: valid_like, user: user, post_activity: post_activity}
end
test "returns ok when called in the ObjectValidator", %{valid_like: valid_like} do
{:ok, object, _meta} = ObjectValidator.validate(valid_like, [])
assert "id" in Map.keys(object)
end
test "is valid for a valid object", %{valid_like: valid_like} do
assert LikeValidator.cast_and_validate(valid_like).valid?
end
test "sets the 'to' field to the object actor if no recipients are given", %{
valid_like: valid_like,
user: user
} do
without_recipients =
valid_like
|> Map.delete("to")
{:ok, object, _meta} = ObjectValidator.validate(without_recipients, [])
assert object["to"] == [user.ap_id]
end
test "sets the context field to the context of the object if no context is given", %{
valid_like: valid_like,
post_activity: post_activity
} do
without_context =
valid_like
|> Map.delete("context")
{:ok, object, _meta} = ObjectValidator.validate(without_context, [])
assert object["context"] == post_activity.data["context"]
end
test "it errors when the actor is missing or not known", %{valid_like: valid_like} do
without_actor = Map.delete(valid_like, "actor")
refute LikeValidator.cast_and_validate(without_actor).valid?
with_invalid_actor = Map.put(valid_like, "actor", "invalidactor")
refute LikeValidator.cast_and_validate(with_invalid_actor).valid?
end
test "it errors when the object is missing or not known", %{valid_like: valid_like} do
without_object = Map.delete(valid_like, "object")
refute LikeValidator.cast_and_validate(without_object).valid?
with_invalid_object = Map.put(valid_like, "object", "invalidobject")
refute LikeValidator.cast_and_validate(with_invalid_object).valid?
end
test "it errors when the actor has already like the object", %{
valid_like: valid_like,
user: user,
post_activity: post_activity
} do
_like = CommonAPI.favorite(user, post_activity.id)
refute LikeValidator.cast_and_validate(valid_like).valid?
end
test "it works when actor or object are wrapped in maps", %{valid_like: valid_like} do
wrapped_like =
valid_like
|> Map.put("actor", %{"id" => valid_like["actor"]})
|> Map.put("object", %{"id" => valid_like["object"]})
validated = LikeValidator.cast_and_validate(wrapped_like)
assert validated.valid?
assert {:actor, valid_like["actor"]} in validated.changes
assert {:object, valid_like["object"]} in validated.changes
end
end
end

View file

@ -0,0 +1,35 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do
use Pleroma.DataCase
alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
alias Pleroma.Web.ActivityPub.Utils
import Pleroma.Factory
describe "Notes" do
setup do
user = insert(:user)
note = %{
"id" => Utils.generate_activity_id(),
"type" => "Note",
"actor" => user.ap_id,
"to" => [user.follower_address],
"cc" => [],
"content" => "Hellow this is content.",
"context" => "xxx",
"summary" => "a post"
}
%{user: user, note: note}
end
test "a basic note validates", %{note: note} do
%{valid?: true} = NoteValidator.cast_and_validate(note)
end
end
end

View file

@ -0,0 +1,32 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do
alias Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTime
use Pleroma.DataCase
test "it validates an xsd:Datetime" do
valid_strings = [
"2004-04-12T13:20:00",
"2004-04-12T13:20:15.5",
"2004-04-12T13:20:00-05:00",
"2004-04-12T13:20:00Z"
]
invalid_strings = [
"2004-04-12T13:00",
"2004-04-1213:20:00",
"99-04-12T13:00",
"2004-04-12"
]
assert {:ok, "2004-04-01T12:00:00Z"} == DateTime.cast("2004-04-01T12:00:00Z")
Enum.each(valid_strings, fn date_time ->
result = DateTime.cast(date_time)
assert {:ok, _} = result
end)
Enum.each(invalid_strings, fn date_time ->
result = DateTime.cast(date_time)
assert :error == result
end)
end
end

View file

@ -0,0 +1,37 @@
defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do
alias Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID
use Pleroma.DataCase
@uris [
"http://lain.com/users/lain",
"http://lain.com",
"https://lain.com/object/1"
]
@non_uris [
"https://",
"rin",
1,
:x,
%{"1" => 2}
]
test "it accepts http uris" do
Enum.each(@uris, fn uri ->
assert {:ok, uri} == ObjectID.cast(uri)
end)
end
test "it accepts an object with a nested uri id" do
Enum.each(@uris, fn uri ->
assert {:ok, uri} == ObjectID.cast(%{"id" => uri})
end)
end
test "it rejects non-uri strings" do
Enum.each(@non_uris, fn non_uri ->
assert :error == ObjectID.cast(non_uri)
assert :error == ObjectID.cast(%{"id" => non_uri})
end)
end
end

View file

@ -0,0 +1,27 @@
defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do
alias Pleroma.Web.ActivityPub.ObjectValidators.Types.Recipients
use Pleroma.DataCase
test "it asserts that all elements of the list are object ids" do
list = ["https://lain.com/users/lain", "invalid"]
assert :error == Recipients.cast(list)
end
test "it works with a list" do
list = ["https://lain.com/users/lain"]
assert {:ok, list} == Recipients.cast(list)
end
test "it works with a list with whole objects" do
list = ["https://lain.com/users/lain", %{"id" => "https://gensokyo.2hu/users/raymoo"}]
resulting_list = ["https://gensokyo.2hu/users/raymoo", "https://lain.com/users/lain"]
assert {:ok, resulting_list} == Recipients.cast(list)
end
test "it turns a single string into a list" do
recipient = "https://lain.com/users/lain"
assert {:ok, [recipient]} == Recipients.cast(recipient)
end
end

View file

@ -0,0 +1,87 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.PipelineTest do
use Pleroma.DataCase
import Mock
import Pleroma.Factory
describe "common_pipeline/2" do
test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
activity = insert(:note_activity)
meta = [local: true]
with_mocks([
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
{
Pleroma.Web.ActivityPub.MRF,
[],
[filter: fn o -> {:ok, o} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
[],
[persist: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.SideEffects,
[],
[handle: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.Federator,
[],
[publish: fn _o -> :ok end]
}
]) do
assert {:ok, ^activity, ^meta} =
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
assert_called(Pleroma.Web.Federator.publish(activity))
end
end
test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do
activity = insert(:note_activity)
meta = [local: false]
with_mocks([
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
{
Pleroma.Web.ActivityPub.MRF,
[],
[filter: fn o -> {:ok, o} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
[],
[persist: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.SideEffects,
[],
[handle: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.Federator,
[],
[]
}
]) do
assert {:ok, ^activity, ^meta} =
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end
end
end
end

View file

@ -48,10 +48,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
describe "determine_inbox/2" do
test "it returns sharedInbox for messages involving as:Public in to" do
user =
insert(:user, %{
source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
})
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
activity = %Activity{
data: %{"to" => [@as_public], "cc" => [user.follower_address]}
@ -61,10 +58,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end
test "it returns sharedInbox for messages involving as:Public in cc" do
user =
insert(:user, %{
source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
})
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
activity = %Activity{
data: %{"cc" => [@as_public], "to" => [user.follower_address]}
@ -74,11 +68,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end
test "it returns sharedInbox for messages involving multiple recipients in to" do
user =
insert(:user, %{
source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
})
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
user_two = insert(:user)
user_three = insert(:user)
@ -90,11 +80,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end
test "it returns sharedInbox for messages involving multiple recipients in cc" do
user =
insert(:user, %{
source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
})
user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
user_two = insert(:user)
user_three = insert(:user)
@ -107,12 +93,10 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
test "it returns sharedInbox for messages involving multiple recipients in total" do
user =
insert(:user,
source_data: %{
"inbox" => "http://example.com/personal-inbox",
"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
}
)
insert(:user, %{
shared_inbox: "http://example.com/inbox",
inbox: "http://example.com/personal-inbox"
})
user_two = insert(:user)
@ -125,12 +109,10 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
test "it returns inbox for messages involving single recipients in total" do
user =
insert(:user,
source_data: %{
"inbox" => "http://example.com/personal-inbox",
"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
}
)
insert(:user, %{
shared_inbox: "http://example.com/inbox",
inbox: "http://example.com/personal-inbox"
})
activity = %Activity{
data: %{"to" => [user.ap_id], "cc" => []}
@ -258,11 +240,11 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
[:passthrough],
[] do
follower =
insert(:user,
insert(:user, %{
local: false,
source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"},
inbox: "https://domain.com/users/nick1/inbox",
ap_enabled: true
)
})
actor = insert(:user, follower_address: follower.ap_id)
user = insert(:user)
@ -295,14 +277,14 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
fetcher =
insert(:user,
local: false,
source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"},
inbox: "https://domain.com/users/nick1/inbox",
ap_enabled: true
)
another_fetcher =
insert(:user,
local: false,
source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"},
inbox: "https://domain2.com/users/nick1/inbox",
ap_enabled: true
)

View file

@ -89,6 +89,11 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
}
)
Tesla.Mock.mock(fn
%{method: :get, url: "http://mastodon.example.org/eee/99541947525187367"} ->
%Tesla.Env{status: 500, body: ""}
end)
assert capture_log(fn ->
assert Relay.publish(activity) == {:error, nil}
end) =~ "[error] error: nil"

View file

@ -0,0 +1,267 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.SideEffects
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
import Mock
describe "delete objects" do
setup do
user = insert(:user)
other_user = insert(:user)
{:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
{:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
{:ok, favorite} = CommonAPI.favorite(user, post.id)
object = Object.normalize(post)
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
%{
user: user,
delete: delete,
post: post,
object: object,
delete_user: delete_user,
op: op,
favorite: favorite
}
end
test "it handles object deletions", %{
delete: delete,
post: post,
object: object,
user: user,
op: op,
favorite: favorite
} do
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
stream_out: fn _ -> nil end,
stream_out_participations: fn _, _ -> nil end do
{:ok, delete, _} = SideEffects.handle(delete)
user = User.get_cached_by_ap_id(object.data["actor"])
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
end
object = Object.get_by_id(object.id)
assert object.data["type"] == "Tombstone"
refute Activity.get_by_id(post.id)
refute Activity.get_by_id(favorite.id)
user = User.get_by_id(user.id)
assert user.note_count == 0
object = Object.normalize(op.data["object"], false)
assert object.data["repliesCount"] == 0
end
test "it handles object deletions when the object itself has been pruned", %{
delete: delete,
post: post,
object: object,
user: user,
op: op
} do
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
stream_out: fn _ -> nil end,
stream_out_participations: fn _, _ -> nil end do
{:ok, delete, _} = SideEffects.handle(delete)
user = User.get_cached_by_ap_id(object.data["actor"])
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
end
object = Object.get_by_id(object.id)
assert object.data["type"] == "Tombstone"
refute Activity.get_by_id(post.id)
user = User.get_by_id(user.id)
assert user.note_count == 0
object = Object.normalize(op.data["object"], false)
assert object.data["repliesCount"] == 0
end
test "it handles user deletions", %{delete_user: delete, user: user} do
{:ok, _delete, _} = SideEffects.handle(delete)
ObanHelpers.perform_all()
assert User.get_cached_by_ap_id(user.ap_id).deactivated
end
end
describe "EmojiReact objects" do
setup do
poster = insert(:user)
user = insert(:user)
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
{:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
%{emoji_react: emoji_react, user: user, poster: poster}
end
test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
{:ok, emoji_react, _} = SideEffects.handle(emoji_react)
object = Object.get_by_ap_id(emoji_react.data["object"])
assert object.data["reaction_count"] == 1
assert ["👌", [user.ap_id]] in object.data["reactions"]
end
test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
{:ok, emoji_react, _} = SideEffects.handle(emoji_react)
assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
end
end
describe "Undo objects" do
setup do
poster = insert(:user)
user = insert(:user)
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, like} = CommonAPI.favorite(user, post.id)
{:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
{:ok, announce, _} = CommonAPI.repeat(post.id, user)
{:ok, block} = ActivityPub.block(user, poster)
User.block(user, poster)
{:ok, undo_data, _meta} = Builder.undo(user, like)
{:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
{:ok, undo_data, _meta} = Builder.undo(user, reaction)
{:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
{:ok, undo_data, _meta} = Builder.undo(user, announce)
{:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
{:ok, undo_data, _meta} = Builder.undo(user, block)
{:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
%{
like_undo: like_undo,
post: post,
like: like,
reaction_undo: reaction_undo,
reaction: reaction,
announce_undo: announce_undo,
announce: announce,
block_undo: block_undo,
block: block,
poster: poster,
user: user
}
end
test "deletes the original block", %{block_undo: block_undo, block: block} do
{:ok, _block_undo, _} = SideEffects.handle(block_undo)
refute Activity.get_by_id(block.id)
end
test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
blocker = User.get_by_ap_id(block.data["actor"])
blocked = User.get_by_ap_id(block.data["object"])
{:ok, _block_undo, _} = SideEffects.handle(block_undo)
refute User.blocks?(blocker, blocked)
end
test "an announce undo removes the announce from the object", %{
announce_undo: announce_undo,
post: post
} do
{:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
object = Object.get_by_ap_id(post.data["object"])
assert object.data["announcement_count"] == 0
assert object.data["announcements"] == []
end
test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
{:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
refute Activity.get_by_id(announce.id)
end
test "a reaction undo removes the reaction from the object", %{
reaction_undo: reaction_undo,
post: post
} do
{:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
object = Object.get_by_ap_id(post.data["object"])
assert object.data["reaction_count"] == 0
assert object.data["reactions"] == []
end
test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
{:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
refute Activity.get_by_id(reaction.id)
end
test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
{:ok, _like_undo, _} = SideEffects.handle(like_undo)
object = Object.get_by_ap_id(post.data["object"])
assert object.data["like_count"] == 0
assert object.data["likes"] == []
end
test "deletes the original like", %{like_undo: like_undo, like: like} do
{:ok, _like_undo, _} = SideEffects.handle(like_undo)
refute Activity.get_by_id(like.id)
end
end
describe "like objects" do
setup do
poster = insert(:user)
user = insert(:user)
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, like_data, _meta} = Builder.like(user, post.object)
{:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
%{like: like, user: user, poster: poster}
end
test "add the like to the original object", %{like: like, user: user} do
{:ok, like, _} = SideEffects.handle(like)
object = Object.get_by_ap_id(like.data["object"])
assert object.data["like_count"] == 1
assert user.ap_id in object.data["likes"]
end
test "creates a notification", %{like: like, poster: poster} do
{:ok, like, _} = SideEffects.handle(like)
assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
end
end
end

View file

@ -0,0 +1,114 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
test "it works for incoming deletes" do
activity = insert(:note_activity)
deleting_user = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete.json")
|> Poison.decode!()
|> Map.put("actor", deleting_user.ap_id)
|> put_in(["object", "id"], activity.data["object"])
{:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
Transmogrifier.handle_incoming(data)
assert id == data["id"]
# We delete the Create activity because we base our timelines on it.
# This should be changed after we unify objects and activities
refute Activity.get_by_id(activity.id)
assert actor == deleting_user.ap_id
# Objects are replaced by a tombstone object.
object = Object.normalize(activity.data["object"])
assert object.data["type"] == "Tombstone"
end
test "it works for incoming when the object has been pruned" do
activity = insert(:note_activity)
{:ok, object} =
Object.normalize(activity.data["object"])
|> Repo.delete()
Cachex.del(:object_cache, "object:#{object.data["id"]}")
deleting_user = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete.json")
|> Poison.decode!()
|> Map.put("actor", deleting_user.ap_id)
|> put_in(["object", "id"], activity.data["object"])
{:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
Transmogrifier.handle_incoming(data)
assert id == data["id"]
# We delete the Create activity because we base our timelines on it.
# This should be changed after we unify objects and activities
refute Activity.get_by_id(activity.id)
assert actor == deleting_user.ap_id
end
test "it fails for incoming deletes with spoofed origin" do
activity = insert(:note_activity)
%{ap_id: ap_id} = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo")
data =
File.read!("test/fixtures/mastodon-delete.json")
|> Poison.decode!()
|> Map.put("actor", ap_id)
|> put_in(["object", "id"], activity.data["object"])
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
end
@tag capture_log: true
test "it works for incoming user deletes" do
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
data =
File.read!("test/fixtures/mastodon-delete-user.json")
|> Poison.decode!()
{:ok, _} = Transmogrifier.handle_incoming(data)
ObanHelpers.perform_all()
assert User.get_cached_by_ap_id(ap_id).deactivated
end
test "it fails for incoming user deletes with spoofed origin" do
%{ap_id: ap_id} = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete-user.json")
|> Poison.decode!()
|> Map.put("actor", ap_id)
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
assert User.get_cached_by_ap_id(ap_id)
end
end

Some files were not shown because too many files have changed in this diff Show more