Home

Awesome

rego-test-assertions

Tiny Rego library providing helper functions for unit testing. The library primarily contains various assertion functions, which will print the expected result vs. the outcome to the console on failure. This allows you to quickly grasp what went wrong in your unit tests, resulting in a faster test iteration process!

This assert library is what I’ve been wanting since I started using OPA. Fixed something in ten minutes, while eating a sandwich, I’d previously been poking at for a couple of hours. You’ve made my day!

— Duncan Thomas, Groupon

Note that since OPA v0.66.0, the opa test command has built-in support for printing variable bindings for failed test assertions when run with the --var-values flag, which can be used as an alternative to this library if your goal is only to see what variable values were bound when a test failed.

Usage

Simply download the test assertions library policy file and place it somewhere opa test checks for policy and tests:

Alternatively, use ODM to add the library to your project:

odm depend rego-test-assertions --no-namespace \
    git+https://github.com/anderseknert/rego-test-assertions

In order to use the test assertion functions, import the test.assert package:

import data.test.assert

Functions

Once imported, all functions may now be referenced like assert.<function>. Using the assert package prefix avoids having these functions clash with other built-ins and custom functions, and makes it clear in your test code what the purpose of these functions is. As an added bonus, you won't need repeated import statements to import each function separetely.

FunctionArgumentsExample console output
assert.equalsexpected, resultexpected equals: "foo" got: "bar"
assert.not_equalsexpected, resultexpected not equals: 1 got: 1
assert.all_equalscoll, valueexpected all items to have value 2, failed for [1]
assert.none_equalscoll, valueexpected no items to have value 2, failed for [2, 2]
assert.hasitem, collexpected string "foo" in array got: ["bar", "baz"]
assert.not_hasitem, collexpected string "foo" not in set got {"foo", "x"}
assert.emptycollexpected empty set got: {"admin", "dba"}
assert.not_emptycollexpected empty array
assert.starts_withstr, searchexpected "test" to start with "a"
assert.ends_withstr, searchexpected "test" to end with "a"
assert.all_starts_withcoll, searchexpected all strings to start with "a", failed for ["b"]
assert.all_ends_withcoll, searchexpected all strings to end with "a", failed for ["b"]
assert.none_starts_swithcoll, searchexpected no strings to start with "a", failed for ["a"]
assert.none_ends_swithcoll, searchexpected no strings to end with "a", failed for ["a"]
assert.failmsgfail with provided message!

Example

Policy

package rego.example

deny[msg] {
    msg := "I'll always deny that"
}

violation[msg] {
    input.user.name == "banned"
    msg := "You're banned!"
}

Test without assertions

package rego.example_test

import future.keywords.in

import data.example.deny
import data.example.violation

test_empty_without_assertion {
    count(deny) == 0
}

test_in_without_assertion {
    "You're banned!" in violation with input.user.name as "bob"
}
❯ opa test example_test.rego
example_test.rego:
data.rego.example_test.test_empty_without_assertion: FAIL (178.375µs)
data.rego.example_test.test_in_without_assertion: FAIL (99.416µs)

--------------------------------------------------------------------------------
FAIL: 2/2

Test with assertions

package rego.example_test

import data.example.deny
import data.example.violation

import data.test.assert

test_empty_with_assertion {
    assert.empty(deny)
}

test_in_with_assertion {
    assert.has("You're banned!", violation) with input.user.name as "bob"
}
❯ opa test example_test.rego
example_test.rego:
data.rego.example_test.test_empty_with_assertion: FAIL (206.5µs)

  expected empty set got {"I'll always deny that"}

data.rego.example_test.test_in_with_assertion: FAIL (138.792µs)

  expected string "You're banned!" in set got set()

--------------------------------------------------------------------------------
FAIL: 2/2

Prerequisites

OPA v0.39.0 and above — a bug in older versions caused the print function to error in else blocks, which this library makes heavy use of.