Merge remote-tracking branch 'origin/develop' into HEAD
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
c592a0e58d
184 changed files with 1738 additions and 1213 deletions
1
test/fixtures/ccworld-ap-bridge_note.json
vendored
Normal file
1
test/fixtures/ccworld-ap-bridge_note.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"@context":"https://www.w3.org/ns/activitystreams","type":"Note","id":"https://cc.mkdir.uk/ap/note/e5d1d0a1-1ab3-4498-9949-588e3fdea286","attributedTo":"https://cc.mkdir.uk/ap/acct/hiira","inReplyTo":"","quoteUrl":"","content":"おはコンー","published":"2024-01-19T22:08:05Z","to":["https://www.w3.org/ns/activitystreams#Public"],"tag":null,"attachment":[],"object":null}
|
||||
12
test/fixtures/rich_media/google.html
vendored
Normal file
12
test/fixtures/rich_media/google.html
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<meta property="og:url" content="https://google.com">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="Google">
|
||||
<meta property="og:description" content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.">
|
||||
<meta property="og:image" content="">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:domain" content="google.com">
|
||||
<meta property="twitter:url" content="https://google.com">
|
||||
<meta name="twitter:title" content="Google">
|
||||
<meta name="twitter:description" content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.">
|
||||
<meta name="twitter:image" content="">
|
||||
2
test/fixtures/rich_media/oembed.html
vendored
2
test/fixtures/rich_media/oembed.html
vendored
|
|
@ -1,3 +1,3 @@
|
|||
<link rel="alternate" type="application/json+oembed"
|
||||
href="http://example.com/oembed.json"
|
||||
href="https://example.com/oembed.json"
|
||||
title="Bacon Lollys oEmbed Profile" />
|
||||
|
|
|
|||
12
test/fixtures/rich_media/yahoo.html
vendored
Normal file
12
test/fixtures/rich_media/yahoo.html
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<meta property="og:url" content="https://yahoo.com">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="Yahoo | Mail, Weather, Search, Politics, News, Finance, Sports & Videos">
|
||||
<meta property="og:description" content="Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!">
|
||||
<meta property="og:image" content="https://s.yimg.com/cv/apiv2/social/images/yahoo_default_logo.png">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:domain" content="yahoo.com">
|
||||
<meta property="twitter:url" content="https://yahoo.com">
|
||||
<meta name="twitter:title" content="Yahoo | Mail, Weather, Search, Politics, News, Finance, Sports & Videos">
|
||||
<meta name="twitter:description" content="Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!">
|
||||
<meta name="twitter:image" content="https://s.yimg.com/cv/apiv2/social/images/yahoo_default_logo.png">
|
||||
|
|
@ -6,26 +6,26 @@ defmodule Pleroma.EmojiTest do
|
|||
use ExUnit.Case, async: true
|
||||
alias Pleroma.Emoji
|
||||
|
||||
describe "is_unicode_emoji?/1" do
|
||||
describe "unicode?/1" do
|
||||
test "tells if a string is an unicode emoji" do
|
||||
refute Emoji.is_unicode_emoji?("X")
|
||||
refute Emoji.is_unicode_emoji?("ね")
|
||||
refute Emoji.unicode?("X")
|
||||
refute Emoji.unicode?("ね")
|
||||
|
||||
# Only accept fully-qualified (RGI) emoji
|
||||
# See http://www.unicode.org/reports/tr51/
|
||||
refute Emoji.is_unicode_emoji?("❤")
|
||||
refute Emoji.is_unicode_emoji?("☂")
|
||||
refute Emoji.unicode?("❤")
|
||||
refute Emoji.unicode?("☂")
|
||||
|
||||
assert Emoji.is_unicode_emoji?("🥺")
|
||||
assert Emoji.is_unicode_emoji?("🤰")
|
||||
assert Emoji.is_unicode_emoji?("❤️")
|
||||
assert Emoji.is_unicode_emoji?("🏳️⚧️")
|
||||
assert Emoji.is_unicode_emoji?("🫵")
|
||||
assert Emoji.unicode?("🥺")
|
||||
assert Emoji.unicode?("🤰")
|
||||
assert Emoji.unicode?("❤️")
|
||||
assert Emoji.unicode?("🏳️⚧️")
|
||||
assert Emoji.unicode?("🫵")
|
||||
|
||||
# Additionally, we accept regional indicators.
|
||||
assert Emoji.is_unicode_emoji?("🇵")
|
||||
assert Emoji.is_unicode_emoji?("🇴")
|
||||
assert Emoji.is_unicode_emoji?("🇬")
|
||||
assert Emoji.unicode?("🇵")
|
||||
assert Emoji.unicode?("🇴")
|
||||
assert Emoji.unicode?("🇬")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -268,17 +268,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
|
|||
end)
|
||||
end
|
||||
|
||||
test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
|
||||
assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
|
||||
|
||||
capture_log(fn ->
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} =
|
||||
start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
|
||||
|
||||
Process.sleep(30)
|
||||
end)
|
||||
end
|
||||
|
||||
test "accepts valid token on client-sent event", %{token: token} do
|
||||
assert {:ok, pid} = start_socket()
|
||||
|
||||
|
|
|
|||
22
test/pleroma/maps_test.exs
Normal file
22
test/pleroma/maps_test.exs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2024 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.MapsTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
|
||||
alias Pleroma.Maps
|
||||
|
||||
describe "filter_empty_values/1" do
|
||||
assert %{"bar" => "b", "ray" => ["foo"], "objs" => %{"a" => "b"}} ==
|
||||
Maps.filter_empty_values(%{
|
||||
"foo" => nil,
|
||||
"fooz" => "",
|
||||
"bar" => "b",
|
||||
"rei" => [],
|
||||
"ray" => ["foo"],
|
||||
"obj" => %{},
|
||||
"objs" => %{"a" => "b"}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
@ -113,7 +113,7 @@ defmodule Pleroma.SignatureTest do
|
|||
|
||||
test "it calls webfinger for 'acct:' accounts" do
|
||||
with_mock(Pleroma.Web.WebFinger,
|
||||
finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end
|
||||
finger: fn _ -> {:ok, %{"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"}
|
||||
|
|
|
|||
|
|
@ -2424,20 +2424,20 @@ defmodule Pleroma.UserTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "is_internal_user?/1" do
|
||||
describe "internal?/1" do
|
||||
test "non-internal user returns false" do
|
||||
user = insert(:user)
|
||||
refute User.is_internal_user?(user)
|
||||
refute User.internal?(user)
|
||||
end
|
||||
|
||||
test "user with no nickname returns true" do
|
||||
user = insert(:user, %{nickname: nil})
|
||||
assert User.is_internal_user?(user)
|
||||
assert User.internal?(user)
|
||||
end
|
||||
|
||||
test "user with internal-prefixed nickname returns true" do
|
||||
user = insert(:user, %{nickname: "internal.test"})
|
||||
assert User.is_internal_user?(user)
|
||||
assert User.internal?(user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
|
||||
|
||||
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
|
||||
assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
|
||||
|
||||
object = Object.normalize(post, fetch: false)
|
||||
uuid = String.split(object.data["id"], "/") |> List.last()
|
||||
|
|
@ -238,7 +238,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
|
||||
|
||||
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
|
||||
assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
|
||||
|
||||
object = Object.normalize(post, fetch: false)
|
||||
uuid = String.split(object.data["id"], "/") |> List.last()
|
||||
|
|
@ -259,7 +259,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
{:ok, post} =
|
||||
CommonAPI.post(user, %{status: "test @#{reader.nickname}", visibility: "local"})
|
||||
|
||||
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
|
||||
assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
|
||||
|
||||
object = Object.normalize(post, fetch: false)
|
||||
uuid = String.split(object.data["id"], "/") |> List.last()
|
||||
|
|
@ -436,7 +436,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
|
||||
|
||||
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
|
||||
assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
|
||||
|
||||
uuid = String.split(post.data["id"], "/") |> List.last()
|
||||
|
||||
|
|
@ -452,7 +452,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
user = insert(:user)
|
||||
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
|
||||
|
||||
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
|
||||
assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
|
||||
|
||||
uuid = String.split(post.data["id"], "/") |> List.last()
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,32 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
|
|||
assert File.exists?(fullpath)
|
||||
end
|
||||
|
||||
test "rejects invalid shortcodes", %{path: path} do
|
||||
message = %{
|
||||
"type" => "Create",
|
||||
"object" => %{
|
||||
"emoji" => [{"fired/fox", "https://example.org/emoji/firedfox"}],
|
||||
"actor" => "https://example.org/users/admin"
|
||||
}
|
||||
}
|
||||
|
||||
fullpath = Path.join(path, "fired/fox.png")
|
||||
|
||||
Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox"} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
|
||||
end)
|
||||
|
||||
clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
|
||||
|
||||
refute "firedfox" in installed()
|
||||
refute File.exists?(path)
|
||||
|
||||
assert {:ok, _message} = StealEmojiPolicy.filter(message)
|
||||
|
||||
refute "fired/fox" in installed()
|
||||
refute File.exists?(fullpath)
|
||||
end
|
||||
|
||||
test "reject regex shortcode", %{message: message} do
|
||||
refute "firedfox" in installed()
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
|
|||
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
|
||||
end
|
||||
|
||||
test "a Note from Convergence AP Bridge validates" do
|
||||
insert(:user, ap_id: "https://cc.mkdir.uk/ap/acct/hiira")
|
||||
|
||||
note =
|
||||
"test/fixtures/ccworld-ap-bridge_note.json"
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|
||||
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
|
||||
end
|
||||
|
||||
test "a note with an attachment should work", _ do
|
||||
insert(:user, %{ap_id: "https://owncast.localhost.localdomain/federation/user/streamer"})
|
||||
|
||||
|
|
|
|||
|
|
@ -52,60 +52,60 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
|
|||
}
|
||||
end
|
||||
|
||||
test "is_direct?", %{
|
||||
test "direct?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
assert Visibility.is_direct?(direct)
|
||||
refute Visibility.is_direct?(public)
|
||||
refute Visibility.is_direct?(private)
|
||||
refute Visibility.is_direct?(unlisted)
|
||||
assert Visibility.is_direct?(list)
|
||||
assert Visibility.direct?(direct)
|
||||
refute Visibility.direct?(public)
|
||||
refute Visibility.direct?(private)
|
||||
refute Visibility.direct?(unlisted)
|
||||
assert Visibility.direct?(list)
|
||||
end
|
||||
|
||||
test "is_public?", %{
|
||||
test "public?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_public?(direct)
|
||||
assert Visibility.is_public?(public)
|
||||
refute Visibility.is_public?(private)
|
||||
assert Visibility.is_public?(unlisted)
|
||||
refute Visibility.is_public?(list)
|
||||
refute Visibility.public?(direct)
|
||||
assert Visibility.public?(public)
|
||||
refute Visibility.public?(private)
|
||||
assert Visibility.public?(unlisted)
|
||||
refute Visibility.public?(list)
|
||||
end
|
||||
|
||||
test "is_private?", %{
|
||||
test "private?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_private?(direct)
|
||||
refute Visibility.is_private?(public)
|
||||
assert Visibility.is_private?(private)
|
||||
refute Visibility.is_private?(unlisted)
|
||||
refute Visibility.is_private?(list)
|
||||
refute Visibility.private?(direct)
|
||||
refute Visibility.private?(public)
|
||||
assert Visibility.private?(private)
|
||||
refute Visibility.private?(unlisted)
|
||||
refute Visibility.private?(list)
|
||||
end
|
||||
|
||||
test "is_list?", %{
|
||||
test "list?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list
|
||||
} do
|
||||
refute Visibility.is_list?(direct)
|
||||
refute Visibility.is_list?(public)
|
||||
refute Visibility.is_list?(private)
|
||||
refute Visibility.is_list?(unlisted)
|
||||
assert Visibility.is_list?(list)
|
||||
refute Visibility.list?(direct)
|
||||
refute Visibility.list?(public)
|
||||
refute Visibility.list?(private)
|
||||
refute Visibility.list?(unlisted)
|
||||
assert Visibility.list?(list)
|
||||
end
|
||||
|
||||
test "visible_for_user? Activity", %{
|
||||
|
|
@ -227,7 +227,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
|
|||
} do
|
||||
Repo.delete(user)
|
||||
Pleroma.User.invalidate_cache(user)
|
||||
refute Visibility.is_private?(direct)
|
||||
refute Visibility.private?(direct)
|
||||
end
|
||||
|
||||
test "get_visibility", %{
|
||||
|
|
|
|||
|
|
@ -873,7 +873,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
|
|||
%{
|
||||
"tuple" => [
|
||||
":_",
|
||||
"Phoenix.Endpoint.Cowboy2Handler",
|
||||
"Plug.Cowboy.Handler",
|
||||
%{"tuple" => ["Pleroma.Web.Endpoint", []]}
|
||||
]
|
||||
}
|
||||
|
|
@ -937,7 +937,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
|
|||
%{
|
||||
"tuple" => [
|
||||
":_",
|
||||
"Phoenix.Endpoint.Cowboy2Handler",
|
||||
"Plug.Cowboy.Handler",
|
||||
%{"tuple" => ["Pleroma.Web.Endpoint", []]}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
{:ok, convo_reply} =
|
||||
CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
|
||||
|
||||
assert Visibility.is_direct?(convo_reply)
|
||||
assert Visibility.direct?(convo_reply)
|
||||
|
||||
assert activity.data["context"] == convo_reply.data["context"]
|
||||
end
|
||||
|
|
@ -924,7 +924,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
||||
|
||||
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
|
||||
assert Visibility.is_public?(announce_activity)
|
||||
assert Visibility.public?(announce_activity)
|
||||
end
|
||||
|
||||
test "can't repeat a repeat" do
|
||||
|
|
@ -946,7 +946,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
{:ok, %Activity{} = announce_activity} =
|
||||
CommonAPI.repeat(activity.id, user, %{visibility: "private"})
|
||||
|
||||
assert Visibility.is_private?(announce_activity)
|
||||
assert Visibility.private?(announce_activity)
|
||||
refute Visibility.visible_for_user?(announce_activity, nil)
|
||||
end
|
||||
|
||||
|
|
@ -959,7 +959,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
|
||||
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author)
|
||||
|
||||
assert Visibility.is_private?(announce_activity)
|
||||
assert Visibility.private?(announce_activity)
|
||||
refute Visibility.visible_for_user?(announce_activity, nil)
|
||||
|
||||
assert Visibility.visible_for_user?(activity, follower)
|
||||
|
|
@ -1604,7 +1604,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1619,7 +1619,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
|
||||
CommonAPI.delete(activity_id, user)
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1635,7 +1635,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
|
||||
CommonAPI.repeat(activity_id, user)
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1653,7 +1653,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
||||
CommonAPI.unrepeat(activity_id, user)
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1668,7 +1668,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
|
||||
CommonAPI.favorite(user, activity.id)
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1683,7 +1683,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1697,7 +1697,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
|
||||
CommonAPI.react_with_emoji(activity.id, user, "👍")
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
@ -1713,7 +1713,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
||||
CommonAPI.unreact_with_emoji(activity.id, user, "👍")
|
||||
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert Visibility.local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -336,13 +336,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
path -> Pleroma.Test.StaticConfig.get(path)
|
||||
end)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{
|
||||
method: :get,
|
||||
url: "https://example.com/twitter-card"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
|
||||
|
||||
Tesla.Mock.mock_global(fn
|
||||
env ->
|
||||
apply(HttpRequestMock, :request, [env])
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
media_proxy_url: media_proxy_url
|
||||
} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 500, body: ""}
|
||||
end)
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
media_proxy_url: media_proxy_url
|
||||
} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
|
||||
end)
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: "",
|
||||
|
|
@ -242,7 +242,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
media_proxy_url: media_proxy_url
|
||||
} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
|
||||
end)
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
media_proxy_url: media_proxy_url
|
||||
} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
|
||||
end)
|
||||
|
||||
|
|
@ -280,7 +280,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
clear_config([:media_preview_proxy, :min_content_length], 100_000)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: "",
|
||||
|
|
@ -302,7 +302,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
assert_dependencies_installed()
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
|
||||
|
||||
%{method: :get, url: ^media_proxy_url} ->
|
||||
|
|
@ -324,7 +324,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
assert_dependencies_installed()
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
|
||||
|
||||
%{method: :get, url: ^media_proxy_url} ->
|
||||
|
|
@ -344,7 +344,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
|||
media_proxy_url: media_proxy_url
|
||||
} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: "HEAD", url: ^media_proxy_url} ->
|
||||
%{method: :head, url: ^media_proxy_url} ->
|
||||
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
|
||||
|
||||
%{method: :get, url: ^media_proxy_url} ->
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
|
|||
:chat_message_id_idempotency_key_cache, ^id -> {:ok, "123"}
|
||||
cache, key -> NullCache.get(cache, key)
|
||||
end)
|
||||
|> stub(:fetch, fn :rich_media_cache, _, _ -> {:ok, {:ok, %{}}} end)
|
||||
|
||||
chat_message = MessageReferenceView.render("show.json", chat_message_reference: cm_ref)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.HelpersTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
|
@ -14,7 +14,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
|
|||
import Tesla.Mock
|
||||
|
||||
setup do
|
||||
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
|
||||
ConfigMock
|
||||
|> stub(:get, fn
|
||||
|
|
@ -83,8 +83,34 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
|
|||
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
|
||||
end
|
||||
|
||||
# This does not seem to work. The urls are being fetched.
|
||||
@tag skip: true
|
||||
test "recrawls URLs on updates" do
|
||||
original_url = "https://google.com/"
|
||||
updated_url = "https://yahoo.com/"
|
||||
|
||||
Pleroma.StaticStubbedConfigMock
|
||||
|> stub(:get, fn
|
||||
[:rich_media, :enabled] -> true
|
||||
path -> Pleroma.Test.StaticConfig.get(path)
|
||||
end)
|
||||
|
||||
user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "I like this site #{original_url}"})
|
||||
|
||||
assert match?(
|
||||
%{page_url: ^original_url, rich_media: _},
|
||||
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
|
||||
)
|
||||
|
||||
{:ok, _} = CommonAPI.update(user, activity, %{status: "I like this site #{updated_url}"})
|
||||
|
||||
activity = Pleroma.Activity.get_by_id(activity.id)
|
||||
|
||||
assert match?(
|
||||
%{page_url: ^updated_url, rich_media: _},
|
||||
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
|
||||
)
|
||||
end
|
||||
|
||||
test "refuses to crawl URLs of private network from posts" do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
@ -102,10 +128,10 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
|
|||
path -> Pleroma.Test.StaticConfig.get(path)
|
||||
end)
|
||||
|
||||
assert %{} = Helpers.fetch_data_for_activity(activity)
|
||||
assert %{} = Helpers.fetch_data_for_activity(activity2)
|
||||
assert %{} = Helpers.fetch_data_for_activity(activity3)
|
||||
assert %{} = Helpers.fetch_data_for_activity(activity4)
|
||||
assert %{} = Helpers.fetch_data_for_activity(activity5)
|
||||
assert %{} == Helpers.fetch_data_for_activity(activity)
|
||||
assert %{} == Helpers.fetch_data_for_activity(activity2)
|
||||
assert %{} == Helpers.fetch_data_for_activity(activity3)
|
||||
assert %{} == Helpers.fetch_data_for_activity(activity4)
|
||||
assert %{} == Helpers.fetch_data_for_activity(activity5)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do
|
|||
expire_time =
|
||||
Timex.parse!(timestamp, "{ISO:Basic:Z}") |> Timex.to_unix() |> Kernel.+(valid_till)
|
||||
|
||||
assert {:ok, expire_time} == Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl.ttl(metadata, url)
|
||||
assert expire_time == Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl.ttl(metadata, url)
|
||||
end
|
||||
|
||||
test "s3 signed url is parsed and correct ttl is set for rich media" do
|
||||
|
|
|
|||
|
|
@ -3,95 +3,26 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.ParserTest do
|
||||
use ExUnit.Case, async: true
|
||||
use Pleroma.DataCase, async: false
|
||||
|
||||
alias Pleroma.Web.RichMedia.Parser
|
||||
|
||||
import Tesla.Mock
|
||||
|
||||
setup do
|
||||
Tesla.Mock.mock(fn
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/ogp"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/non-ogp"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/ogp-missing-title"
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/rich_media/ogp-missing-title.html")
|
||||
}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/twitter-card"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/oembed"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.html")}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "http://example.com/oembed.json"
|
||||
} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.json")}
|
||||
|
||||
%{method: :get, url: "http://example.com/empty"} ->
|
||||
%Tesla.Env{status: 200, body: "hello"}
|
||||
|
||||
%{method: :get, url: "http://example.com/malformed"} ->
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/malformed-data.html")}
|
||||
|
||||
%{method: :get, url: "http://example.com/error"} ->
|
||||
{:error, :overload}
|
||||
|
||||
%{
|
||||
method: :head,
|
||||
url: "http://example.com/huge-page"
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
|
||||
}
|
||||
|
||||
%{
|
||||
method: :head,
|
||||
url: "http://example.com/pdf-file"
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
|
||||
}
|
||||
|
||||
%{method: :head} ->
|
||||
%Tesla.Env{status: 404, body: "", headers: []}
|
||||
end)
|
||||
|
||||
:ok
|
||||
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
end
|
||||
|
||||
test "returns error when no metadata present" do
|
||||
assert {:error, _} = Parser.parse("http://example.com/empty")
|
||||
assert {:error, _} = Parser.parse("https://example.com/empty")
|
||||
end
|
||||
|
||||
test "doesn't just add a title" do
|
||||
assert {:error, {:invalid_metadata, _}} = Parser.parse("http://example.com/non-ogp")
|
||||
assert {:error, {:invalid_metadata, _}} = Parser.parse("https://example.com/non-ogp")
|
||||
end
|
||||
|
||||
test "parses ogp" do
|
||||
assert Parser.parse("http://example.com/ogp") ==
|
||||
assert Parser.parse("https://example.com/ogp") ==
|
||||
{:ok,
|
||||
%{
|
||||
"image" => "http://ia.media-imdb.com/images/rock.jpg",
|
||||
|
|
@ -99,12 +30,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
|
|||
"description" =>
|
||||
"Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
|
||||
"type" => "video.movie",
|
||||
"url" => "http://example.com/ogp"
|
||||
"url" => "https://example.com/ogp"
|
||||
}}
|
||||
end
|
||||
|
||||
test "falls back to <title> when ogp:title is missing" do
|
||||
assert Parser.parse("http://example.com/ogp-missing-title") ==
|
||||
assert Parser.parse("https://example.com/ogp-missing-title") ==
|
||||
{:ok,
|
||||
%{
|
||||
"image" => "http://ia.media-imdb.com/images/rock.jpg",
|
||||
|
|
@ -112,12 +43,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
|
|||
"description" =>
|
||||
"Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
|
||||
"type" => "video.movie",
|
||||
"url" => "http://example.com/ogp-missing-title"
|
||||
"url" => "https://example.com/ogp-missing-title"
|
||||
}}
|
||||
end
|
||||
|
||||
test "parses twitter card" do
|
||||
assert Parser.parse("http://example.com/twitter-card") ==
|
||||
assert Parser.parse("https://example.com/twitter-card") ==
|
||||
{:ok,
|
||||
%{
|
||||
"card" => "summary",
|
||||
|
|
@ -125,12 +56,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
|
|||
"image" => "https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg",
|
||||
"title" => "Small Island Developing States Photo Submission",
|
||||
"description" => "View the album on Flickr.",
|
||||
"url" => "http://example.com/twitter-card"
|
||||
"url" => "https://example.com/twitter-card"
|
||||
}}
|
||||
end
|
||||
|
||||
test "parses OEmbed and filters HTML tags" do
|
||||
assert Parser.parse("http://example.com/oembed") ==
|
||||
assert Parser.parse("https://example.com/oembed") ==
|
||||
{:ok,
|
||||
%{
|
||||
"author_name" => "\u202E\u202D\u202Cbees\u202C",
|
||||
|
|
@ -150,7 +81,7 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
|
|||
"thumbnail_width" => 150,
|
||||
"title" => "Bacon Lollys",
|
||||
"type" => "photo",
|
||||
"url" => "http://example.com/oembed",
|
||||
"url" => "https://example.com/oembed",
|
||||
"version" => "1.0",
|
||||
"web_page" => "https://www.flickr.com/photos/bees/2362225867/",
|
||||
"web_page_short_url" => "https://flic.kr/p/4AK2sc",
|
||||
|
|
@ -159,18 +90,18 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
|
|||
end
|
||||
|
||||
test "rejects invalid OGP data" do
|
||||
assert {:error, _} = Parser.parse("http://example.com/malformed")
|
||||
assert {:error, _} = Parser.parse("https://example.com/malformed")
|
||||
end
|
||||
|
||||
test "returns error if getting page was not successful" do
|
||||
assert {:error, :overload} = Parser.parse("http://example.com/error")
|
||||
assert {:error, :overload} = Parser.parse("https://example.com/error")
|
||||
end
|
||||
|
||||
test "does a HEAD request to check if the body is too large" do
|
||||
assert {:error, :body_too_large} = Parser.parse("http://example.com/huge-page")
|
||||
assert {:error, :body_too_large} = Parser.parse("https://example.com/huge-page")
|
||||
end
|
||||
|
||||
test "does a HEAD request to check if the body is html" do
|
||||
assert {:error, {:content_type, _}} = Parser.parse("http://example.com/pdf-file")
|
||||
assert {:error, {:content_type, _}} = Parser.parse("https://example.com/pdf-file")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,9 +26,15 @@ defmodule Pleroma.CachexProxy do
|
|||
@impl true
|
||||
defdelegate fetch!(cache, key, func), to: Cachex
|
||||
|
||||
@impl true
|
||||
defdelegate fetch(cache, key, func), to: Cachex
|
||||
|
||||
@impl true
|
||||
defdelegate expire_at(cache, str, num), to: Cachex
|
||||
|
||||
@impl true
|
||||
defdelegate expire(cache, str, num), to: Cachex
|
||||
|
||||
@impl true
|
||||
defdelegate exists?(cache, key), to: Cachex
|
||||
|
||||
|
|
|
|||
|
|
@ -1059,7 +1059,7 @@ defmodule HttpRequestMock do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("http://example.com/malformed", _, _, _) do
|
||||
def get("https://example.com/malformed", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/malformed-data.html")}}
|
||||
end
|
||||
|
|
@ -1464,6 +1464,45 @@ defmodule HttpRequestMock do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("https://google.com/", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/google.html")}}
|
||||
end
|
||||
|
||||
def get("https://yahoo.com/", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/yahoo.html")}}
|
||||
end
|
||||
|
||||
def get("https://example.com/error", _, _, _), do: {:error, :overload}
|
||||
|
||||
def get("https://example.com/ogp-missing-title", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/rich_media/ogp-missing-title.html")
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://example.com/oembed", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.html")}}
|
||||
end
|
||||
|
||||
def get("https://example.com/oembed.json", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.json")}}
|
||||
end
|
||||
|
||||
def get("https://example.com/twitter-card", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}}
|
||||
end
|
||||
|
||||
def get("https://example.com/non-ogp", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")}}
|
||||
end
|
||||
|
||||
def get("https://example.com/empty", _, _, _) do
|
||||
{:ok, %Tesla.Env{status: 200, body: "hello"}}
|
||||
end
|
||||
|
||||
def get("https://friends.grishka.me/posts/54642", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
|
|
@ -1555,14 +1594,41 @@ defmodule HttpRequestMock do
|
|||
|
||||
# Most of the rich media mocks are missing HEAD requests, so we just return 404.
|
||||
@rich_media_mocks [
|
||||
"https://example.com/empty",
|
||||
"https://example.com/error",
|
||||
"https://example.com/malformed",
|
||||
"https://example.com/non-ogp",
|
||||
"https://example.com/oembed",
|
||||
"https://example.com/oembed.json",
|
||||
"https://example.com/ogp",
|
||||
"https://example.com/ogp-missing-data",
|
||||
"https://example.com/twitter-card"
|
||||
"https://example.com/ogp-missing-title",
|
||||
"https://example.com/twitter-card",
|
||||
"https://google.com/",
|
||||
"https://pleroma.local/notice/9kCP7V",
|
||||
"https://yahoo.com/"
|
||||
]
|
||||
|
||||
def head(url, _query, _body, _headers) when url in @rich_media_mocks do
|
||||
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||
end
|
||||
|
||||
def head("https://example.com/pdf-file", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def head("https://example.com/huge-page", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
|
||||
}}
|
||||
end
|
||||
|
||||
def head(url, query, body, headers) do
|
||||
{:error,
|
||||
"Mock response not implemented for HEAD #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ defmodule Pleroma.NullCache do
|
|||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def fetch(_, key, func), do: func.(key)
|
||||
|
||||
@impl true
|
||||
def get_and_update(_, _, func) do
|
||||
func.(nil)
|
||||
|
|
@ -36,6 +39,9 @@ defmodule Pleroma.NullCache do
|
|||
@impl true
|
||||
def expire_at(_, _, _), do: {:ok, true}
|
||||
|
||||
@impl true
|
||||
def expire(_, _, _), do: {:ok, true}
|
||||
|
||||
@impl true
|
||||
def exists?(_, _), do: {:ok, false}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue