defmodule Mv.Membership.GroupPoliciesTest do @moduledoc """ Tests for Group resource authorization policies. Verifies that own_data, read_only, normal_user can read groups; only admin can create, update, and destroy groups. """ use Mv.DataCase, async: false alias Mv.Membership alias Mv.Accounts alias Mv.Authorization require Ash.Query setup do system_actor = Mv.Helpers.SystemActor.get_system_actor() %{actor: system_actor} end defp create_role_with_permission_set(permission_set_name, actor) do role_name = "Test Role #{permission_set_name} #{System.unique_integer([:positive])}" case Authorization.create_role( %{ name: role_name, description: "Test role for #{permission_set_name}", permission_set_name: permission_set_name }, actor: actor ) do {:ok, role} -> role {:error, error} -> raise "Failed to create role: #{inspect(error)}" end end defp create_user_with_permission_set(permission_set_name, actor) do role = create_role_with_permission_set(permission_set_name, actor) {:ok, user} = Accounts.User |> Ash.Changeset.for_create(:register_with_password, %{ email: "user#{System.unique_integer([:positive])}@example.com", password: "testpassword123" }) |> Ash.create(actor: actor) {:ok, user} = user |> Ash.Changeset.for_update(:update, %{}) |> Ash.Changeset.manage_relationship(:role, role, type: :append_and_remove) |> Ash.update(actor: actor) {:ok, user_with_role} = Ash.load(user, :role, domain: Mv.Accounts, actor: actor) user_with_role end defp create_admin_user(actor) do create_user_with_permission_set("admin", actor) end defp create_group_fixture(actor) do admin = create_admin_user(actor) {:ok, group} = Membership.create_group( %{name: "Test Group #{System.unique_integer([:positive])}", description: "Test"}, actor: admin ) group end describe "own_data permission set" do setup %{actor: actor} do user = create_user_with_permission_set("own_data", actor) group = create_group_fixture(actor) %{user: user, group: group} end test "can read groups (list)", %{user: user} do {:ok, groups} = Membership.list_groups(actor: user) assert is_list(groups) end test "can read single group", %{user: user, group: group} do {:ok, found} = Ash.get(Membership.Group, group.id, actor: user, domain: Mv.Membership) assert found.id == group.id end end describe "read_only permission set" do setup %{actor: actor} do user = create_user_with_permission_set("read_only", actor) group = create_group_fixture(actor) %{user: user, group: group} end test "can read groups (list)", %{user: user} do {:ok, groups} = Membership.list_groups(actor: user) assert is_list(groups) end test "can read single group", %{user: user, group: group} do {:ok, found} = Ash.get(Membership.Group, group.id, actor: user, domain: Mv.Membership) assert found.id == group.id end end describe "normal_user permission set" do setup %{actor: actor} do user = create_user_with_permission_set("normal_user", actor) group = create_group_fixture(actor) %{user: user, group: group} end test "can read groups (list)", %{user: user} do {:ok, groups} = Membership.list_groups(actor: user) assert is_list(groups) end test "can read single group", %{user: user, group: group} do {:ok, found} = Ash.get(Membership.Group, group.id, actor: user, domain: Mv.Membership) assert found.id == group.id end test "can create group", %{user: user} do assert {:ok, created} = Membership.create_group( %{name: "New Group #{System.unique_integer([:positive])}", description: "New"}, actor: user ) assert created.name =~ "New Group" end test "can update group", %{user: user, group: group} do assert {:ok, updated} = Membership.update_group(group, %{description: "Updated"}, actor: user) assert updated.description == "Updated" end test "can destroy group", %{user: user, group: group} do assert :ok = Membership.destroy_group(group, actor: user) end end describe "admin permission set" do setup %{actor: actor} do user = create_user_with_permission_set("admin", actor) group = create_group_fixture(actor) %{user: user, group: group} end test "can read groups (list)", %{user: user} do {:ok, groups} = Membership.list_groups(actor: user) assert is_list(groups) end test "can create group", %{user: user} do name = "Admin Group #{System.unique_integer([:positive])}" assert {:ok, group} = Membership.create_group(%{name: name, description: "Admin created"}, actor: user) assert group.name == name end test "can update group", %{user: user, group: group} do assert {:ok, updated} = Membership.update_group(group, %{description: "Updated by admin"}, actor: user) assert updated.description == "Updated by admin" end test "can destroy group", %{user: user, group: group} do assert :ok = Membership.destroy_group(group, actor: user) assert {:error, _} = Ash.get(Membership.Group, group.id, actor: user, domain: Mv.Membership) end end end