Skip to content

Commit

Permalink
Use best practice package name in test examples (open-policy-agent#6731)
Browse files Browse the repository at this point in the history
Best practice according to https://docs.styra.com/regal/rules/testing/test-outside-test-package is to have tests in a package with _test suffix, but this is not documented anywhere.

Updating the examples is an easy way to teach readers the best practice

Signed-off-by: Aleksander <Aleksander.Sleire@Signicat.com>
  • Loading branch information
asleire committed May 3, 2024
1 parent 7ec4d58 commit e011f60
Showing 1 changed file with 66 additions and 40 deletions.
106 changes: 66 additions & 40 deletions docs/content/policy-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ profile.

```live:example:module:read_only,openable
package authz
import rego.v1
allow if {
Expand All @@ -50,23 +51,26 @@ To test this policy, we will create a separate Rego file that contains test case
**example_test.rego**:

```live:example/test:module:read_only
package authz
package authz_test
import rego.v1
import data.authz
test_post_allowed if {
allow with input as {"path": ["users"], "method": "POST"}
authz.allow with input as {"path": ["users"], "method": "POST"}
}
test_get_anonymous_denied if {
not allow with input as {"path": ["users"], "method": "GET"}
not authz.allow with input as {"path": ["users"], "method": "GET"}
}
test_get_user_allowed if {
allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "bob"}
authz.allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "bob"}
}
test_get_another_user_denied if {
not allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "alice"}
not authz.allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "alice"}
}
```

Expand All @@ -81,10 +85,10 @@ To exercise the policy, run the `opa test` command in the directory containing t

```console
$ opa test . -v
data.authz.test_post_allowed: PASS (1.417µs)
data.authz.test_get_anonymous_denied: PASS (426ns)
data.authz.test_get_user_allowed: PASS (367ns)
data.authz.test_get_another_user_denied: PASS (320ns)
data.authz_test.test_post_allowed: PASS (1.417µs)
data.authz_test.test_get_anonymous_denied: PASS (426ns)
data.authz_test.test_get_user_allowed: PASS (367ns)
data.authz_test.test_get_another_user_denied: PASS (320ns)
--------------------------------------------------------------------------------
PASS: 4/4
```
Expand All @@ -97,19 +101,19 @@ Try exercising the tests a bit more by removing the first rule in **example.rego
$ opa test . -v
FAILURES
--------------------------------------------------------------------------------
data.authz.test_post_allowed: FAIL (277.306µs)
data.authz_test.test_post_allowed: FAIL (277.306µs)

query:1 Enter data.authz.test_post_allowed = _
example_test.rego:3 | Enter data.authz.test_post_allowed
example_test.rego:4 | | Fail data.authz.allow with input as {"method": "POST", "path": ["users"]}
query:1 | Fail data.authz.test_post_allowed = _
query:1 Enter data.authz_test.test_post_allowed = _
example_test.rego:3 | Enter data.authz_test.test_post_allowed
example_test.rego:4 | | Fail data.authz_test.allow with input as {"method": "POST", "path": ["users"]}
query:1 | Fail data.authz_test.test_post_allowed = _

SUMMARY
--------------------------------------------------------------------------------
data.authz.test_post_allowed: FAIL (277.306µs)
data.authz.test_get_anonymous_denied: PASS (124.287µs)
data.authz.test_get_user_allowed: PASS (242.2µs)
data.authz.test_get_another_user_denied: PASS (131.964µs)
data.authz_test.test_post_allowed: FAIL (277.306µs)
data.authz_test.test_get_anonymous_denied: PASS (124.287µs)
data.authz_test.test_get_user_allowed: PASS (242.2µs)
data.authz_test.test_get_another_user_denied: PASS (131.964µs)
--------------------------------------------------------------------------------
PASS: 3/4
FAIL: 1/4
Expand All @@ -118,12 +122,15 @@ FAIL: 1/4
## Test Format

Tests are expressed as standard Rego rules with a convention that the rule
name is prefixed with `test_`.
name is prefixed with `test_`. It's a good practice for tests to be placed in a package suffixed with `_test`, but not a requirement.

```live:example_format:module:read_only
package mypackage
package mypackage_test
import rego.v1
import data.mypackage
test_some_descriptive_name if {
# test logic
}
Expand Down Expand Up @@ -153,9 +160,12 @@ by zero condition) the test result is marked as an `ERROR`. Tests prefixed with
**pass_fail_error_test.rego**:

```live:example_results:module:read_only
package example
package example_test
import rego.v1
import data.example
# This test will pass.
test_ok if true
Expand All @@ -167,7 +177,7 @@ test_error if 1 / 0
# This test will be skipped.
todo_test_missing_implementation if {
allow with data.roles as ["not", "implemented"]
example.allow with data.roles as ["not", "implemented"]
}
```

Expand All @@ -176,8 +186,8 @@ of the tests that failed or errored.

```console
$ opa test pass_fail_error_test.rego
data.example.test_failure: FAIL (253ns)
data.example.test_error: ERROR (289ns)
data.example_test.test_failure: FAIL (253ns)
data.example_test.test_error: ERROR (289ns)
pass_fail_error_test.rego:15: eval_builtin_error: div: divide by zero
--------------------------------------------------------------------------------
PASS: 1/3
Expand All @@ -200,7 +210,7 @@ opa test --format=json pass_fail_error_test.rego
"row": 4,
"col": 1
},
"package": "data.example",
"package": "data.example_test",
"name": "test_ok",
"duration": 618515
},
Expand All @@ -210,7 +220,7 @@ opa test --format=json pass_fail_error_test.rego
"row": 9,
"col": 1
},
"package": "data.example",
"package": "data.example_test",
"name": "test_failure",
"fail": true,
"duration": 322177
Expand All @@ -221,7 +231,7 @@ opa test --format=json pass_fail_error_test.rego
"row": 14,
"col": 1
},
"package": "data.example",
"package": "data.example_test",
"name": "test_error",
"error": {
"code": "eval_internal_error",
Expand Down Expand Up @@ -255,6 +265,7 @@ Below is a simple policy that depends on the data document.

```live:with_keyword:module:read_only,openable
package authz
import rego.v1
allow if {
Expand All @@ -271,14 +282,17 @@ Below is the Rego file to test the above policy.
**authz_test.rego**:

```live:with_keyword/tests:module:read_only
package authz
package authz_test
import rego.v1
import data.authz
policies := [{"name": "test_policy"}]
roles := {"admin": ["alice"]}
test_allow_with_data if {
allow with input as {"user": "alice", "role": "admin"}
authz.allow with input as {"user": "alice", "role": "admin"}
with data.policies as policies
with data.roles as roles
}
Expand All @@ -288,7 +302,7 @@ To exercise the policy, run the `opa test` command.

```console
$ opa test -v authz.rego authz_test.rego
data.authz.test_allow_with_data: PASS (697ns)
data.authz_test.test_allow_with_data: PASS (697ns)
--------------------------------------------------------------------------------
PASS: 1/1
```
Expand All @@ -299,6 +313,7 @@ Below is an example to replace a **rule without arguments**.

```live:with_keyword_rules:module:read_only
package authz
import rego.v1
allow1 if allow2
Expand All @@ -309,17 +324,20 @@ allow2 if 2 == 1
**authz_test.rego**:

```live:with_keyword_rules/tests:module:read_only
package authz
package authz_test
import rego.v1
import data.authz
test_replace_rule if {
allow1 with allow2 as true
authz.allow1 with authz.allow2 as true
}
```

```console
$ opa test -v authz.rego authz_test.rego
data.authz.test_replace_rule: PASS (328ns)
data.authz_test.test_replace_rule: PASS (328ns)
--------------------------------------------------------------------------------
PASS: 1/1
```
Expand All @@ -330,6 +348,7 @@ Here is an example to replace a rule's **built-in function** with a user-defined

```live:with_keyword_builtins:module:read_only
package authz
import rego.v1
import data.jwks.cert
Expand All @@ -342,22 +361,25 @@ allow if {
**authz_test.rego**:

```live:with_keyword_builtins/tests:module:read_only
package authz
package authz_test
import rego.v1
import data.authz
mock_decode_verify("my-jwt", _) := [true, {}, {}]
mock_decode_verify(x, _) := [false, {}, {}] if x != "my-jwt"
test_allow if {
allow with input.headers["x-token"] as "my-jwt"
authz.allow with input.headers["x-token"] as "my-jwt"
with data.jwks.cert as "mock-cert"
with io.jwt.decode_verify as mock_decode_verify
}
```

```console
$ opa test -v authz.rego authz_test.rego
data.authz.test_allow: PASS (458.752µs)
data.authz_test.test_allow: PASS (458.752µs)
--------------------------------------------------------------------------------
PASS: 1/1
```
Expand All @@ -366,7 +388,7 @@ In simple cases, a function can also be replaced with a value, as in

```live:with_keyword_builtins/tests/value:module:read_only
test_allow_value if {
allow
authz.allow
with input.headers["x-token"] as "my-jwt"
with data.jwks.cert as "mock-cert"
with io.jwt.decode_verify as [true, {}, {}]
Expand All @@ -383,6 +405,7 @@ function by a built-in function.

```live:with_keyword_funcs:module:read_only
package authz
import rego.v1
replace_rule if {
Expand All @@ -397,17 +420,20 @@ replace(label) if {
**authz_test.rego**:

```live:with_keyword_funcs/tests:module:read_only
package authz
package authz_test
import rego.v1
import data.authz
test_replace_rule if {
replace_rule with input.label as "does-not-matter" with replace as true
authz.replace_rule with input.label as "does-not-matter" with replace as true
}
```

```console
$ opa test -v authz.rego authz_test.rego
data.authz.test_replace_rule: PASS (648.314µs)
data.authz_test.test_replace_rule: PASS (648.314µs)
--------------------------------------------------------------------------------
PASS: 1/1
```
Expand Down

0 comments on commit e011f60

Please sign in to comment.