defmodule OhMyExOhIrcd.ImagesTest do
use OhMyExOhIrcd.DataCase, async: false
import OhMyExOhIrcd.AccountsFixtures
alias OhMyExOhIrcd.Channels
alias OhMyExOhIrcd.Images
alias OhMyExOhIrcd.Images.Image
# 1x1 transparent PNG.
@png Base.decode64!(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M8AAAMBAQDJ/pLvAAAAAElFTkSuQmCC"
)
setup do
# Isolate uploads to a temp dir and restore app env afterwards.
tmp = Path.join(System.tmp_dir!(), "imgtest-#{System.unique_integer([:positive])}")
prev = Application.get_env(:oh_my_ex_oh_ircd, :imgserv)
Application.put_env(:oh_my_ex_oh_ircd, :imgserv, Keyword.put(prev, :upload_dir, tmp))
on_exit(fn ->
Application.put_env(:oh_my_ex_oh_ircd, :imgserv, prev)
File.rm_rf(tmp)
end)
user = user_fixture()
chan = "#img-#{System.unique_integer([:positive])}"
{:ok, _} = Channels.register(chan, user)
{:ok, user: user, chan: chan, tmp: tmp}
end
defp store(chan, attrs \\ %{}) do
base = %{who: "gmp", content_type: "image/png", byte_size: byte_size(@png)}
Images.store_upload(chan, Map.merge(base, attrs), {:binary, @png})
end
describe "storage" do
test "stores bytes on disk and records metadata", %{chan: chan} do
assert {:ok, %Image{} = img} = store(chan)
assert img.who == "gmp"
assert img.content_type == "image/png"
assert String.ends_with?(img.filename, ".png")
assert File.exists?(Images.path_for(img))
assert File.read!(Images.path_for(img)) == @png
end
test "rejects a disallowed content type", %{chan: chan} do
assert {:error, :bad_type} = store(chan, %{content_type: "application/pdf"})
end
test "rejects an oversized upload", %{chan: chan} do
assert {:error, :too_large} = store(chan, %{byte_size: Images.max_bytes() + 1})
end
test "lookup by filename + recent", %{chan: chan} do
{:ok, img} = store(chan)
assert Images.get_image_by_filename(img.filename).id == img.id
assert hd(Images.recent(chan, 5)).id == img.id
end
test "delete removes row and file", %{chan: chan} do
{:ok, img} = store(chan)
path = Images.path_for(img)
:ok = Images.delete_image(chan, img.id)
refute File.exists?(path)
assert Images.get_image_by_filename(img.filename) == nil
end
end
describe "pinning (per-user budget)" do
test "pin then unpin updates the user's pinned byte total", %{chan: chan, user: user} do
{:ok, img} = store(chan)
assert Images.pinned_bytes_for_user(user.id) == 0
assert {:ok, pinned} = Images.pin_image(chan, img.id, user)
assert pinned.pinned
assert pinned.pinned_by_user_id == user.id
assert Images.pinned_bytes_for_user(user.id) == img.byte_size
assert {:ok, _} = Images.unpin_image(chan, img.id)
assert Images.pinned_bytes_for_user(user.id) == 0
end
test "refuses to pin beyond the per-user budget", %{chan: chan, user: user} do
prev = Application.get_env(:oh_my_ex_oh_ircd, :imgserv)
Application.put_env(:oh_my_ex_oh_ircd, :imgserv, Keyword.put(prev, :pin_budget_mb, 0))
on_exit(fn -> Application.put_env(:oh_my_ex_oh_ircd, :imgserv, prev) end)
{:ok, img} = store(chan)
assert {:error, :over_budget} = Images.pin_image(chan, img.id, user)
refute Images.get_image_by_filename(img.filename).pinned
end
end
describe "retention GC" do
defp backdate(%Image{} = img, days) do
old =
DateTime.utc_now() |> DateTime.add(-days * 86_400, :second) |> DateTime.truncate(:second)
Repo.update_all(from(i in Image, where: i.id == ^img.id), set: [inserted_at: old])
end
test "removes expired non-pinned images and their files", %{chan: chan} do
{:ok, img} = store(chan)
path = Images.path_for(img)
backdate(img, 40)
assert Images.gc() >= 1
refute File.exists?(path)
assert Repo.get(Image, img.id) == nil
end
test "keeps pinned images even when expired", %{chan: chan, user: user} do
{:ok, img} = store(chan)
{:ok, _} = Images.pin_image(chan, img.id, user)
backdate(img, 40)
Images.gc()
assert Repo.get(Image, img.id)
assert File.exists?(Images.path_for(img))
end
test "honours a per-channel retention override", %{chan: chan} do
{:ok, _} = Images.set_retention_days(chan, 1)
{:ok, img} = store(chan)
backdate(img, 2)
assert Images.gc() >= 1
assert Repo.get(Image, img.id) == nil
end
test "keeps images within the window", %{chan: chan} do
{:ok, img} = store(chan)
backdate(img, 5)
Images.gc()
assert Repo.get(Image, img.id)
end
end
describe "tokens + config" do
test "mint/verify round-trips channel + who + user", %{chan: chan, user: user} do
assert {:ok, display, _t} = Images.mint_token(chan, user, "gmp", "cam")
assert {:ok, %{channel: c, who: "gmp", user_id: uid}} = Images.verify_token(display)
assert c.name == String.downcase(chan)
assert uid == user.id
end
test "retention override validation rejects nonsense", %{chan: chan} do
assert {:error, _} = Images.set_retention_days(chan, -3)
end
end
end
neiam
/oh-my-ex-oh-ircd
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
5.1 KiB · text
History
4b6fe3b