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.
Function | Arguments | Example console output |
---|---|---|
assert.equals | expected , result | expected equals: "foo" got: "bar" |
assert.not_equals | expected , result | expected not equals: 1 got: 1 |
assert.all_equals | coll , value | expected all items to have value 2, failed for [1] |
assert.none_equals | coll , value | expected no items to have value 2, failed for [2, 2] |
assert.has | item , coll | expected string "foo" in array got: ["bar", "baz"] |
assert.not_has | item , coll | expected string "foo" not in set got {"foo", "x"} |
assert.empty | coll | expected empty set got: {"admin", "dba"} |
assert.not_empty | coll | expected empty array |
assert.starts_with | str , search | expected "test" to start with "a" |
assert.ends_with | str , search | expected "test" to end with "a" |
assert.all_starts_with | coll , search | expected all strings to start with "a", failed for ["b"] |
assert.all_ends_with | coll , search | expected all strings to end with "a", failed for ["b"] |
assert.none_starts_swith | coll , search | expected no strings to start with "a", failed for ["a"] |
assert.none_ends_swith | coll , search | expected no strings to end with "a", failed for ["a"] |
assert.fail | msg | fail 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.