# Pleroma: A lightweight social networking server # Copyright © 2017-2023 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.CacheTest do # Relies on Cachex, has to stay synchronous use Pleroma.DataCase use Plug.Test alias Pleroma.Web.Plugs.Cache @miss_resp {200, [ {"cache-control", "max-age=0, private, must-revalidate"}, {"content-type", "cofe/hot; charset=utf-8"}, {"x-cache", "MISS from Pleroma"} ], "cofe"} @hit_resp {200, [ {"cache-control", "max-age=0, private, must-revalidate"}, {"content-type", "cofe/hot; charset=utf-8"}, {"x-cache", "HIT from Pleroma"} ], "cofe"} @ttl 5 test "caches a response" do assert @miss_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert_raise(Plug.Conn.AlreadySentError, fn -> conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end) assert @hit_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> sent_resp() end test "ttl is set" do assert @miss_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: @ttl}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert @hit_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: @ttl}) |> sent_resp() :timer.sleep(@ttl + 1) assert @miss_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: @ttl}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end test "set ttl via conn.assigns" do assert @miss_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> assign(:cache_ttl, @ttl) |> send_resp(:ok, "cofe") |> sent_resp() assert @hit_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> sent_resp() :timer.sleep(@ttl + 1) assert @miss_resp == conn(:get, "/") |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end test "ignore query string when `query_params` is false" do assert @miss_resp == conn(:get, "/?cofe") |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert @hit_resp == conn(:get, "/?cofefe") |> Cache.call(%{query_params: false, ttl: nil}) |> sent_resp() end test "take query string into account when `query_params` is true" do assert @miss_resp == conn(:get, "/?cofe") |> Cache.call(%{query_params: true, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert @miss_resp == conn(:get, "/?cofefe") |> Cache.call(%{query_params: true, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end test "take specific query params into account when `query_params` is list" do assert @miss_resp == conn(:get, "/?a=1&b=2&c=3&foo=bar") |> fetch_query_params() |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert @hit_resp == conn(:get, "/?bar=foo&c=3&b=2&a=1") |> fetch_query_params() |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil}) |> sent_resp() assert @miss_resp == conn(:get, "/?bar=foo&c=3&b=2&a=2") |> fetch_query_params() |> Cache.call(%{query_params: ["a", "b", "c"], ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end test "ignore not GET requests" do expected = {200, [ {"cache-control", "max-age=0, private, must-revalidate"}, {"content-type", "cofe/hot; charset=utf-8"} ], "cofe"} assert expected == conn(:post, "/") |> Cache.call(%{query_params: true, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end test "ignore non-successful responses" do expected = {418, [ {"cache-control", "max-age=0, private, must-revalidate"}, {"content-type", "tea/iced; charset=utf-8"} ], "🥤"} assert expected == conn(:get, "/cofe") |> Cache.call(%{query_params: true, ttl: nil}) |> put_resp_content_type("tea/iced") |> send_resp(:im_a_teapot, "🥤") |> sent_resp() end test "ignores if skip_cache is assigned" do assert @miss_resp == conn(:get, "/") |> assign(:skip_cache, true) |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() assert @miss_resp == conn(:get, "/") |> assign(:skip_cache, true) |> Cache.call(%{query_params: false, ttl: nil}) |> put_resp_content_type("cofe/hot") |> send_resp(:ok, "cofe") |> sent_resp() end end