Mogrify/Mogrifun: Asyncify

This commit is contained in:
Lain Soykaf 2025-02-25 17:08:21 +04:00
parent ee291f08e8
commit c31fabdebd
9 changed files with 90 additions and 40 deletions

View file

@ -162,6 +162,9 @@ config :pleroma, Pleroma.Web.Plugs.HTTPSignaturePlug, config_impl: Pleroma.Stati
config :pleroma, Pleroma.Upload.Filter.AnonymizeFilename, config :pleroma, Pleroma.Upload.Filter.AnonymizeFilename,
config_impl: Pleroma.StaticStubbedConfigMock config_impl: Pleroma.StaticStubbedConfigMock
config :pleroma, Pleroma.Upload.Filter.Mogrify, config_impl: Pleroma.StaticStubbedConfigMock
config :pleroma, Pleroma.Upload.Filter.Mogrify, mogrify_impl: Pleroma.MogrifyMock
config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock config :pleroma, Pleroma.Signature, http_signatures_impl: Pleroma.StubbedHTTPSignaturesMock
peer_module = peer_module =

View file

@ -27,6 +27,7 @@ defmodule Pleroma.Config do
Application.get_env(:pleroma, key, default) Application.get_env(:pleroma, key, default)
end end
@impl true
def get!(key) do def get!(key) do
value = get(key, nil) value = get(key, nil)

View file

@ -5,10 +5,13 @@
defmodule Pleroma.Config.Getting do defmodule Pleroma.Config.Getting do
@callback get(any()) :: any() @callback get(any()) :: any()
@callback get(any(), any()) :: any() @callback get(any(), any()) :: any()
@callback get!(any()) :: any()
def get(key), do: get(key, nil) def get(key), do: get(key, nil)
def get(key, default), do: impl().get(key, default) def get(key, default), do: impl().get(key, default)
def get!(key), do: impl().get!(key)
def impl do def impl do
Application.get_env(:pleroma, :config_impl, Pleroma.Config) Application.get_env(:pleroma, :config_impl, Pleroma.Config)
end end

42
lib/pleroma/mogrify.ex Normal file
View file

@ -0,0 +1,42 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MogrifyBehaviour do
@moduledoc """
Behaviour for Mogrify operations.
This module defines the interface for Mogrify operations that can be mocked in tests.
"""
@callback open(binary()) :: map()
@callback custom(map(), binary()) :: map()
@callback custom(map(), binary(), binary()) :: map()
@callback save(map(), keyword()) :: map()
end
defmodule Pleroma.MogrifyWrapper do
@moduledoc """
Default implementation of MogrifyBehaviour that delegates to Mogrify.
"""
@behaviour Pleroma.MogrifyBehaviour
@impl true
def open(file) do
Mogrify.open(file)
end
@impl true
def custom(image, action) do
Mogrify.custom(image, action)
end
@impl true
def custom(image, action, options) do
Mogrify.custom(image, action, options)
end
@impl true
def save(image, opts) do
Mogrify.save(image, opts)
end
end

View file

@ -8,9 +8,16 @@ defmodule Pleroma.Upload.Filter.Mogrify do
@type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()} @type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()}
@type conversions :: conversion() | [conversion()] @type conversions :: conversion() | [conversion()]
@config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
@mogrify_impl Application.compile_env(
:pleroma,
[__MODULE__, :mogrify_impl],
Pleroma.MogrifyWrapper
)
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do try do
do_filter(file, Pleroma.Config.get!([__MODULE__, :args])) do_filter(file, @config_impl.get!([__MODULE__, :args]))
{:ok, :filtered} {:ok, :filtered}
rescue rescue
e in ErlangError -> e in ErlangError ->
@ -22,9 +29,9 @@ defmodule Pleroma.Upload.Filter.Mogrify do
def do_filter(file, filters) do def do_filter(file, filters) do
file file
|> Mogrify.open() |> @mogrify_impl.open()
|> mogrify_filter(filters) |> mogrify_filter(filters)
|> Mogrify.save(in_place: true) |> @mogrify_impl.save(in_place: true)
end end
defp mogrify_filter(mogrify, nil), do: mogrify defp mogrify_filter(mogrify, nil), do: mogrify
@ -38,10 +45,10 @@ defmodule Pleroma.Upload.Filter.Mogrify do
defp mogrify_filter(mogrify, []), do: mogrify defp mogrify_filter(mogrify, []), do: mogrify
defp mogrify_filter(mogrify, {action, options}) do defp mogrify_filter(mogrify, {action, options}) do
Mogrify.custom(mogrify, action, options) @mogrify_impl.custom(mogrify, action, options)
end end
defp mogrify_filter(mogrify, action) when is_binary(action) do defp mogrify_filter(mogrify, action) when is_binary(action) do
Mogrify.custom(mogrify, action) @mogrify_impl.custom(mogrify, action)
end end
end end

View file

@ -3,11 +3,12 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifunTest do defmodule Pleroma.Upload.Filter.MogrifunTest do
use Pleroma.DataCase use Pleroma.DataCase, async: true
import Mock import Mox
alias Pleroma.Upload alias Pleroma.Upload
alias Pleroma.Upload.Filter alias Pleroma.Upload.Filter
alias Pleroma.MogrifyMock
test "apply mogrify filter" do test "apply mogrify filter" do
File.cp!( File.cp!(
@ -22,23 +23,12 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }
task = MogrifyMock
Task.async(fn -> |> stub(:open, fn _file -> %{} end)
assert_receive {:apply_filter, {}}, 4_000 |> stub(:custom, fn _image, _action -> %{} end)
end) |> stub(:custom, fn _image, _action, _options -> %{} end)
|> stub(:save, fn _image, [in_place: true] -> :ok end)
with_mocks([ assert Filter.Mogrifun.filter(upload) == {:ok, :filtered}
{Mogrify, [],
[
open: fn _f -> %Mogrify.Image{} end,
custom: fn _m, _a -> send(task.pid, {:apply_filter, {}}) end,
custom: fn _m, _a, _o -> send(task.pid, {:apply_filter, {}}) end,
save: fn _f, _o -> :ok end
]}
]) do
assert Filter.Mogrifun.filter(upload) == {:ok, :filtered}
end
Task.await(task)
end end
end end

View file

@ -3,13 +3,18 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifyTest do defmodule Pleroma.Upload.Filter.MogrifyTest do
use Pleroma.DataCase use Pleroma.DataCase, async: true
import Mock import Mox
alias Pleroma.Upload.Filter alias Pleroma.Upload.Filter
alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.MogrifyMock
setup :verify_on_exit!
test "apply mogrify filter" do test "apply mogrify filter" do
clear_config(Filter.Mogrify, args: [{"tint", "40"}]) ConfigMock
|> stub(:get!, fn [Filter.Mogrify, :args] -> [{"tint", "40"}] end)
File.cp!( File.cp!(
"test/fixtures/image.jpg", "test/fixtures/image.jpg",
@ -23,19 +28,11 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }
task = MogrifyMock
Task.async(fn -> |> expect(:open, fn _file -> %{} end)
assert_receive {:apply_filter, {_, "tint", "40"}}, 4_000 |> expect(:custom, fn _image, "tint", "40" -> %{} end)
end) |> expect(:save, fn _image, [in_place: true] -> :ok end)
with_mock Mogrify, assert Filter.Mogrify.filter(upload) == {:ok, :filtered}
open: fn _f -> %Mogrify.Image{} end,
custom: fn _m, _a -> :ok end,
custom: fn m, a, o -> send(task.pid, {:apply_filter, {m, a, o}}) end,
save: fn _f, _o -> :ok end do
assert Filter.Mogrify.filter(upload) == {:ok, :filtered}
end
Task.await(task)
end end
end end

View file

@ -35,3 +35,4 @@ Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging)
Mox.defmock(Pleroma.Uploaders.S3.ExAwsMock, for: Pleroma.Uploaders.S3.ExAwsAPI) Mox.defmock(Pleroma.Uploaders.S3.ExAwsMock, for: Pleroma.Uploaders.S3.ExAwsAPI)
Mox.defmock(Pleroma.DateTimeMock, for: Pleroma.DateTime) Mox.defmock(Pleroma.DateTimeMock, for: Pleroma.DateTime)
Mox.defmock(Pleroma.MogrifyMock, for: Pleroma.MogrifyBehaviour)

View file

@ -34,7 +34,13 @@ defmodule Pleroma.Test.StaticConfig do
@behaviour Pleroma.Config.Getting @behaviour Pleroma.Config.Getting
@config Application.get_all_env(:pleroma) @config Application.get_all_env(:pleroma)
@impl true
def get(path, default \\ nil) do def get(path, default \\ nil) do
get_in(@config, path) || default get_in(@config, path) || default
end end
@impl true
def get!(path) do
get_in(@config, path)
end
end end