208 lines
5.5 KiB
Elixir
208 lines
5.5 KiB
Elixir
defmodule BDS.CSM006N1ReindexTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
alias BDS.Posts
|
|
alias BDS.Media.Media, as: MediaRecord
|
|
alias BDS.Media.Translation, as: MediaTranslation
|
|
alias BDS.Repo
|
|
alias BDS.Search
|
|
|
|
setup do
|
|
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
|
|
|
|
temp_dir =
|
|
Path.join(System.tmp_dir!(), "bds-csm006-#{System.unique_integer([:positive])}")
|
|
|
|
File.mkdir_p!(temp_dir)
|
|
on_exit(fn -> File.rm_rf(temp_dir) end)
|
|
|
|
{:ok, project} = BDS.Projects.create_project(%{name: "CSM006", data_path: temp_dir})
|
|
%{project: project, temp_dir: temp_dir}
|
|
end
|
|
|
|
describe "Search.reindex_posts/2" do
|
|
test "uses batch inserts — query count does not scale with post count", %{project: project} do
|
|
_post_ids = create_posts_with_translations(project.id, 100)
|
|
|
|
query_count = count_queries(fn -> Search.reindex_posts(project.id) end)
|
|
|
|
# 1 DELETE + 1 SELECT posts + 1 SELECT translations + 1 batch INSERT = 4
|
|
# (may be a few more for chunking, but must be << 100)
|
|
assert query_count > 0, "Telemetry counting returned 0 — check event name"
|
|
assert query_count < 10, "Expected <10 queries for 100 posts, got #{query_count}"
|
|
end
|
|
|
|
test "correctly indexes posts and their translations", %{project: project} do
|
|
{:ok, post1} =
|
|
Posts.create_post(%{
|
|
project_id: project.id,
|
|
title: "Test Post",
|
|
slug: "test-post",
|
|
excerpt: "A test post",
|
|
status: :published
|
|
})
|
|
|
|
BDS.Posts.Translations.upsert_post_translation(post1.id, "de", %{
|
|
title: "Testbeitrag",
|
|
excerpt: "Ein Testbeitrag"
|
|
})
|
|
|
|
Search.reindex_posts(project.id)
|
|
|
|
result =
|
|
Repo.query!(
|
|
"SELECT COUNT(*) as count FROM posts_fts WHERE post_id = ?",
|
|
[post1.id]
|
|
)
|
|
|
|
assert result.rows == [[1]]
|
|
end
|
|
end
|
|
|
|
describe "Search.reindex_media/2" do
|
|
test "uses batch inserts — query count does not scale with media count", %{project: project} do
|
|
_media_ids = create_media_with_translations(project.id, 100)
|
|
|
|
query_count = count_queries(fn -> Search.reindex_media(project.id) end)
|
|
|
|
assert query_count > 0, "Telemetry counting returned 0 — check event name"
|
|
assert query_count < 10, "Expected <10 queries for 100 media items, got #{query_count}"
|
|
end
|
|
|
|
test "correctly indexes media and their translations", %{project: project} do
|
|
now = System.os_time(:second)
|
|
|
|
{:ok, media} =
|
|
%MediaRecord{}
|
|
|> MediaRecord.changeset(%{
|
|
id: Ecto.UUID.generate(),
|
|
project_id: project.id,
|
|
title: "Test Image",
|
|
original_name: "test.jpg",
|
|
filename: "test.jpg",
|
|
mime_type: "image/jpeg",
|
|
size: 1024,
|
|
file_path: "uploads/test.jpg",
|
|
sidecar_path: "uploads/test.json",
|
|
language: "en",
|
|
created_at: now,
|
|
updated_at: now
|
|
})
|
|
|> Repo.insert()
|
|
|
|
%MediaTranslation{}
|
|
|> MediaTranslation.changeset(%{
|
|
id: Ecto.UUID.generate(),
|
|
project_id: project.id,
|
|
translation_for: media.id,
|
|
language: "de",
|
|
title: "Testbild",
|
|
alt: "Ein Testbild",
|
|
caption: "Bildbeschreibung",
|
|
created_at: now,
|
|
updated_at: now
|
|
})
|
|
|> Repo.insert!()
|
|
|
|
Search.reindex_media(project.id)
|
|
|
|
result =
|
|
Repo.query!(
|
|
"SELECT COUNT(*) as count FROM media_fts WHERE media_id = ?",
|
|
[media.id]
|
|
)
|
|
|
|
assert result.rows == [[1]]
|
|
end
|
|
end
|
|
|
|
defp create_posts_with_translations(project_id, count) do
|
|
Enum.map(1..count, fn i ->
|
|
{:ok, post} =
|
|
Posts.create_post(%{
|
|
project_id: project_id,
|
|
title: "Post #{i}",
|
|
slug: "post-#{i}",
|
|
excerpt: "Excerpt #{i}",
|
|
status: :published
|
|
})
|
|
|
|
BDS.Posts.Translations.upsert_post_translation(post.id, "de", %{
|
|
title: "Beitrag #{i}",
|
|
excerpt: "Auszug #{i}"
|
|
})
|
|
|
|
post.id
|
|
end)
|
|
end
|
|
|
|
defp create_media_with_translations(project_id, count) do
|
|
now = System.os_time(:second)
|
|
|
|
Enum.map(1..count, fn i ->
|
|
{:ok, media} =
|
|
%MediaRecord{}
|
|
|> MediaRecord.changeset(%{
|
|
id: Ecto.UUID.generate(),
|
|
project_id: project_id,
|
|
title: "Media #{i}",
|
|
original_name: "file#{i}.jpg",
|
|
filename: "file#{i}.jpg",
|
|
mime_type: "image/jpeg",
|
|
size: 1024 + i,
|
|
file_path: "uploads/file#{i}.jpg",
|
|
sidecar_path: "uploads/file#{i}.json",
|
|
language: "en",
|
|
created_at: now,
|
|
updated_at: now
|
|
})
|
|
|> Repo.insert()
|
|
|
|
%MediaTranslation{}
|
|
|> MediaTranslation.changeset(%{
|
|
id: Ecto.UUID.generate(),
|
|
project_id: project_id,
|
|
translation_for: media.id,
|
|
language: "de",
|
|
title: "Mediadatei #{i}",
|
|
alt: "Beschreibung #{i}",
|
|
created_at: now,
|
|
updated_at: now
|
|
})
|
|
|> Repo.insert!()
|
|
|
|
media.id
|
|
end)
|
|
end
|
|
|
|
defp count_queries(func) do
|
|
test_pid = self()
|
|
ref = make_ref()
|
|
|
|
handler_id = "csm006-query-counter-#{inspect(ref)}"
|
|
|
|
:telemetry.attach(
|
|
handler_id,
|
|
[:bds, :repo, :query],
|
|
fn _event, _measurements, _metadata, _ ->
|
|
send(test_pid, {:query_executed, ref})
|
|
end,
|
|
nil
|
|
)
|
|
|
|
func.()
|
|
|
|
:telemetry.detach(handler_id)
|
|
|
|
count_messages(ref, 0)
|
|
end
|
|
|
|
defp count_messages(ref, acc) do
|
|
receive do
|
|
{:query_executed, ^ref} -> count_messages(ref, acc + 1)
|
|
after
|
|
0 -> acc
|
|
end
|
|
end
|
|
end
|