Skip to main content
Version: 1.1

Testing ALFA policies

Testing is essential to verify that an ALFA project functions correctly and meets its requirements. Axiomatics Policy DevOps supports various testing stages, validating your domains, policies, and attribute connectors for production use. Specifically:

Unit testing (Dev pipeline | pre-deployment)

  • Policy: Test a specific policy or rule in isolation for a given use case, without attribute connectors or other policies.
  • Attribute connector: Test that a specific attribute connector can connect to an external PIP and retrieve attributes.

Integration testing (Dev pipeline | pre-deployment)

  • Single policy: Test the successful integration of a specific policy for a given use case with its required attribute connectors.
  • Multiple policies: Test the combined functionality of multiple use cases with multiple policies, including the correct operation of combination algorithms (conflict resolution).

System/acceptance testing (Post-deployment | product environment may be excluded)

  • Test that the main policy addresses all functional and business use cases.

Policy JUnit tests

Follow the steps below to write JUnit tests for ALFA policies. These tests simulate authorization requests to verify policy decisions, attribute handling, and access control behavior.

  1. Create a Java test class under src/test.

    /src/test/MyUnitTest.java
    import  org.junit.jupiter.api.extension.RegisterExtension;
    import com.axiomatics.cr.alfa.test.junit.AlfaExtension;

    public class MyUnitTest {

    @RegisterExtension
    public AlfaExtension alfa = new AlfaExtension();
  2. Specify the policy under test. This can be the main policy or a specific policy, depending on whether it's a system, integration, or unit test.

            @RegisterExtension
    public AlfaExtension target = new AlfaExtension().withMainPolicy("acme.Main");
    note

    withMainPolicy is not needed if your alfaSpecifications directory contains only one root policy.

  3. Execute a test and use one of the following Hamcrest matchers for assertions: permit(), deny(), notApplicable(), or intermediate().

    import static com.axiomatics.cr.alfa.test.junit.matchers.AlfaMatchers.*
    import static org.hamcrest.CoreMatchers.is;
    import static org.hamcrest.CoreMatchers.not;
    import org.junit.jupiter.api.Test;
    import static org.hamcrest.MatcherAssert.assertThat;

    ...

    @Test
    public void shouldNotPermitConsultantsToApprove() {
    TestResponse result = target.newTestRequest()
    .with("user.role", "consultant")
    .with("action", "approve")
    .evaluate();

    assertThat(result, is(not(permit())));
    note

    Use Hamcrest predicates such as is() and is(not()). See the Hamcrest TutorialOpens in a new tab for more information.

    Important

    Test method names should be descriptive and sufficient to implement and verify the test. If you have a test case specification, you can reference it. Don't be concerned if the name is lengthy.

  4. Test obligations or advice in your policy as in the examples below.

    tip

    Obligations, typically associated with permit decisions, are mandatory actions that must be performed when a condition or decision is met. Advice is optional info commonly associated with deny decisions, offering explanations or guidance regarding the denied access.

    Example 1:

    Advice assertion example
    import static org.hamcrest.CoreMatchers.hasItem;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static com.axiomatics.cr.alfa.test.junit.matchers.AttributeAssignmentMatcher.withIdAndText;
    import static com.axiomatics.cr.alfa.test.junit.matchers.AttributeAssignmentMatcher.withText;

    TestResponse result = target.evaluate();
    assertThat(result.getAdvice(), hasItem(withText("Advice from PDP")));

    Example 2:

    Obligation assertion example targeting specific attribute
    import static org.hamcrest.CoreMatchers.hasItem;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static com.axiomatics.cr.alfa.test.junit.matchers.AttributeAssignmentMatcher.withIdAndText;
    import static com.axiomatics.cr.alfa.test.junit.matchers.AttributeAssignmentMatcher.withText;

    TestResponse result = target.evaluate();
    assertThat(result.getObligation(), hasItem(withIdAndText("org.obligation.message", "Obligation from PDP")));
    Important

    For unit tests, avoid withAttributeConnectors(). Simulate key attributes using .with(...) for test input.

Attribute connectors tests

You should also run unit tests for your attribute connectors. Create a test file with the content below.

src/test/java/OurConnectorUnitTest.java
import com.axiomatics.cr.alfa.test.junit.AlfaExtension;
import com.axiomatics.cr.alfa.test.junit.AttributeConnector;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.Test;

import java.util.List;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;

public class OurConnectorUnitTest {

@RegisterExtension
public AlfaExtension alfa = new AlfaExtension();

@Test
public void shouldGetRoleConsultantforIdentityCecilia() {
AttributeConnector target = alfa.newAttributeTest("ourConnector");
List<String> result = target.lookup("user.role").by("user.identity", "cecilia");
assertThat(result, hasItem("consultant"));
}
MethodDescription
newAttributeTest(...)Enter the filename of your attribute connector (without the extension) located in src/authorizationDomain/attributeConnectors.
lookup(...)Specify the attribute (as a string) that you want to retrieve from your PIP.
by(...)Provide pairs of strings representing the key attribute names and values required for the lookup.

For example, if an attribute connector retrieves a user's approval limit based on their identity and the purchase order's department, the lookup might look like this:

target.lookup("user.approval.limit").by("user.identity", "cecilia", "resource.purchaseOrder.department", "InternalSales");

For unit tests, add any environment variables required by attribute connectors, such as URLs and credentials, to the test section of your build.gradle file.

Chained attribute connectors

When using chained attribute connectors that rely on each other, you can create an integration test by feeding the output of one connector as input to another. This is particularly useful when combining HTTP and Parser attribute connectors.

chained attribute connector test
   @Test
public void shouldGetCleareanceForUserAlice() {
String user = "alice";
String userServiceHttpBodyValue = rule.newAttributeTest("userHttpService").lookup("user.serviceHttpBody").by("user.identity", user).get(0);
String userClearance = rule.newAttributeTest("userHttpServiceParser").lookup("user.clearance").by("user.serviceHttpBody",userServiceHttpBodyValue).get(0);
assertThat(userClearance, is("classified"));
}

Authorization domain system tests

Authorization domain system tests evaluate all your policies and attribute connectors together to ensure they satisfy the use cases and requirements.

Example of system test
package com.myorg.alfa;

import com.axiomatics.cr.alfa.test.junit.AlfaExtension;
import com.axiomatics.cr.alfa.test.junit.TestRequest;
import com.axiomatics.cr.alfa.test.junit.TestResponse;
import org.junit.jupiter.api.Test;
import ort org.junit.jupiter.api.extension.RegisterExtension;

import static com.axiomatics.cr.alfa.test.junit.matchers.AlfaMatchers.permit;
import static com.axiomatics.cr.alfa.test.junit.matchers.AttributeAssignmentMatcher.withText;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;

public class MySystemTest {

@RegisterExtension
public AlfaExtension alfa = new AlfaExtension().withAttributeConnectors();

@Test
public void shouldGiveMartinAccessToResource1() {
TestRequest target = alfa.newTestRequest()
.with("user.identity", "martin")
.with("resource.identity", "1");

TestResponse result = target.evaluate();

assertThat(result, is(permit()));
assertThat(result.getAdvice(), hasItem(withText("Permit since user is manager")));
}
}

To create a system test:

  1. Omit the withMainPolicy() declaration in the test rule. This defaults to testing the main policy for your domain (specified in build.gradle).
  2. Add the withAttributeConnectors() declaration to include all attribute connectors in the test.

The required environment variables should already be defined from the attribute connector unit tests.