test: add tests for group resource #371
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
2ebf289112
commit
0216dfcbbb
5 changed files with 879 additions and 0 deletions
197
test/membership/member_groups_relationship_test.exs
Normal file
197
test/membership/member_groups_relationship_test.exs
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
defmodule Mv.Membership.MemberGroupsRelationshipTest do
|
||||
@moduledoc """
|
||||
Tests for Member resource extension with groups relationship.
|
||||
"""
|
||||
use Mv.DataCase, async: true
|
||||
|
||||
alias Mv.Membership
|
||||
|
||||
require Ash.Query
|
||||
import Ash.Expr
|
||||
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
%{actor: system_actor}
|
||||
end
|
||||
|
||||
describe "Relationships" do
|
||||
test "member has many_to_many groups relationship (load with preloading)", %{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, _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
|
||||
)
|
||||
|
||||
# Load member with groups
|
||||
{:ok, member_with_groups} =
|
||||
Ash.load(member, :groups, actor: actor, domain: Mv.Membership)
|
||||
|
||||
assert length(member_with_groups.groups) == 2
|
||||
assert Enum.any?(member_with_groups.groups, &(&1.id == group1.id))
|
||||
assert Enum.any?(member_with_groups.groups, &(&1.id == group2.id))
|
||||
end
|
||||
|
||||
test "load multiple members with groups preloaded (N+1 prevention)", %{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, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
|
||||
|
||||
{: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
|
||||
)
|
||||
|
||||
# Load all members with groups in single query
|
||||
{:ok, members} =
|
||||
Ash.read(Mv.Membership.Member, actor: actor, domain: Mv.Membership, load: [:groups])
|
||||
|
||||
member1_loaded = Enum.find(members, &(&1.id == member1.id))
|
||||
member2_loaded = Enum.find(members, &(&1.id == member2.id))
|
||||
|
||||
assert length(member1_loaded.groups) == 1
|
||||
assert length(member2_loaded.groups) == 1
|
||||
assert hd(member1_loaded.groups).id == group.id
|
||||
assert hd(member2_loaded.groups).id == group.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "Member-Group Association Operations" do
|
||||
test "add member to group via Ash API", %{actor: actor} do
|
||||
{:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor)
|
||||
{:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
|
||||
|
||||
assert {:ok, member_group} =
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
assert member_group.member_id == member.id
|
||||
assert member_group.group_id == group.id
|
||||
end
|
||||
|
||||
test "remove member from group via Ash API", %{actor: actor} do
|
||||
{:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor)
|
||||
{:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
|
||||
|
||||
{:ok, member_group} =
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
# Remove association
|
||||
:ok = Membership.destroy_member_group(member_group, actor: actor)
|
||||
|
||||
# Verify association is removed
|
||||
{:ok, mgs} =
|
||||
Ash.read(
|
||||
Mv.Membership.MemberGroup
|
||||
|> Ash.Query.filter(expr(member_id == ^member.id and group_id == ^group.id)),
|
||||
actor: actor,
|
||||
domain: Mv.Membership
|
||||
)
|
||||
|
||||
assert mgs == []
|
||||
end
|
||||
|
||||
test "add member to multiple groups in single operation", %{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 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
|
||||
)
|
||||
|
||||
# Verify all associations exist
|
||||
{:ok, member_with_groups} =
|
||||
Ash.load(member, :groups, actor: actor, domain: Mv.Membership)
|
||||
|
||||
assert length(member_with_groups.groups) == 3
|
||||
end
|
||||
end
|
||||
|
||||
describe "Edge Cases" do
|
||||
test "adding member to same group twice fails (duplicate prevention)", %{actor: actor} do
|
||||
{:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor)
|
||||
{:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
|
||||
|
||||
{:ok, _mg1} =
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
# Try to add again
|
||||
assert {:error, %Ash.Error.Invalid{}} =
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: actor
|
||||
)
|
||||
end
|
||||
|
||||
test "removing member from group they're not in (idempotent, no error)", %{actor: actor} do
|
||||
{:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor)
|
||||
{:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor)
|
||||
|
||||
# Verify no association exists
|
||||
{:ok, nil} =
|
||||
Ash.read_one(
|
||||
Mv.Membership.MemberGroup
|
||||
|> Ash.Query.filter(expr(member_id == ^member.id and group_id == ^group.id)),
|
||||
actor: actor,
|
||||
domain: Mv.Membership
|
||||
)
|
||||
|
||||
# Test idempotency: Create association, delete it, then try to delete again
|
||||
# This verifies that destroy_member_group is idempotent
|
||||
{:ok, member_group} =
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
# First deletion should succeed
|
||||
assert :ok = Membership.destroy_member_group(member_group, actor: actor)
|
||||
|
||||
# Verify association is deleted
|
||||
{:ok, nil} =
|
||||
Ash.read_one(
|
||||
Mv.Membership.MemberGroup
|
||||
|> Ash.Query.filter(expr(id == ^member_group.id)),
|
||||
actor: actor,
|
||||
domain: Mv.Membership
|
||||
)
|
||||
|
||||
# Try to destroy again - should be idempotent (either succeed or return not found error)
|
||||
# Note: This tests the idempotency of the destroy action
|
||||
result = Membership.destroy_member_group(member_group, actor: actor)
|
||||
|
||||
# Should either succeed (idempotent) or return an error (not found)
|
||||
# Both behaviors are acceptable for idempotency
|
||||
assert result == :ok || match?({:error, _}, result)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue