defmodule Mv.Authorization.Checks.HasPermissionIntegrationTest do @moduledoc """ Integration tests for HasPermission policy check. These tests verify that the filter expressions generated by HasPermission have the correct structure for relationship-based filtering. Note: Full integration tests with real queries require resources to have policies that use HasPermission. These tests validate filter expression structure and ensure the relationship paths are correct. """ use ExUnit.Case, async: true alias Mv.Authorization.Checks.HasPermission # Helper to create mock actor with role defp create_actor_with_role(permission_set_name, opts \\ []) do actor = %{ id: "user-#{System.unique_integer([:positive])}", role: %{permission_set_name: permission_set_name} } # Add member_id if provided (needed for :linked scope tests) case Keyword.get(opts, :member_id) do nil -> actor member_id -> Map.put(actor, :member_id, member_id) end end describe "Filter Expression Structure - :linked scope" do test "Member filter uses user.id relationship path" do actor = create_actor_with_role("own_data", member_id: "member-123") authorizer = create_authorizer(Mv.Membership.Member, :read) filter = HasPermission.auto_filter(actor, authorizer, []) # Verify filter is not nil (should return a filter for :linked scope) assert not is_nil(filter) # The filter should be a valid expression (keyword list or Ash.Expr) # We verify it's not nil and can be used in queries assert is_list(filter) or is_map(filter) end test "CustomFieldValue filter uses member.user.id relationship path" do actor = create_actor_with_role("own_data", member_id: "member-123") authorizer = create_authorizer(Mv.Membership.CustomFieldValue, :read) filter = HasPermission.auto_filter(actor, authorizer, []) # Verify filter is not nil assert not is_nil(filter) # The filter should be a valid expression assert is_list(filter) or is_map(filter) end end describe "Filter Expression Structure - :own scope" do test "User filter uses id == actor.id" do actor = create_actor_with_role("own_data") authorizer = create_authorizer(Mv.Accounts.User, :read) filter = HasPermission.auto_filter(actor, authorizer, []) # Verify filter is not nil (should return a filter for :own scope) assert not is_nil(filter) # The filter should be a valid expression assert is_list(filter) or is_map(filter) end end describe "Filter Expression Structure - :all scope" do test "Admin can read all members without filter (returns expr(true))" do actor = create_actor_with_role("admin") authorizer = create_authorizer(Mv.Membership.Member, :read) filter = HasPermission.auto_filter(actor, authorizer, []) # :all scope should return [] (empty keyword list = no filter = allow all records) # After auto_filter fix: no longer returns nil, returns [] instead assert filter == [] end end # Helper to create a mock authorizer defp create_authorizer(resource, action) do %Ash.Policy.Authorizer{ resource: resource, subject: %{ action: %{type: action}, data: nil } } end end