Skip to content

Use assertions trees

Whether verifying the scaling behavior of a database cluster or ensuring data consistency across instances, Chainsaw's assertion model provides the precision and flexibility needed for comprehensive validation.

Chainsaw allows declaring complex assertions with a simple and no-code approach, allowing assertions based on comparisons beyond simple equality, working with arrays, and other scenarios that could not be achieved before.

Tip

Under the hood, Chainsaw uses kyverno-json assertion trees. Refer to the assertion trees documentation for more details on the supported syntax.

Beyond simple equality

The assertion below will check that the number of replicas for a deployment is greater than 3 AND less than 6.

Chainsaw doesn't need to know the exact expected number of replicas. The (replicas > 3 && replicas < 6) expression will be evaluated until the result is true or the operation timeout expires (making the assertion fail).

apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
  name: example
spec:
  steps:
  - try:
    # ...
    - assert:
        resource:
          apiVersion: v1
          kind: Deployment
          metadata:
            name: foo
          spec:
            (replicas > `3` && replicas < `6`): true
    # ...

Working with arrays

Chainsaw query language makes it easy to assert on arrays. You can filter and transform arrays to select what you want to assert.

Filtering

In the example below we are creating a resource, then we assert that a condition with type == 'Ready' exists and has a field matching status: 'True':

apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
  name: example
spec:
  steps:
  - try:
    - apply:
        resource:
          apiVersion: tempo.grafana.com/v1alpha1
          kind: TempoStack
          metadata:
            name: simplest
          spec:
            storage:
              secret:
                name: minio
                type: s3
            # ...
    - assert:
        resource:
          apiVersion: tempo.grafana.com/v1alpha1
          kind: TempoStack
          metadata:
            name: simplest
          status:
            # filter conditions array to keep elements where `type == 'Ready'`
            # and assert there's a single element matching the filter
            # and that this element status is `True`
            (conditions[?type == 'Ready']):
            - status: 'True'

Comprehensive reporting

Chainsaw offers detailed resource diffs upon assertion failures.

In the example below, the assertion failure message (metadata.annotations.foo: Invalid value: "null": Expected value: "bar") is augmented with a resource diff.

It provides a clear view of discrepancies between expected and actual resources and gives more context around the specific failure (we can easily identify the owner of the offending pod for example).

| 09:55:50 | deployment | step-1   | ASSERT    | RUN   | v1/Pod @ chainsaw-rare-liger/*
| 09:56:20 | deployment | step-1   | ASSERT    | ERROR | v1/Pod @ chainsaw-rare-liger/*
    === ERROR
    ---------------------------------------------------
    v1/Pod/chainsaw-rare-liger/example-5477b4ff8c-tnhd9
    ---------------------------------------------------
    * metadata.annotations.foo: Invalid value: "null": Expected value: "bar"

    --- expected
    +++ actual
    @@ -1,10 +1,16 @@
      apiVersion: v1
      kind: Pod
      metadata:
    -  annotations:
    -    foo: bar
        labels:
          app: nginx
    +  name: example-5477b4ff8c-tnhd9
        namespace: chainsaw-rare-liger
    +  ownerReferences:
    +  - apiVersion: apps/v1
    +    blockOwnerDeletion: true
    +    controller: true
    +    kind: ReplicaSet
    +    name: example-5477b4ff8c
    +    uid: 118abe16-ec42-4894-83db-64479c4aac6f
      spec: {}
| 09:56:20 | deployment | step-1   | TRY       | DONE  |

Next step

To continue our exploration of the main Chainsaw features, let's look at bindings and resource templating next.