Polar Tests
In your policy (i.e. the collection of rules for your environment), Polar has a built-in test feature that lets you run unit tests of literal-value queries using a set of facts only visible for the lifetime of the test.
| Feature | Description | 
|---|---|
| test | Introduces a test block, which lets you run a set of unit tests | 
| setup | Declares facts to make accessible for the lifetime of your test | 
| assert | Succeeds if the expression evaluates to true | 
| assert_not | Succeeds if the expression evaluates to false | 
| allow | By default, Polar includes an alias to has_permission, which is a common shorthand rule | 
| test fixture | Declare a test fixture block comprising a set of facts that you can reuse across multiple tests | 
| fixture | Reference a test fixture inside a setupblock to include its facts in thesetupblock | 
Here's an annotated pseudo-example demonstrating the syntax:
test fixture fixture_name {  # semicolon-separated list of facts  ...}test "test name" {  setup {    fixture fixture_name;    # semicolon-separated list of facts    ...  }  # semicolon-separated list of tests of form:  # (assert|assert_not) "rule predicate"("comma-separated list of object literals")  ...}
Simple example
Here's a simple example policy including tests, relying only on primitive types.
# Rule: A parent and their children are considered family.family(a: String, b: String) if  parent(a, b) or parent(b, a);# Create a test so we can introduce temporary facts and make assertionstest "Polar ref family test" {  # Set up our temporary facts that exist only for our test's lifetime  setup {    #  Fact: Bernie has two parents, Pat and Morgan    parent("Bernie", "Pat");    parent("Bernie", "Morgan");  }  # Validate that our policy produces the expected results with our temporary facts  assert family("Bernie", "Pat");  assert family("Morgan", "Bernie");  # Our rule does not state that the parents of a child are family  assert_not family("Pat", "Morgan");  # Rules without matching parameters are false  assert_not family(true, "Morgan");}
Complex example
Here is a more complex example that leverages Polar's abstract types and more closely mirrors how we expect you to use Oso.
# Actors are the who. Most of the time, this is a User# https://www.osohq.com/docs/guides/model-your-apps-authz#actors-and-resourcesactor User {}# This is a resource block that is used for grouping authorization # logic pertaining to a particular type of resource.# A resource represents an application component that we wish to protect.# https://www.osohq.com/docs/reference/glossary#resource-blocksresource Organization {  roles = ["viewer", "owner"];  permissions = ["view", "edit"];  # These are permissions for the Organization resource  "view" if "viewer";  "edit" if "owner";  # Organization owners inherit all permissions that Organization viewers have  "viewer" if "owner";}# This is an example of a different resource block resource Repository {  roles = ["viewer", "owner", "contributor"];  permissions = ["view", "edit", "create"];  # This is an example of how we can define the relationship  # between resources. Relations are set within the resource block.  # This relation is named parent and it says that Repository resource  # is related to Organization.  # https://www.osohq.com/docs/reference/more/resource-blocks#relation-declarations  relations = { parent: Organization };  "view" if "viewer";  "edit" if "contributor";  "create" if "owner";  # contributors are also viewers  # owners are also contributors  "viewer" if "contributor";  "contributor" if "owner";  # roles are inherited from the parent organization  "viewer" if "viewer" on "parent";  "owner" if "owner" on "parent";}# These are examples of how to test the Policy logic.# https://www.osohq.com/docs/guides/policy-teststest "Organization roles and permissions" {  # Authorization decisions require data. This is where you can  # define the test data. The test data is defined in a format  # that Oso Cloud refers to as Facts.  # https://www.osohq.com/docs/concepts/oso-cloud-data-model#facts  setup {    has_role(User{"alice"}, "viewer", Organization{"example"});    has_role(User{"bob"}, "owner", Organization{"example"});  }  # This is how we assert that a user is authorized   # to perform a particular action or not  assert     allow(User{"alice"}, "view", Organization{"example"});  assert     allow(User{"bob"}, "view", Organization{"example"});  assert_not allow(User{"alice"}, "edit", Organization{"example"});  assert     allow(User{"bob"}, "edit", Organization{"example"});}test "Repository roles and permissions" {  setup {    has_role(User{"alice"}, "viewer", Repository{"example"});    has_role(User{"bob"}, "owner", Repository{"example"});    has_role(User{"charlie"}, "contributor", Repository{"example"});  }  assert     allow(User{"alice"}, "view", Repository{"example"});  assert     allow(User{"bob"}, "view", Repository{"example"});  assert     allow(User{"charlie"}, "view", Repository{"example"});  assert_not allow(User{"alice"}, "edit", Repository{"example"});  assert     allow(User{"bob"}, "edit", Repository{"example"});  assert     allow(User{"charlie"}, "edit", Repository{"example"});  assert_not allow(User{"alice"}, "create", Repository{"example"});  assert     allow(User{"bob"}, "create", Repository{"example"});  assert_not allow(User{"charlie"}, "create", Repository{"example"});}test "Repository parent relation" {  setup {    has_relation(Repository{"example"}, "parent", Organization{"parentOrganization"});    has_role(User{"alice"}, "viewer", Organization{"parentOrganization"});    has_role(User{"bob"}, "owner", Organization{"parentOrganization"});  }  assert     allow(User{"alice"}, "view", Repository{"example"});  assert     allow(User{"bob"}, "view", Repository{"example"});  assert_not allow(User{"charlie"}, "view", Repository{"example"});  assert_not allow(User{"dave"}, "view", Repository{"example"});  assert_not allow(User{"alice"}, "edit", Repository{"example"});  assert     allow(User{"bob"}, "edit", Repository{"example"});  assert_not allow(User{"charlie"}, "edit", Repository{"example"});  assert_not allow(User{"dave"}, "edit", Repository{"example"});  assert_not allow(User{"alice"}, "create", Repository{"example"});  assert     allow(User{"bob"}, "create", Repository{"example"});}
Reusing data across multiple tests
You can reuse facts across multiple tests by defining a test fixture block.
Here's an example:
test fixture acme {  has_role(User{"alice"}, "admin", Organization{"acme"});  has_role(User{"bob"}, "member", Organization{"acme"});  has_relation(Repository{"foo"}, "organization", Organization{"acme"});  is_private(Repository{"foo"});}test "by default, members cannot read private repositories" {  setup {    fixture acme;  }  assert allow(User{"alice"}, "read", Repository{"foo"});  assert_not allow(User{"bob"}, "read", Repository{"foo"});}test "members can read private repositories if they have direct access" {  setup {    fixture acme;    has_role(User{"bob"}, "reader", Repository{"foo"});  }  assert allow(User{"bob"}, "read", Repository{"foo"});}
Up next
- Patterns to understand common ways to model your applications.
Talk to an Oso engineer
If you want to learn more about Polar, schedule a 1x1 with an Oso engineer. We're happy to help.