mitgliederverwaltung/test/membership/group_integration_test.exs
Simon 67e06e12ce
All checks were successful
continuous-integration/drone/push Build is passing
refactor: move slow performance tests to extra test suite
2026-01-28 12:00:32 +01:00

141 lines
5.3 KiB
Elixir

defmodule Mv.Membership.GroupIntegrationTest do
@moduledoc """
Integration tests for many-to-many relationships and query performance.
"""
use Mv.DataCase, async: false
alias Mv.Membership
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: system_actor}
end
describe "Many-to-Many Relationship" do
test "member can belong to multiple groups", %{actor: actor} do
{:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor)
{:ok, group1} = Membership.create_group(%{name: "Group One"}, actor: actor)
{:ok, group2} = Membership.create_group(%{name: "Group Two"}, actor: actor)
{:ok, group3} = Membership.create_group(%{name: "Group Three"}, actor: actor)
# Add member to all groups
{:ok, _mg1} =
Membership.create_member_group(%{member_id: member.id, group_id: group1.id},
actor: actor
)
{:ok, _mg2} =
Membership.create_member_group(%{member_id: member.id, group_id: group2.id},
actor: actor
)
{:ok, _mg3} =
Membership.create_member_group(%{member_id: member.id, group_id: group3.id},
actor: actor
)
# Load member with groups
{:ok, member_with_groups} =
Ash.load(member, :groups, actor: actor, domain: Mv.Membership)
assert length(member_with_groups.groups) == 3
assert Enum.any?(member_with_groups.groups, &(&1.id == group1.id))
assert Enum.any?(member_with_groups.groups, &(&1.id == group2.id))
assert Enum.any?(member_with_groups.groups, &(&1.id == group3.id))
end
test "group can contain multiple members", %{actor: actor} do
{:ok, member1} = Membership.create_member(%{email: "member1@test.com"}, actor: actor)
{:ok, member2} = Membership.create_member(%{email: "member2@test.com"}, actor: actor)
{:ok, member3} = Membership.create_member(%{email: "member3@test.com"}, actor: actor)
{:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
# Add all members to group
{:ok, _mg1} =
Membership.create_member_group(%{member_id: member1.id, group_id: group.id},
actor: actor
)
{:ok, _mg2} =
Membership.create_member_group(%{member_id: member2.id, group_id: group.id},
actor: actor
)
{:ok, _mg3} =
Membership.create_member_group(%{member_id: member3.id, group_id: group.id},
actor: actor
)
# Load group with members
{:ok, group_with_members} =
Ash.load(group, :members, actor: actor, domain: Mv.Membership)
assert length(group_with_members.members) == 3
assert Enum.any?(group_with_members.members, &(&1.id == member1.id))
assert Enum.any?(group_with_members.members, &(&1.id == member2.id))
assert Enum.any?(group_with_members.members, &(&1.id == member3.id))
end
end
@moduletag :slow
describe "Query Performance" do
test "preloading groups with members avoids N+1 queries", %{actor: actor} do
# Create test data
{:ok, member1} = Membership.create_member(%{email: "member1@test.com"}, actor: actor)
{:ok, member2} = Membership.create_member(%{email: "member2@test.com"}, actor: actor)
{:ok, group1} = Membership.create_group(%{name: "Group One"}, actor: actor)
{:ok, group2} = Membership.create_group(%{name: "Group Two"}, actor: actor)
# Create associations
{:ok, _mg1} =
Membership.create_member_group(%{member_id: member1.id, group_id: group1.id},
actor: actor
)
{:ok, _mg2} =
Membership.create_member_group(%{member_id: member1.id, group_id: group2.id},
actor: actor
)
{:ok, _mg3} =
Membership.create_member_group(%{member_id: member2.id, group_id: group1.id},
actor: actor
)
# Count queries using Telemetry
query_count = Agent.start_link(fn -> 0 end) |> elem(1)
handler = fn _event, _measurements, _metadata, _config ->
Agent.update(query_count, &(&1 + 1))
end
:telemetry.attach("test-query-counter", [:ash, :query, :start], handler, nil)
# Load all members with groups preloaded (should be efficient with JOIN)
{:ok, members} =
Ash.read(Mv.Membership.Member, actor: actor, domain: Mv.Membership, load: [:groups])
final_count = Agent.get(query_count, & &1)
:telemetry.detach("test-query-counter")
member1_loaded = Enum.find(members, &(&1.id == member1.id))
member2_loaded = Enum.find(members, &(&1.id == member2.id))
# Verify preloading worked
assert length(member1_loaded.groups) == 2
assert length(member2_loaded.groups) == 1
# Verify groups are correctly associated
assert Enum.any?(member1_loaded.groups, &(&1.id == group1.id))
assert Enum.any?(member1_loaded.groups, &(&1.id == group2.id))
assert Enum.any?(member2_loaded.groups, &(&1.id == group1.id))
# Verify query count is reasonable (should be 2 queries: one for members, one for groups)
# Note: Exact count may vary based on Ash implementation, but should be much less than N+1
assert final_count <= 3,
"Expected max 3 queries (members + groups + possible count), got #{final_count}. This suggests N+1 query problem."
end
end
end