Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
ebeaty-cisco committed Mar 27, 2024
1 parent e3d9c17 commit 0d60cab
Show file tree
Hide file tree
Showing 10 changed files with 1,693 additions and 0 deletions.
23 changes: 23 additions & 0 deletions tests/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM bats/bats:1.9.0

WORKDIR /charts

RUN echo "@community https://dl-cdn.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories

RUN apk update && \
apk upgrade && \
apk add curl docker helm@community yamllint yq

RUN curl -LO "https://github.com/kubernetes-sigs/kind/releases/download/v0.20.0/kind-linux-amd64"
RUN curl -L "https://github.com/kubernetes-sigs/kind/releases/download/v0.20.0/kind-linux-amd64.sha256sum" | sha256sum -c
RUN mv kind-linux-amd64 /usr/local/bin/kind && chmod +x /usr/local/bin/kind

RUN curl -LO "https://github.com/yannh/kubeconform/releases/download/v0.6.4/kubeconform-linux-amd64.tar.gz"
RUN echo "2b4ebeaa4d5ac4843cf8f7b7e66a8874252b6b71bc7cbfc4ef1cbf85acec7c07 kubeconform-linux-amd64.tar.gz" | sha256sum -c
RUN tar -xz -C /usr/local/bin -f kubeconform-linux-amd64.tar.gz kubeconform && rm kubeconform-linux-amd64.tar.gz

RUN curl -LO "https://dl.k8s.io/release/v1.29.1/bin/linux/amd64/kubectl"
RUN echo "$(curl -L https://dl.k8s.io/release/v1.29.1/bin/linux/amd64/kubectl.sha256) kubectl" | sha256sum -c
RUN mv kubectl /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl

ENTRYPOINT ["bash"]
24 changes: 24 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# XRd Helm chart tests

## Prerequisites

The following dependencies are required for unit tests:

- [Bats](https://github.com/bats-core/bats-core)
- [Bats support](https://github.com/bats-core/bats-support)
- [Bats assert](https://github.com/bats-core/bats-assert)
- [Helm](https://helm.sh)
- [yq](https://github.com/mikefarah/yq)
- [yamllint](https://github.com/adrienverge/yamllint)
- [kubeconform](https://github.com/yannh/kubeconform)

## Running the tests in a container

A [Dockerfile](Dockerfile) is provided which defines a container image which includes all test dependencies.

The unit tests can be run using any container manager. For example, using Docker:

```
docker build . -t helm-tests
docker run -v "$PWD/..:/charts" helm-tests bats tests/ut
```
3 changes: 3 additions & 0 deletions tests/ut/setup_suite.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setup_suite () {
bats_require_minimum_version 1.5.0
}
74 changes: 74 additions & 0 deletions tests/ut/utils.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
bats_load_library "bats-assert/load.bash"
bats_load_library "bats-support/load.bash"

cp_chart_dir () {
readlink -f "${BATS_TEST_DIRNAME}/../../../charts/xrd-control-plane"
}
vrouter_chart_dir () {
readlink -f "${BATS_TEST_DIRNAME}/../../../charts/xrd-vrouter"
}
common_chart_dir () {
readlink -f "${BATS_TEST_DIRNAME}/../../../charts/xrd-common"
}

template () {
echo -n "# Run 'helm template'"
[ "$#" -eq 0 ] && echo "" || echo " with arguments: $*"

run -0 helm template . \
--set image.repository=local \
--set image.tag=latest \
-s "$TEMPLATE_UNDER_TEST" \
"$@"

# shellcheck disable=SC2154
echo "$output"

echo "# Assert output passes yamllint"
echo "$output" | yamllint -d '{extends: default, rules: {indentation: {indent-sequences: false}, line-length: disable}}' -

echo "# Assert output passes Kubeconform"
echo "$output" | kubeconform -strict -schema-location default -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/v0.0.12/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
}

template_failure () {
template_failure_no_set \
--set image.repository=local \
--set image.tag=latest \
"$@"
}

template_failure_no_set () {
echo -n "# Run 'helm template'"
[ "$#" -eq 0 ] && echo "" || echo " with arguments: $*"
echo "# (Expecting failure)"

run helm template . \
-s "$TEMPLATE_UNDER_TEST" \
"$@"

[ "$status" -eq 1 ]

# shellcheck disable=SC2154
echo "$output"
}

assert_query () {
assert "$(echo "$output" | yq -e "$1")" "$2"
}

assert_query_equal () {
assert_equal "$(echo "$output" | yq -e "$1")" "$2"
}

assert_fields_equal () {
assert_equal "$(echo "$output" | yq -e "$1")" "$(echo "$output" | yq -e "$2")"
}

assert_multiline_query_equal () {
assert_equal "$(echo "$output" | yq -e "$1")" "$(echo -e "$2")"
}

assert_error_message_contains () {
assert_output --partial "$1"
}
95 changes: 95 additions & 0 deletions tests/ut/xrd-control-plane/cp_configmap.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bats

load "utils.bash"

export TEMPLATE_UNDER_TEST="templates/config-configmap.yaml"

setup_file () {
cd "$(cp_chart_dir)" || exit
helm dependency update .
}

@test "Control Plane ConfigMap: No ConfigMap is generated if no config is set" {
template_failure
assert_error_message_contains "could not find template templates/config-configmap.yaml in chart"
}

@test "Control Plane ConfigMap: Name consists of the release name and the template name" {
template --set 'config.script=foo'
assert_query_equal '.metadata.name' "release-name-xrd-control-plane-config"
}

@test "Control Plane ConfigMap: Name can be overridden with fullnameOverride" {
template --set 'fullnameOverride=xrd-test' --set 'config.script=foo'
assert_query_equal '.metadata.name' "xrd-test-config"
}

@test "Control Plane ConfigMap: Name can be overridden with nameOverride" {
template --set 'nameOverride=xrd-test' --set 'config.script=foo'
assert_query_equal '.metadata.name' "release-name-xrd-test-config"
}

@test "Control Plane ConfigMap: Namespace is default" {
template --set 'config.script=foo'
assert_query_equal '.metadata.namespace' "default"
}

@test "Control Plane ConfigMap: No annotations are set by default" {
template --set 'config.script=foo'
assert_query '.metadata.annotations | not'
}

@test "Control Plane ConfigMap: Global annotations and commonAnnotations can be added and are merged with expected precedence" {
template \
--set 'global.annotations.foo=bar' \
--set 'commonAnnotations.baz=baa' \
--set 'commonAnnotations.foo=qux' \
--set 'config.script=foo'
assert_query_equal '.metadata.annotations.foo' "qux"
assert_query_equal '.metadata.annotations.baz' "baa"
}

@test "Control Plane ConfigMap: Recommended labels are set" {
template --set 'config.script=foo'
assert_query_equal '.metadata.labels."app.kubernetes.io/name"' "xrd-control-plane"
assert_query_equal '.metadata.labels."app.kubernetes.io/instance"' "release-name"
assert_query_equal '.metadata.labels."app.kubernetes.io/managed-by"' "Helm"
assert_query '.metadata.labels | has("app.kubernetes.io/version")'
assert_query '.metadata.labels | has("helm.sh/chart")'
}

@test "Control Plane ConfigMap: Global labels and commonLabels can be added and are correctly merged" {
template \
--set 'global.labels.foo=bar' \
--set 'commonLabels.baz=baa' \
--set 'config.script=foo'
assert_query_equal '.metadata.labels.foo' "bar"
assert_query_equal '.metadata.labels.baz' "baa"
}

@test "Control Plane ConfigMap: Startup config can be set using username and password" {
template --set 'config.username=foo' --set 'config.password=bar'
assert_multiline_query_equal '.data."startup.cfg"' \
"username foo\n group root-lr\n group cisco-support\n password bar\n!"
}

@test "Control Plane ConfigMap: Startup config can be set using ascii" {
template --set 'config.ascii=foo'
assert_query_equal '.data."startup.cfg"' "foo"
}

@test "Control Plane ConfigMap: Startup script can be set" {
template --set 'config.script=foo'
assert_query_equal '.data."startup.sh"' "foo"
}

@test "Control Plane ConfigMap: ztpIni can't be set without being enabled" {
template_failure --set 'config.ztpIni=foo'
assert_error_message_contains "ztpIni can only be specified if ztpEnable is set to true"
}

@test "Control Plane ConfigMap: ztpIni can be set if it is enabled" {
template --set 'config.ztpIni=foo' --set 'config.ztpEnable=true'
assert_query_equal '.data."ztp.ini"' "foo"
}

123 changes: 123 additions & 0 deletions tests/ut/xrd-control-plane/cp_network-attachments.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env bats

load "utils.bash"

export TEMPLATE_UNDER_TEST="templates/network-attachments.yaml"

setup_file () {
cd "$(cp_chart_dir)" || exit
helm dependency update .
}

@test "Control Plane NetworkAttachmentDefinition: Name consists of the release name, template name and index" {
template --set-json 'interfaces=[{"type": "multus"}]'
assert_query_equal '.metadata.name' "release-name-xrd-control-plane-0"
}

@test "Control Plane NetworkAttachmentDefinition: Name can be overridden with fullnameOverride" {
template --set-json 'interfaces=[{"type": "multus"}]' --set 'fullnameOverride=xrd-test'
assert_query_equal '.metadata.name' "xrd-test-0"
}

@test "Control Plane NetworkAttachmentDefinition: Name can be overridden with nameOverride" {
template --set-json 'interfaces=[{"type": "multus"}]' --set 'nameOverride=xrd-test'
assert_query_equal '.metadata.name' "release-name-xrd-test-0"
}

@test "Control Plane NetworkAttachmentDefinition: Names have correct index when more than one interface requested" {
template \
--set-json 'interfaces=[{"type": "multus"}, {"type": "multus"}]' \
--set-json 'mgmtInterfaces=[{"type": "multus"}]'
assert_multiline_query_equal '.metadata.name' \
"release-name-xrd-control-plane-0\n---\nrelease-name-xrd-control-plane-1\n---\nrelease-name-xrd-control-plane-2"
}

@test "Control Plane NetworkAttachmentDefinition: Namespace is default" {
template --set-json 'interfaces=[{"type": "multus"}]'
assert_query_equal '.metadata.namespace' "default"
}

@test "Control Plane NetworkAttachmentDefinition: No annotations are set by default" {
template --set-json 'interfaces=[{"type": "multus"}]'
assert_query '.metadata.annotations | not'
}

@test "Control Plane NetworkAttachmentDefinition: Global annotations and commonAnnotations can be added and are correctly merged" {
template \
--set-json 'interfaces=[{"type": "multus"}]' \
--set 'global.annotations.foo=bar' \
--set 'commonAnnotations.baz=baa'
assert_query_equal '.metadata.annotations.foo' "bar"
assert_query_equal '.metadata.annotations.baz' "baa"
}

@test "Control Plane NetworkAttachmentDefinition: Recommended labels are set" {
template --set-json 'interfaces=[{"type": "multus"}]'
assert_query_equal '.metadata.labels."app.kubernetes.io/name"' "xrd-control-plane"
assert_query_equal '.metadata.labels."app.kubernetes.io/instance"' "release-name"
assert_query_equal '.metadata.labels."app.kubernetes.io/managed-by"' "Helm"
assert_query '.metadata.labels | has("app.kubernetes.io/version")'
assert_query '.metadata.labels | has("helm.sh/chart")'
}

@test "Control Plane NetworkAttachmentDefinition: Global labels and commonLabels can be added and are correctly merged" {
template \
--set-json 'interfaces=[{"type": "multus"}]' \
--set 'global.labels.foo=bar' \
--set 'commonLabels.baz=baa'
assert_query_equal '.metadata.labels.foo' "bar"
assert_query_equal '.metadata.labels.baz' "baa"
}

@test "Control Plane NetworkAttachmentDefinition: Check default config" {
template --set-json 'interfaces=[{"type": "multus"}]'
assert_multiline_query_equal '.spec.config' \
"{\n \"cniVersion\": \"0.3.1\",\n \"plugins\": [\n null\n ]\n}"
}

@test "Control Plane NetworkAttachmentDefinition: Config can be set for MGMT interfaces" {
template --set-json 'mgmtInterfaces=[{"type": "multus", "config": {"foo": "bar"}}]'
assert_multiline_query_equal '.spec.config'\
"{\n \"cniVersion\": \"0.3.1\",\n \"plugins\": [\n {\n \"foo\": \"bar\"\n }\n ]\n}"
}

@test "Control Plane NetworkAttachmentDefinition: Config can be set for interfaces" {
template --set-json 'interfaces=[{"type": "multus", "config": {"foo": "bar"}}]'
assert_multiline_query_equal '.spec.config' \
"{\n \"cniVersion\": \"0.3.1\",\n \"plugins\": [\n {\n \"foo\": \"bar\"\n }\n ]\n}"
}

@test "Control Plane NetworkAttachmentDefinition: No interfaces" {
template_failure
}

@test "Control Plane NetworkAttachmentDefinition: No custom resource created for defaultCNI" {
template_failure --set-json 'interfaces=[{"type": "defaultCni"}]'
}

@test "Control Plane NetworkAttachmentDefinition: error if multiple defaultCNI requested" {
template_failure \
--set-json 'interfaces=[{"type": "defaultCni"}]' \
--set-json 'mgmtInterfaces=[{"type": "defaultCni"}]'
assert_error_message_contains "At most one defaultCni interface can be specified across both interfaces and mgmtInterfaces"
}

@test "Control Plane NetworkAttachmentDefinition: error if unknown interface type is requested" {
template_failure --set-json 'interfaces=[{"type": "foo"}]'
assert_error_message_contains "must be one of the following: \"defaultCni\", \"multus\""
}

@test "Control Plane NetworkAttachmentDefinition: error if PCI interface type is requested" {
template_failure --set-json 'interfaces=[{"type": "pci"}]'
assert_error_message_contains "must be one of the following: \"defaultCni\", \"multus\""
}

@test "Control Plane NetworkAttachmentDefinition: error if unknown mgmt interface type is requested" {
template_failure --set-json 'mgmtInterfaces=[{"type": "foo"}]'
assert_error_message_contains "must be one of the following: \"defaultCni\", \"multus\""
}

@test "Control Plane NetworkAttachmentDefinition: error if PCI mgmt interface type is requested" {
template_failure --set-json 'mgmtInterfaces=[{"type": "pci"}]'
assert_error_message_contains "must be one of the following: \"defaultCni\", \"multus\""
}
Loading

0 comments on commit 0d60cab

Please sign in to comment.