Fix Pleroma.HTML.extract_first_external_url/2
[akkoma] / test / object_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.ObjectTest do
6 use Pleroma.DataCase
7 import ExUnit.CaptureLog
8 import Pleroma.Factory
9 import Tesla.Mock
10 alias Pleroma.Activity
11 alias Pleroma.Object
12 alias Pleroma.Repo
13 alias Pleroma.Web.CommonAPI
14
15 setup do
16 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
17 :ok
18 end
19
20 test "returns an object by it's AP id" do
21 object = insert(:note)
22 found_object = Object.get_by_ap_id(object.data["id"])
23
24 assert object == found_object
25 end
26
27 describe "generic changeset" do
28 test "it ensures uniqueness of the id" do
29 object = insert(:note)
30 cs = Object.change(%Object{}, %{data: %{id: object.data["id"]}})
31 assert cs.valid?
32
33 {:error, _result} = Repo.insert(cs)
34 end
35 end
36
37 describe "deletion function" do
38 test "deletes an object" do
39 object = insert(:note)
40 found_object = Object.get_by_ap_id(object.data["id"])
41
42 assert object == found_object
43
44 Object.delete(found_object)
45
46 found_object = Object.get_by_ap_id(object.data["id"])
47
48 refute object == found_object
49
50 assert found_object.data["type"] == "Tombstone"
51 end
52
53 test "ensures cache is cleared for the object" do
54 object = insert(:note)
55 cached_object = Object.get_cached_by_ap_id(object.data["id"])
56
57 assert object == cached_object
58
59 Cachex.put(:web_resp_cache, URI.parse(object.data["id"]).path, "cofe")
60
61 Object.delete(cached_object)
62
63 {:ok, nil} = Cachex.get(:object_cache, "object:#{object.data["id"]}")
64 {:ok, nil} = Cachex.get(:web_resp_cache, URI.parse(object.data["id"]).path)
65
66 cached_object = Object.get_cached_by_ap_id(object.data["id"])
67
68 refute object == cached_object
69
70 assert cached_object.data["type"] == "Tombstone"
71 end
72 end
73
74 describe "normalizer" do
75 test "fetches unknown objects by default" do
76 %Object{} =
77 object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367")
78
79 assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367"
80 end
81
82 test "fetches unknown objects when fetch_remote is explicitly true" do
83 %Object{} =
84 object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367", true)
85
86 assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367"
87 end
88
89 test "does not fetch unknown objects when fetch_remote is false" do
90 assert is_nil(
91 Object.normalize("http://mastodon.example.org/@admin/99541947525187367", false)
92 )
93 end
94 end
95
96 describe "get_by_id_and_maybe_refetch" do
97 setup do
98 mock(fn
99 %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
100 %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")}
101
102 env ->
103 apply(HttpRequestMock, :request, [env])
104 end)
105
106 mock_modified = fn resp ->
107 mock(fn
108 %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
109 resp
110
111 env ->
112 apply(HttpRequestMock, :request, [env])
113 end)
114 end
115
116 on_exit(fn -> mock(fn env -> apply(HttpRequestMock, :request, [env]) end) end)
117
118 [mock_modified: mock_modified]
119 end
120
121 test "refetches if the time since the last refetch is greater than the interval", %{
122 mock_modified: mock_modified
123 } do
124 %Object{} =
125 object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
126
127 Object.set_cache(object)
128
129 assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
130 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
131
132 mock_modified.(%Tesla.Env{
133 status: 200,
134 body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
135 })
136
137 updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
138 object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
139 assert updated_object == object_in_cache
140 assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
141 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
142 end
143
144 test "returns the old object if refetch fails", %{mock_modified: mock_modified} do
145 %Object{} =
146 object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
147
148 Object.set_cache(object)
149
150 assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
151 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
152
153 assert capture_log(fn ->
154 mock_modified.(%Tesla.Env{status: 404, body: ""})
155
156 updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
157 object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
158 assert updated_object == object_in_cache
159 assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
160 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
161 end) =~
162 "[error] Couldn't refresh https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"
163 end
164
165 test "does not refetch if the time since the last refetch is greater than the interval", %{
166 mock_modified: mock_modified
167 } do
168 %Object{} =
169 object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
170
171 Object.set_cache(object)
172
173 assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
174 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
175
176 mock_modified.(%Tesla.Env{
177 status: 200,
178 body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
179 })
180
181 updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100)
182 object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
183 assert updated_object == object_in_cache
184 assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
185 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
186 end
187
188 test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
189 %Object{} =
190 object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
191
192 Object.set_cache(object)
193
194 assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
195 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
196
197 user = insert(:user)
198 activity = Activity.get_create_by_object_ap_id(object.data["id"])
199 {:ok, _activity, object} = CommonAPI.favorite(activity.id, user)
200
201 assert object.data["like_count"] == 1
202
203 mock_modified.(%Tesla.Env{
204 status: 200,
205 body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
206 })
207
208 updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
209 object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
210 assert updated_object == object_in_cache
211 assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
212 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
213
214 assert updated_object.data["like_count"] == 1
215 end
216 end
217 end