From 90a47ca050c5839e8b4dc3bac315dc436d49152d Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Mon, 11 Dec 2023 09:25:05 +0400 Subject: [PATCH] S3 Test: Remove global state dependencies --- config/test.exs | 3 + lib/pleroma/upload.ex | 15 ++--- lib/pleroma/uploaders/s3.ex | 15 +++-- test/pleroma/uploaders/s3_test.exs | 89 +++++++++++++++++++----------- test/support/mocks.ex | 2 + 5 files changed, 81 insertions(+), 43 deletions(-) diff --git a/config/test.exs b/config/test.exs index 071e985dd..5dd6a2f5d 100644 --- a/config/test.exs +++ b/config/test.exs @@ -147,6 +147,9 @@ # Mox definitions. Only read during compile time. config :pleroma, Pleroma.User.Backup, config_impl: Pleroma.UnstubbedConfigMock +config :pleroma, Pleroma.Uploaders.S3, ex_aws_impl: Pleroma.Uploaders.S3.ExAwsMock +config :pleroma, Pleroma.Uploaders.S3, config_impl: Pleroma.UnstubbedConfigMock +config :pleroma, Pleroma.Upload, config_impl: Pleroma.UnstubbedConfigMock if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 4aee9326f..bedd7889a 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -34,7 +34,6 @@ defmodule Pleroma.Upload do """ alias Ecto.UUID - alias Pleroma.Config alias Pleroma.Maps alias Pleroma.Web.ActivityPub.Utils require Logger @@ -76,6 +75,8 @@ defmodule Pleroma.Upload do :path ] + @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config) + defp get_description(upload) do case {upload.description, Pleroma.Config.get([Pleroma.Upload, :default_description])} do {description, _} when is_binary(description) -> description @@ -244,18 +245,18 @@ defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do defp url_from_spec(_upload, _base_url, {:url, url}), do: url def base_url do - uploader = Config.get([Pleroma.Upload, :uploader]) - upload_base_url = Config.get([Pleroma.Upload, :base_url]) - public_endpoint = Config.get([uploader, :public_endpoint]) + uploader = @config_impl.get([Pleroma.Upload, :uploader]) + upload_base_url = @config_impl.get([Pleroma.Upload, :base_url]) + public_endpoint = @config_impl.get([uploader, :public_endpoint]) case uploader do Pleroma.Uploaders.Local -> upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/" Pleroma.Uploaders.S3 -> - bucket = Config.get([Pleroma.Uploaders.S3, :bucket]) - truncated_namespace = Config.get([Pleroma.Uploaders.S3, :truncated_namespace]) - namespace = Config.get([Pleroma.Uploaders.S3, :bucket_namespace]) + bucket = @config_impl.get([Pleroma.Uploaders.S3, :bucket]) + truncated_namespace = @config_impl.get([Pleroma.Uploaders.S3, :truncated_namespace]) + namespace = @config_impl.get([Pleroma.Uploaders.S3, :bucket_namespace]) bucket_with_namespace = cond do diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex index 19287c532..7b32bd8a5 100644 --- a/lib/pleroma/uploaders/s3.ex +++ b/lib/pleroma/uploaders/s3.ex @@ -6,7 +6,8 @@ defmodule Pleroma.Uploaders.S3 do @behaviour Pleroma.Uploaders.Uploader require Logger - alias Pleroma.Config + @ex_aws_impl Application.compile_env(:pleroma, [__MODULE__, :ex_aws_impl], ExAws) + @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config) # The file name is re-encoded with S3's constraints here to comply with previous # links with less strict filenames @@ -22,7 +23,7 @@ def get_file(file) do @impl true def put_file(%Pleroma.Upload{} = upload) do - config = Config.get([__MODULE__]) + config = @config_impl.get([__MODULE__]) bucket = Keyword.get(config, :bucket) streaming = Keyword.get(config, :streaming_enabled) @@ -56,7 +57,7 @@ def put_file(%Pleroma.Upload{} = upload) do ]) end - case ExAws.request(op) do + case @ex_aws_impl.request(op) do {:ok, _} -> {:ok, {:file, s3_name}} @@ -69,9 +70,9 @@ def put_file(%Pleroma.Upload{} = upload) do @impl true def delete_file(file) do [__MODULE__, :bucket] - |> Config.get() + |> @config_impl.get() |> ExAws.S3.delete_object(file) - |> ExAws.request() + |> @ex_aws_impl.request() |> case do {:ok, %{status_code: 204}} -> :ok error -> {:error, inspect(error)} @@ -83,3 +84,7 @@ def strict_encode(name) do String.replace(name, @regex, "-") end end + +defmodule Pleroma.Uploaders.S3.ExAwsAPI do + @callback request(op :: ExAws.Operation.t()) :: {:ok, ExAws.Operation.t()} | {:error, term()} +end diff --git a/test/pleroma/uploaders/s3_test.exs b/test/pleroma/uploaders/s3_test.exs index d870449b1..484f8b944 100644 --- a/test/pleroma/uploaders/s3_test.exs +++ b/test/pleroma/uploaders/s3_test.exs @@ -3,22 +3,27 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Uploaders.S3Test do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Uploaders.S3 + alias Pleroma.Uploaders.S3.ExAwsMock + alias Pleroma.UnstubbedConfigMock, as: ConfigMock - import Mock + import Mox import ExUnit.CaptureLog - setup do - clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3) - clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com") - clear_config([Pleroma.Uploaders.S3]) - clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket") - end - describe "get_file/1" do - test "it returns path to local folder for files" do + test "it returns url for files" do + ConfigMock + |> expect(:get, 6, fn key -> + [ + {Pleroma.Upload, + [uploader: Pleroma.Uploaders.S3, base_url: "https://s3.amazonaws.com"]}, + {Pleroma.Uploaders.S3, [bucket: "test_bucket"]} + ] + |> get_in(key) + end) + assert S3.get_file("test_image.jpg") == { :ok, {:url, "https://s3.amazonaws.com/test_bucket/test_image.jpg"} @@ -26,13 +31,16 @@ test "it returns path to local folder for files" do end test "it returns path without bucket when truncated_namespace set to ''" do - clear_config([Pleroma.Uploaders.S3], - bucket: "test_bucket", - bucket_namespace: "myaccount", - truncated_namespace: "" - ) - - clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com") + ConfigMock + |> expect(:get, 6, fn key -> + [ + {Pleroma.Upload, + [uploader: Pleroma.Uploaders.S3, base_url: "https://s3.amazonaws.com"]}, + {Pleroma.Uploaders.S3, + [bucket: "test_bucket", truncated_namespace: "", bucket_namespace: "myaccount"]} + ] + |> get_in(key) + end) assert S3.get_file("test_image.jpg") == { :ok, @@ -41,10 +49,15 @@ test "it returns path without bucket when truncated_namespace set to ''" do end test "it returns path with bucket namespace when namespace is set" do - clear_config([Pleroma.Uploaders.S3], - bucket: "test_bucket", - bucket_namespace: "family" - ) + ConfigMock + |> expect(:get, 6, fn key -> + [ + {Pleroma.Upload, + [uploader: Pleroma.Uploaders.S3, base_url: "https://s3.amazonaws.com"]}, + {Pleroma.Uploaders.S3, [bucket: "test_bucket", bucket_namespace: "family"]} + ] + |> get_in(key) + end) assert S3.get_file("test_image.jpg") == { :ok, @@ -62,28 +75,42 @@ test "it returns path with bucket namespace when namespace is set" do tempfile: Path.absname("test/instance_static/add/shortcode.png") } + ConfigMock + |> expect(:get, fn [Pleroma.Uploaders.S3] -> + [ + bucket: "test_bucket" + ] + end) + [file_upload: file_upload] end test "save file", %{file_upload: file_upload} do - with_mock ExAws, request: fn _ -> {:ok, :ok} end do - assert S3.put_file(file_upload) == {:ok, {:file, "test_folder/image-tet.jpg"}} - end + ExAwsMock + |> expect(:request, fn _req -> {:ok, %{status_code: 200}} end) + + assert S3.put_file(file_upload) == {:ok, {:file, "test_folder/image-tet.jpg"}} end test "returns error", %{file_upload: file_upload} do - with_mock ExAws, request: fn _ -> {:error, "S3 Upload failed"} end do - assert capture_log(fn -> - assert S3.put_file(file_upload) == {:error, "S3 Upload failed"} - end) =~ "Elixir.Pleroma.Uploaders.S3: {:error, \"S3 Upload failed\"}" - end + ExAwsMock + |> expect(:request, fn _req -> {:error, "S3 Upload failed"} end) + + assert capture_log(fn -> + assert S3.put_file(file_upload) == {:error, "S3 Upload failed"} + end) =~ "Elixir.Pleroma.Uploaders.S3: {:error, \"S3 Upload failed\"}" end end describe "delete_file/1" do - test_with_mock "deletes file", ExAws, request: fn _req -> {:ok, %{status_code: 204}} end do + test "deletes file" do + ExAwsMock + |> expect(:request, fn _req -> {:ok, %{status_code: 204}} end) + + ConfigMock + |> expect(:get, fn [Pleroma.Uploaders.S3, :bucket] -> "test_bucket" end) + assert :ok = S3.delete_file("image.jpg") - assert_called(ExAws.request(:_)) end end end diff --git a/test/support/mocks.ex b/test/support/mocks.ex index b941f5bb3..22388c0c8 100644 --- a/test/support/mocks.ex +++ b/test/support/mocks.ex @@ -31,3 +31,5 @@ Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging) Mox.defmock(Pleroma.User.Backup.ProcessorMock, for: Pleroma.User.Backup.ProcessorAPI) + +Mox.defmock(Pleroma.Uploaders.S3.ExAwsMock, for: Pleroma.Uploaders.S3.ExAwsAPI)