logo
0
2
Login
docs: 增加 isNullOrEmpty & isEmpty 断言介绍

Helm Unit Test Plugin

No need to deploy a Kubernetes cluster, perform unit tests on Helm Charts. Supports concurrent testing and allows testing only a single or a subset of files (supports glob pattern matching).

Image

cnbcool/helm-unittest:latest

Or

docker.cnb.cool/cnb/plugins/cnbcool/helm-unittest:latest

Usage

main: push: ut: stages: - name: Execute Helm test cases image: cnbcool/helm-unittest:latest settings: mode: sequential helm_dir: my-helmchart/ tests_file: - misc/tests/job_test.yaml - misc/tests/client/*_test.yaml
  • mode: Execution mode. This property is optional and defaults to sequential. Supports the following values. When an unsupported value is provided, it will forcibly use sequential mode.
    • sequential: Execute all test cases sequentially and output a complete test report.
    • concurrent: Execute each test case concurrently, with each test case generating a separate test report. After all test cases are executed concurrently, output the test reports for each case.
    • split: Execute all test cases sequentially and output each test report separately.
  • helm_dir: Specify the Helm chart directory. This property is optional and defaults to the current repository. In multi-repository projects, you can specify the Helm chart directory within the project for testing.
  • tests_file: Specify the test case files to be tested (supports glob expression matching). This property is optional and defaults to executing all test files ending with _test.yaml in the helm_dir/tests directory. This property is commonly used in Helm chart debugging or to execute only certain critical test cases, avoiding full test execution that would take too much time.

Test Document Development Specification

This section describes how to define your own unit test cases in a YAML file.

Test Suite

A test suite is a collection of tests with the same purpose and scope defined in one single file. The root structure of a test suite is like below:

suite: test deploy and service

The suite property type is string. It is also an optional property. The suite name to show on test result output. For example:

PASS test deploy and service tests/deploy_and_service_test.yaml

Specify additional values files

The property values can specify attitional values files. The values files used to renders the chart, think it as the -f, --values options of helm install. ❗️The file path should be the relative path from the test suite file itself.

The values property is an array of string, optional.

For example, the following test suite specify an additional values file (values-override.yaml) which is located in the same directory as the current test file. This means that the ./values-override.yaml file and the Helm Chart's values.yaml file will be merged during rendering, with the former overriding conflicting configurations in the latter.

suite: Test Deployment values: - values-override.yaml

Thus, the order of elements in the values property is critical. In the following example, the values property includes 4 YAML files. During the rendering process, for overlapping configurations, the last declared file will override the previous ones.

suite: Test Deployment values: - a.yaml - b.yaml - override/c.yaml - ../values-override.yaml

When the values property is omitted, only the values.yaml file within the Helm Chart will be used to render the chart.

Set The Values Directly In Suite File

The set property is used to individually configure one or more configuration items within a test suite. It's type is object of any, optional. The key is the value path with the format just like --set option of helm install, for example image.pullPolicy. The value is anything you want to set to the path specified by the key, which can be even an array or an object. This set will override values which are already set in the values file.

In the following example, the --set property defines a configuration path global.image.tag with the value latest. If the configuration item exists in the values (including both the Helm Chart's default values.yaml and any additional values files specified via values property), the set directive will override its value (i.e., global.image.tag will resolve to latest after rendering). If the configuration item does not exist, set will add it to the final configuration set.

suite: My Suite Name set: global.image.tag: latest

It is important to note that the declaration order of set property is irrelevant to values. For example, the following two configurations produce identical rendering results: set definitions will consistently override values specified in values files, regardless of their order.

suite: My Suite Name set: global.image.tag: latest values: - ../values-override.yaml
suite: My Suite Name values: - ../values-override.yaml set: global.image.tag: latest

The set property supports multiple configuration paths, such as:

suite: My Suite Name set: global.image.tag: latest group: enable: false mysql.args: - args1 - args2

💡A recommended best practice is to utilize values property (e.g., creating an additional_values directory under tests/ to store configuration collections for specific scenarios like tests/additional_values/suite1_values.yaml) to encapsulate test-specific configurations, avoiding excessive set declarations in test suite.

suite: My Suite Name values: - additional_values/suite1_values.yaml

The Template Files Scope To Test In This Suite

The property templates is an array of string, recommended. The template files scope to test in this suite. Only the selected files will be rendered. Template files that are put in a templates sub-folder can be addressed with a linux path separator. Also the templates/ can be omitted. Using wildcards it is possible to test multiple templates without listing them one-by-one. Partial templates (which are prefixed with and _ or have the .tpl extension) are added automatically even if it is in a templates sub-folder, you don't need to add them.

For example, the following suite used to test templates/redis-test/stateful_set.yamll and templates/deployment.yaml files.

suite: Test StatefulSet templates: - redis-test/stateful_set.yaml - deployment.yaml

Define the Release Object

You can use the release property to define the {{ .Release }} object. It is an optional property. There are four properties in release:

Release Name

name is an optional string. It defines the release name, default to "RELEASE-NAME".

For example, the following suite sets the release name to cnb.

suite: Test StatefulSet release: name: cnb

Namespace

namespace is an optional string, It means the namespace which release be installed to, default to "NAMESPACE".

For example, the following suite sets the release namespace to cnb.

suite: Test StatefulSet release: namespace: cnb

Revision

The revision of current build, default to 0. It is an optional integer.

💡 Although release.revision should be a natural number, declaring it as a negative value in test cases does not cause an error.

For example, the following suite sets the revision to 1.

suite: Test StatefulSet release: revision: 1

Upgrade

release.upgrade is an optional boolean. It means whether the build is an upgrade, default to false.

For example, the following suite is an upgrade deployment, not installation.

suite: Test StatefulSet release: upgrade: true

Define the Capabilities Object

There is an optional object property capabilities used to define the {{ .Capabilities }} object. It has 3 properties:

Major Version

capabilities.majorVersion is an optional integer. It represents the kubernetes major version (not helm), default to the major version which is set by helm.

The following code set to the major version of kubernetes is 1 (means v1.xxx):

suite: Test StatefulSet capabilities: majorVersion: 1

Minor Version

capabilities.minorVersion is an optional integer. It represents the kubernetes minor version (not helm), default to the major version which is set by helm.

The following code set to the minor version of kubernetes is 23 (means v1.23.0):

suite: Test StatefulSet capabilities: majorVersion: 1 minorVersion: 23

💡The scenario where version settings are explicitly defined is rare. One common example is when Helm code adapts its rendering logic based on the current Kubernetes version. For instance:

(The value of global.kube_version in values is "{{ .Capabilities.KubeVersion.Version }}")

apiVersion: v1 kind: ConfigMap metadata: name: environment-variables data: author: "{{ .Values.global.author }}" {{- $kube_version := tpl .Values.global.kube_version . }} kube_version: "{{ $kube_version }}" {{- if semverCompare ">=1.23.0" $kube_version }} support_grpc_in_probe: "true" {{- else }} support_grpc_in_probe: "false" {{- end }}

Based on this code, we can develop test case:

suite: test config map capabilities: majorVersion: 1 minorVersion: 25 templates: - config_map.yaml tests: - it: Kubernetes version asserts: - equal: path: data.kube_version value: "v1.25.0" - equal: path: data.support_grpc_in_probe value: "true"

API Version

Property apiVersions is an array of string, optional. A set of versions, default to the version set used by the defined kubernetes version. Defaults to the capabilities from system's Helm installation itself.

Define the Chart Object

There is an optional object property chart used to define the {{ .Chart }} object. It has 2 optional properties:

Chart Version

Using the property chart.version (string, optional) to set the semantic version of chart. Default to the version set in the Chart.yaml.

For instance, the following code set the chart version to 1.3.0 (although the actual version is 1.0.0):

suite: test config map chart: version: 1.3.0

Application Version

Property chart.appVersion (string, optional) means the app-version of the chart, default to the app-version set in the Chart.yaml.

For instance, the following code set the app-version to latest (although the actual app-version is 1.0.0).

suite: test config map chart: appVersion: latest

Skip This Suite

An optional property skip marks the test suite as having been skipped. Execution will continue at the next suite.

You must use the skip.reason property (string, required) to define the reason for skipping. (😅Otherwise, the skip will not take effect.)

The following code will skip during testing.

suite: Test ConfigMap Rendering templates: - templates/cm2.yaml release: namespace: default skip: reason: "WIP: Work In Process"

Post Renderer

postRenderer is an optional object. A helm post-renderer to apply after chart rendering but before validation.

📖 What is the Post Rendering ?

Post rendering gives chart installers the ability to manually manipulate, configure, and/or validate rendered manifests before they are installed by Helm. This allows users with advanced configuration needs to be able to use tools like kustomize or yq to apply configuration changes without the need to fork a public chart or requiring chart maintainers to specify every last configuration option for a piece of software. There are also use cases for injecting common tools and side cars in enterprise environments or analysis of the manifests before deployment.

A post renderer can be used with install, upgrade, and template. To use a post-renderer, use the --post-renderer flag with a path to the renderer executable you wish to use. For example:

helm install mychart stable/wordpress --post-renderer /path/to/executable

If the path does not contain any separators, it will search in $PATH, otherwise it will resolve any relative paths to a fully qualified path.

Notice: Need Helm 3.1+

For example, there is a description YAML for config map named templates/cm2.yaml:

apiVersion: v1 kind: ConfigMap metadata: name: my-config data: key: "value1"

The content of test file tests/cm2_test.yaml is:

suite: Test ConfigMap Rendering templates: - templates/cm2.yaml postRenderer: cmd: "yq" args: - "eval" - ".metadata.namespace=\"my-ns\"" tests: - it: should render ConfigMap when v1 is available asserts: - isKind: of: ConfigMap - equal: path: metadata.namespace value: my-ns

I did not define metadata.namespace in the templates/cm2.yaml file, but by using the postRenderer property with a yq command, I added metadata.namespace to the final rendered output with the value my-ns.

From the example above, we can see that postRenderer has two properties: cmd and args.

  • cmd: string, required. The full path to the command to invoke, or just its name if it's on $PATH.
  • args: array of strings. Command-line arguments to pass to the above cmd.

‼️Test Jobs

The test job is the base unit of testing. Your chart is rendered each time a test job run, and validated with assertions defined in the test. You can setup your values used to render the chart in the test job with external values files or directly in the test job definition.

The property tests represents the a list of test jobs. It is an object array. The tests property is required; omitting it will result in an error no tests found.

suite: Test ConfigMap templates: - templates/cm2.yaml tests: - job1 - job2 - ...

Test Name for Your Job

Define the name of the test with TDD style or any message you like for it property in tests array. It’s advisable to choose a meaningful name so that during maintenance, the main purpose of this test job is clearly evident.

For example, the following code defines the name "metadata info" for the first job (It sounds like we're testing whether the content under metadata meets expectations).

suite: Test ConfigMap templates: - templates/cm2.yaml tests: - it: metadata info ...

Inherited Properties

TODO: Specify additional values files

The values files used to renders the chart, think it as the -f, --values options of helm install. The file path should be the relative path from the test suite file itself. This file will override existing values set in the suite values.

For example:

suite: Test StatefulSet values: - values.yaml templates: - redis-test/stateful_set.yaml tests: - it: document values: - values2.yaml asserts: - hasDocuments: count: 1

Set The Values Directly In Job

Property set which in test job used to set the values directly in suite file. The key is the value path with the format just like --set option of helm install, for example image.pullPolicy. The value is anything you want to set to the path specified by the key, which can be even an array or an object. This set will override values which are already set in the values file.

If both the top-level set property and the set property of the test Job are specified, and they modify the same configuration, the setproperty in the Job takes precedence.

For example, the final value of the test.enable in the first test job is true.

suite: Test Redis Client set: test.enable: false test.resources.limits.cpu: 28 templates: - redis-test/stateful_set.yaml tests: - it: document set: test.enable: true