total rebase
[anni] / test / pleroma / web / plugs / cache_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.Plugs.CacheTest do
6   # Relies on Cachex, has to stay synchronous
7   use Pleroma.DataCase
8   use Plug.Test
9
10   alias Pleroma.Web.Plugs.Cache
11
12   @miss_resp {200,
13               [
14                 {"cache-control", "max-age=0, private, must-revalidate"},
15                 {"content-type", "cofe/hot; charset=utf-8"},
16                 {"x-cache", "MISS from Pleroma"}
17               ], "cofe"}
18
19   @hit_resp {200,
20              [
21                {"cache-control", "max-age=0, private, must-revalidate"},
22                {"content-type", "cofe/hot; charset=utf-8"},
23                {"x-cache", "HIT from Pleroma"}
24              ], "cofe"}
25
26   @ttl 5
27
28   test "caches a response" do
29     assert @miss_resp ==
30              conn(:get, "/")
31              |> Cache.call(%{query_params: false, ttl: nil})
32              |> put_resp_content_type("cofe/hot")
33              |> send_resp(:ok, "cofe")
34              |> sent_resp()
35
36     assert_raise(Plug.Conn.AlreadySentError, fn ->
37       conn(:get, "/")
38       |> Cache.call(%{query_params: false, ttl: nil})
39       |> put_resp_content_type("cofe/hot")
40       |> send_resp(:ok, "cofe")
41       |> sent_resp()
42     end)
43
44     assert @hit_resp ==
45              conn(:get, "/")
46              |> Cache.call(%{query_params: false, ttl: nil})
47              |> sent_resp()
48   end
49
50   test "ttl is set" do
51     assert @miss_resp ==
52              conn(:get, "/")
53              |> Cache.call(%{query_params: false, ttl: @ttl})
54              |> put_resp_content_type("cofe/hot")
55              |> send_resp(:ok, "cofe")
56              |> sent_resp()
57
58     assert @hit_resp ==
59              conn(:get, "/")
60              |> Cache.call(%{query_params: false, ttl: @ttl})
61              |> sent_resp()
62
63     :timer.sleep(@ttl + 1)
64
65     assert @miss_resp ==
66              conn(:get, "/")
67              |> Cache.call(%{query_params: false, ttl: @ttl})
68              |> put_resp_content_type("cofe/hot")
69              |> send_resp(:ok, "cofe")
70              |> sent_resp()
71   end
72
73   test "set ttl via conn.assigns" do
74     assert @miss_resp ==
75              conn(:get, "/")
76              |> Cache.call(%{query_params: false, ttl: nil})
77              |> put_resp_content_type("cofe/hot")
78              |> assign(:cache_ttl, @ttl)
79              |> send_resp(:ok, "cofe")
80              |> sent_resp()
81
82     assert @hit_resp ==
83              conn(:get, "/")
84              |> Cache.call(%{query_params: false, ttl: nil})
85              |> sent_resp()
86
87     :timer.sleep(@ttl + 1)
88
89     assert @miss_resp ==
90              conn(:get, "/")
91              |> Cache.call(%{query_params: false, ttl: nil})
92              |> put_resp_content_type("cofe/hot")
93              |> send_resp(:ok, "cofe")
94              |> sent_resp()
95   end
96
97   test "ignore query string when `query_params` is false" do
98     assert @miss_resp ==
99              conn(:get, "/?cofe")
100              |> Cache.call(%{query_params: false, ttl: nil})
101              |> put_resp_content_type("cofe/hot")
102              |> send_resp(:ok, "cofe")
103              |> sent_resp()
104
105     assert @hit_resp ==
106              conn(:get, "/?cofefe")
107              |> Cache.call(%{query_params: false, ttl: nil})
108              |> sent_resp()
109   end
110
111   test "take query string into account when `query_params` is true" do
112     assert @miss_resp ==
113              conn(:get, "/?cofe")
114              |> Cache.call(%{query_params: true, ttl: nil})
115              |> put_resp_content_type("cofe/hot")
116              |> send_resp(:ok, "cofe")
117              |> sent_resp()
118
119     assert @miss_resp ==
120              conn(:get, "/?cofefe")
121              |> Cache.call(%{query_params: true, ttl: nil})
122              |> put_resp_content_type("cofe/hot")
123              |> send_resp(:ok, "cofe")
124              |> sent_resp()
125   end
126
127   test "take specific query params into account when `query_params` is list" do
128     assert @miss_resp ==
129              conn(:get, "/?a=1&b=2&c=3&foo=bar")
130              |> fetch_query_params()
131              |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil})
132              |> put_resp_content_type("cofe/hot")
133              |> send_resp(:ok, "cofe")
134              |> sent_resp()
135
136     assert @hit_resp ==
137              conn(:get, "/?bar=foo&c=3&b=2&a=1")
138              |> fetch_query_params()
139              |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil})
140              |> sent_resp()
141
142     assert @miss_resp ==
143              conn(:get, "/?bar=foo&c=3&b=2&a=2")
144              |> fetch_query_params()
145              |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil})
146              |> put_resp_content_type("cofe/hot")
147              |> send_resp(:ok, "cofe")
148              |> sent_resp()
149   end
150
151   test "ignore not GET requests" do
152     expected =
153       {200,
154        [
155          {"cache-control", "max-age=0, private, must-revalidate"},
156          {"content-type", "cofe/hot; charset=utf-8"}
157        ], "cofe"}
158
159     assert expected ==
160              conn(:post, "/")
161              |> Cache.call(%{query_params: true, ttl: nil})
162              |> put_resp_content_type("cofe/hot")
163              |> send_resp(:ok, "cofe")
164              |> sent_resp()
165   end
166
167   test "ignore non-successful responses" do
168     expected =
169       {418,
170        [
171          {"cache-control", "max-age=0, private, must-revalidate"},
172          {"content-type", "tea/iced; charset=utf-8"}
173        ], "🥤"}
174
175     assert expected ==
176              conn(:get, "/cofe")
177              |> Cache.call(%{query_params: true, ttl: nil})
178              |> put_resp_content_type("tea/iced")
179              |> send_resp(:im_a_teapot, "🥤")
180              |> sent_resp()
181   end
182
183   test "ignores if skip_cache is assigned" do
184     assert @miss_resp ==
185              conn(:get, "/")
186              |> assign(:skip_cache, true)
187              |> Cache.call(%{query_params: false, ttl: nil})
188              |> put_resp_content_type("cofe/hot")
189              |> send_resp(:ok, "cofe")
190              |> sent_resp()
191
192     assert @miss_resp ==
193              conn(:get, "/")
194              |> assign(:skip_cache, true)
195              |> Cache.call(%{query_params: false, ttl: nil})
196              |> put_resp_content_type("cofe/hot")
197              |> send_resp(:ok, "cofe")
198              |> sent_resp()
199   end
200 end