From ea681369b90bcda9978fc68c2c128abd25ac1f4d Mon Sep 17 00:00:00 2001 From: Atif Ali <56743004+aali309@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:31:27 -0400 Subject: [PATCH] test(unit): add template tests (#159) --- .github/workflows/unittest.yml | 41 ++ charts/cryostat/Chart.yaml | 2 +- charts/cryostat/TESTING.md | 148 ++++++ charts/cryostat/templates/deployment.yaml | 12 +- charts/cryostat/templates/pvc.yaml | 2 +- charts/cryostat/tests/alpha_config_test.yaml | 28 + .../tests/clusterrolebinding_test.yaml | 65 +++ charts/cryostat/tests/db_secret_test.yaml | 31 ++ charts/cryostat/tests/deployment_test.yaml | 499 ++++++++++++++++++ charts/cryostat/tests/ingress_test.yaml | 60 +++ charts/cryostat/tests/notes_test.yaml | 108 ++++ charts/cryostat/tests/pvc_test.yaml | 56 ++ charts/cryostat/tests/role_test.yaml | 141 +++++ charts/cryostat/tests/rolebinding_test.yaml | 124 +++++ charts/cryostat/tests/route_test.yaml | 74 +++ charts/cryostat/tests/service_test.yaml | 120 +++++ .../cryostat/tests/serviceaccount_test.yaml | 37 ++ .../tests/storage_access_secret_test.yaml | 20 + 18 files changed, 1560 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/unittest.yml create mode 100644 charts/cryostat/TESTING.md create mode 100644 charts/cryostat/tests/alpha_config_test.yaml create mode 100644 charts/cryostat/tests/clusterrolebinding_test.yaml create mode 100644 charts/cryostat/tests/db_secret_test.yaml create mode 100644 charts/cryostat/tests/deployment_test.yaml create mode 100644 charts/cryostat/tests/ingress_test.yaml create mode 100644 charts/cryostat/tests/notes_test.yaml create mode 100644 charts/cryostat/tests/pvc_test.yaml create mode 100644 charts/cryostat/tests/role_test.yaml create mode 100644 charts/cryostat/tests/rolebinding_test.yaml create mode 100644 charts/cryostat/tests/route_test.yaml create mode 100644 charts/cryostat/tests/service_test.yaml create mode 100644 charts/cryostat/tests/serviceaccount_test.yaml create mode 100644 charts/cryostat/tests/storage_access_secret_test.yaml diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml new file mode 100644 index 00000000..b89d990f --- /dev/null +++ b/.github/workflows/unittest.yml @@ -0,0 +1,41 @@ +name: Helm unit tests + +on: + push: + branches: + - main + - v[0-9]+ + - v[0-9]+.[0-9]+ + - cryostat-v[0-9]+.[0-9]+ + + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + - unlabeled + branches: + - main + - v[0-9]+ + - v[0-9]+.[0-9]+ + - cryostat-v[0-9]+.[0-9]+ + +jobs: + helm-unittests: + runs-on: ubuntu-latest + steps: + - name: fail if safe-to-test label NOT applied + if: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'safe-to-test') }} + run: exit 1 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.14.4 + - name: Install unit test plugin + run: helm plugin install https://github.com/helm-unittest/helm-unittest.git --version v0.5.1 + - name: Run Helm unit tests + run: helm unittest --debug ./charts/cryostat diff --git a/charts/cryostat/Chart.yaml b/charts/cryostat/Chart.yaml index 792c1131..479e7ca4 100644 --- a/charts/cryostat/Chart.yaml +++ b/charts/cryostat/Chart.yaml @@ -26,7 +26,7 @@ keywords: - diagnostic sources: -- https://github.com/cryostatio/cryostat3 +- https://github.com/cryostatio/cryostat - https://github.com/cryostatio/cryostat-core - https://github.com/cryostatio/cryostat-web - https://github.com/cryostatio/jfr-datasource diff --git a/charts/cryostat/TESTING.md b/charts/cryostat/TESTING.md new file mode 100644 index 00000000..ff9fb3be --- /dev/null +++ b/charts/cryostat/TESTING.md @@ -0,0 +1,148 @@ +# Testing Guide for Cryostat Helm Chart + +This guide outlines the conventions and practices for writing and executing tests in the Cryostat Helm chart project using the Helm Unittest plugin. + +## Overview + +Helm Unittest is a Helm plugin that allows to write declarative tests for Helm charts. It enables testing the rendered templates of a Helm chart with specified values without the need for any running Kubernetes cluster. + +# Testing Guide for Cryostat Helm Chart + +## Requirements + +Before running tests, you need to have the following tools installed: + +- **Helm:** Helm is a package manager for Kubernetes needed to manage the charts. + `Required version: >= v3.14.4` +- **Helm Unittest Plugin:** This plugin enables unit testing for Helm charts. + `Required version: >= v0.5.1` + +## Installation + +##### Installing Helm + +Helm can be installed on a variety of platforms. [Official Helm installation documentation](https://helm.sh/docs/intro/install/) provides detailed instructions. + +##### Installing Helm Unittest Plugin + +Once Helm is installed, you can install the Helm Unittest plugin. +First, verify whether the Helm Unittest plugin has been successfully installed, you can use the following command to list all installed Helm plugins: +```bash +helm plugin list +``` +This command will display a list of all plugins currently installed in your Helm environment, including the Helm Unittest plugin if it's already installed. Look for an entry named unittest in the output. If it's listed, then the Helm Unittest plugin is installed correctly. For example: +``` +❯ helm plugin list + +NAME VERSION DESCRIPTION +unittest 0.5.1 Unit test for helm chart in YAML with ease +to keep your chart functional and robust. +``` +If the Helm Unittest plugin is not listed, you can install it using the following command: +```bash +$ helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` +This will install the latest version of binary into helm plugin directory. + +## Writing Tests + +Each test is associated with a specific Helm template and is structured to validate specific aspects of that template. Here's a general structure for writing tests: + +1. **Test Suite:** A collection of tests related to a particular aspect of the chart, usually corresponding to a specific template file. +2. **Test Cases:** Each test case should focus on a single aspect or feature of the chart. Test cases can have different configurations set through the `set` directive to simulate different environments or scenarios. +3. **Assertions:** Test cases contain assertions that specify the expected output of the rendered templates. Assertions can check for the existence of objects, equality of values, matching patterns, and more. + +##### Naming Conventions for Test Files +The naming convention for test files typically mirrors the name of the template they are testing with a `_test` suffix. For example: + +- service.yaml ➔ service_test.yaml +- deployment.yaml ➔ deployment_test.yaml + +## Directory Structure + +Tests are organized under the `tests/` directory, with each test file corresponding to a template in the `templates/` directory: + +```plaintext +cryostat-helm/ +├── charts +│   └── cryostat +│   ├── Chart.yaml +│   ├── templates +│   │   ├── alpha_config.yaml +│   │   ├── ... +│   │   └── tests +│   │   ├── test-core-connection.yaml +│   │   └── ... +│   ├── TESTING.md +│   ├── tests +│   │   ├── alpha_config_test.yaml +│   │   ├── ... +│   │   ├── __snapshot__ +│   │   └── storage_access_secret_test.yaml +│   ├── values.schema.json +│   └── values.yaml + +``` +In addition, Cryostat Helm chart includes integration tests located in the `templates/tests` directory and are executed using `helm test`. These tests are different from unit tests in that they involve actual deployment of resources to a Kubernetes cluster to validate the integrated operation of those resources. + +## Test File Structure + +Here's an example of what a test file looks like: + +```yaml +suite: +templates: + - +tests: + - it: + set: + + asserts: + - : + path: + value: +``` +## Common Assertions +- `equal`: Checks if the actual value at path equals the expected value. +- `matchRegex`: Validates if the actual string matches the given regex pattern. +- `exists`: Checks if the specified path exists in the document. +- `notExists`: Ensures the specified path does not exist in the document. + +Visit [this document](https://github.com/helm-unittest/helm-unittest/blob/main/DOCUMENT.md#assertion-types) for more assertion types. +## Running Tests + +Once Unittest plugin has been installed, tests can be executed by running the following command: +```bash +$ helm unittest +``` +In the case of `cryostat-helm`, the command would be: + +```bash +$ helm unittest ./charts/cryostat +``` +To run test for a specific test file, use the `-f` flag with helm unittest to specify the test file to be executed. Here's the command format: + +```bash +$ helm unittest -f tests/.yaml ./charts/ +``` +This command will run the test for `service_test.yaml` file: + +```bash +$ helm unittest -f tests/service_test.yaml ./charts/cryostat +``` +## Additional Resources and Documentation + +For more infomation on Helm and writing tests for Helm charts, the following resources can be invaluable: + +### Helm Documentation + +- **Helm Official Documentation:** Provides comprehensive guides, tutorials, and reference material for working with Helm. + [Helm Documentation](https://helm.sh/docs/) + +- **Helm Chart Best Practices:** A guide by the Helm community outlining best practices for creating and managing Helm charts. + [Helm Chart Best Practices](https://helm.sh/docs/chart_best_practices/) + +### Helm Unittest Plugin + +- **Helm Unittest GitHub Repository:** Contains the source code, installation instructions, and detailed usage examples of the Helm Unittest plugin. + [Helm Unittest on GitHub](https://github.com/helm-unittest/helm-unittest) diff --git a/charts/cryostat/templates/deployment.yaml b/charts/cryostat/templates/deployment.yaml index 1307ebcf..a0c84150 100644 --- a/charts/cryostat/templates/deployment.yaml +++ b/charts/cryostat/templates/deployment.yaml @@ -56,7 +56,7 @@ spec: - name: QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION value: drop-and-create - name: QUARKUS_DATASOURCE_USERNAME - value: cryostat3 + value: cryostat - name: QUARKUS_DATASOURCE_PASSWORD valueFrom: secretKeyRef: @@ -64,7 +64,7 @@ spec: key: CONNECTION_KEY optional: false - name: QUARKUS_DATASOURCE_JDBC_URL - value: jdbc:postgresql://localhost:5432/cryostat3 + value: jdbc:postgresql://localhost:5432/cryostat - name: STORAGE_BUCKETS_ARCHIVES_NAME value: archivedrecordings - name: QUARKUS_S3_ENDPOINT_OVERRIDE @@ -126,7 +126,7 @@ spec: imagePullPolicy: {{ (.Values.db).image.pullPolicy }} env: - name: POSTGRESQL_USER - value: cryostat3 + value: cryostat - name: POSTGRESQL_PASSWORD valueFrom: secretKeyRef: @@ -134,7 +134,7 @@ spec: key: CONNECTION_KEY optional: false - name: POSTGRESQL_DATABASE - value: cryostat3 + value: cryostat - name: PG_ENCRYPT_KEY valueFrom: secretKeyRef: @@ -153,9 +153,9 @@ spec: command: - pg_isready - -U - - cryostat3 + - cryostat - -d - - cryostat3 + - cryostat - name: {{ printf "%s-%s" .Chart.Name "storage" }} securityContext: {{- toYaml (.Values.storage).securityContext | nindent 12 }} diff --git a/charts/cryostat/templates/pvc.yaml b/charts/cryostat/templates/pvc.yaml index 9e453623..84667be1 100644 --- a/charts/cryostat/templates/pvc.yaml +++ b/charts/cryostat/templates/pvc.yaml @@ -11,7 +11,7 @@ metadata: {{- end }} spec: {{- with .Values.pvc.accessModes }} - accessModes: + accessModes: {{- toYaml . | nindent 4 }} {{- end }} resources: diff --git a/charts/cryostat/tests/alpha_config_test.yaml b/charts/cryostat/tests/alpha_config_test.yaml new file mode 100644 index 00000000..cced5bcd --- /dev/null +++ b/charts/cryostat/tests/alpha_config_test.yaml @@ -0,0 +1,28 @@ +suite: test alpha_config.yaml +templates: + - templates/alpha_config.yaml + +tests: + - it: should contain server configuration in alpha_config.yaml + asserts: + - matchRegex: + path: data['alpha_config.yaml'] + pattern: "server:\\s*BindAddress: http://0.0.0.0:4180" + + - it: should contain upstream configurations in alpha_config.yaml + asserts: + - matchRegex: + path: data['alpha_config.yaml'] + pattern: "upstreamConfig:\\s*proxyRawPath: true\\s*upstreams:\\s*- id: cryostat\\s*path: /\\s*uri: http://localhost:8181" + - matchRegex: + path: data['alpha_config.yaml'] + pattern: "- id: grafana\\s*path: /grafana/\\s*uri: http://localhost:3000" + - matchRegex: + path: data['alpha_config.yaml'] + pattern: "- id: storage\\s*path: \\^/storage/\\(\\.\\*\\)\\$\\s*rewriteTarget: /\\$1\\s*uri: http://localhost:8333\\s*passHostHeader: false\\s*proxyWebSockets: false" + + - it: should contain provider configuration in alpha_config.yaml + asserts: + - matchRegex: + path: data['alpha_config.yaml'] + pattern: "providers:\\s*- id: dummy\\s*name: Unused - Sign In Below\\s*clientId: CLIENT_ID\\s*clientSecret: CLIENT_SECRET\\s*provider: google" diff --git a/charts/cryostat/tests/clusterrolebinding_test.yaml b/charts/cryostat/tests/clusterrolebinding_test.yaml new file mode 100644 index 00000000..0d867408 --- /dev/null +++ b/charts/cryostat/tests/clusterrolebinding_test.yaml @@ -0,0 +1,65 @@ +suite: test clusterrolebinding.yaml +templates: + - clusterrolebinding.yaml + +tests: + - it: should create a ClusterRoleBinding when RBAC and OpenShift authentication are enabled + set: + rbac.create: true + authentication.openshift.enabled: true + authentication.openshift.clusterRole.name: system:auth-delegator + asserts: + - hasDocuments: + count: 1 + - equal: + path: metadata.name + value: RELEASE-NAME-cryostat + - equal: + path: roleRef.apiGroup + value: rbac.authorization.k8s.io + - equal: + path: roleRef.kind + value: ClusterRole + - equal: + path: roleRef.name + value: system:auth-delegator + - equal: + path: subjects[0].kind + value: ServiceAccount + - equal: + path: subjects[0].name + value: RELEASE-NAME-cryostat + - equal: + path: subjects[0].namespace + value: NAMESPACE + + - it: should create a ClusterRoleBinding with a custom OpenShift cluster role + set: + rbac.create: true + authentication.openshift.enabled: true + authentication.openshift.clusterRole.name: custom-clusterrole + asserts: + - hasDocuments: + count: 1 + - equal: + path: roleRef.name + value: custom-clusterrole + + + - it: should not create a ClusterRoleBinding when RBAC is disabled + set: + rbac.create: false + authentication.openshift.enabled: true + authentication.openshift.clusterRole.name: system:auth-delegator + asserts: + - hasDocuments: + count: 0 + + - it: should not create a ClusterRoleBinding when OpenShift authentication is disabled + set: + rbac.create: true + authentication.openshift.enabled: false + authentication.openshift.clusterRole.name: system:auth-delegator + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/db_secret_test.yaml b/charts/cryostat/tests/db_secret_test.yaml new file mode 100644 index 00000000..3f3fbab9 --- /dev/null +++ b/charts/cryostat/tests/db_secret_test.yaml @@ -0,0 +1,31 @@ +suite: test db_secret.yaml +templates: + - db_secret.yaml + +tests: + - it: should create a database secret if core.databaseSecretName is not set + set: + core.databaseSecretName: "" + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Secret + - equal: + path: metadata.name + value: RELEASE-NAME-db + - equal: + path: type + value: Opaque + - exists: + path: data.ENCRYPTION_KEY + - exists: + path: data.CONNECTION_KEY + + - it: should not create a database secret if core.databaseSecretName is set + set: + core.databaseSecretName: "custom-db-secret" + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/deployment_test.yaml b/charts/cryostat/tests/deployment_test.yaml new file mode 100644 index 00000000..67971fe1 --- /dev/null +++ b/charts/cryostat/tests/deployment_test.yaml @@ -0,0 +1,499 @@ +suite: test deployment.yaml +templates: + - deployment.yaml + +tests: + - it: should verify general deployment settings + asserts: + - equal: + path: kind + value: Deployment + - equal: + path: metadata.name + value: RELEASE-NAME-cryostat + - equal: + path: spec.replicas + value: 1 + - equal: + path: spec.strategy.type + value: Recreate + - equal: + path: spec.selector.matchLabels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: cryostat + - equal: + path: spec.template.metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: cryostat + - equal: + path: spec.template.spec.serviceAccountName + value: RELEASE-NAME-cryostat + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + - equal: + path: metadata.labels + value: + helm.sh/chart: cryostat-2.0.0-dev + app.kubernetes.io/name: cryostat + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/version: "4.0.0-dev" + app.kubernetes.io/managed-by: Helm + + - it: should validate all container settings including environment variables and security contexts + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat')] + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].image + value: "quay.io/cryostat/cryostat:4.0.0-snapshot" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].image + value: "quay.io/oauth2-proxy/oauth2-proxy:latest" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_PORT')].value + value: "8181" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_HOST')].value + value: "localhost" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_PROXY_PROXY_ADDRESS_FORWARDING')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_PROXY_ALLOW_X_FORWARDED')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_PROXY_ENABLE_FORWARDED_HOST')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HTTP_PROXY_ENABLE_FORWARDED_PREFIX')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION')].value + value: "drop-and-create" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_DATASOURCE_USERNAME')].value + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_DATASOURCE_PASSWORD')].valueFrom.secretKeyRef + value: + key: "CONNECTION_KEY" + name: "RELEASE-NAME-db" + optional: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_DATASOURCE_JDBC_URL')].value + value: "jdbc:postgresql://localhost:5432/cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='STORAGE_BUCKETS_ARCHIVES_NAME')].value + value: "archivedrecordings" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_ENDPOINT_OVERRIDE')].value + value: "http://localhost:8333" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_PATH_STYLE_ACCESS')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_AWS_REGION')].value + value: "us-east-1" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_AWS_CREDENTIALS_TYPE')].value + value: "static" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_ACCESS_KEY_ID')].value + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='AWS_ACCESS_KEY_ID')].value + value: $(QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_ACCESS_KEY_ID) + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_SECRET_ACCESS_KEY')].valueFrom.secretKeyRef + value: + key: "SECRET_KEY" + name: "RELEASE-NAME-storage" + optional: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='AWS_SECRET_ACCESS_KEY')].value + value: $(QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_SECRET_ACCESS_KEY) + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='GRAFANA_DATASOURCE_URL')].value + value: "http://localhost:8800" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='GRAFANA_DASHBOARD_URL')].value + value: "http://localhost:3000" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='GRAFANA_DASHBOARD_EXT_URL')].value + value: "/grafana/" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='CRYOSTAT_DISCOVERY_KUBERNETES_ENABLED')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='CRYOSTAT_DISCOVERY_KUBERNETES_NAMESPACES')].value + value: "NAMESPACE" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='CRYOSTAT_DISCOVERY_KUBERNETES_PORT_NAMES')].value + value: "jfr-jmx" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='CRYOSTAT_DISCOVERY_KUBERNETES_PORT_NUMBERS')].value + value: "9091" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].ports[0].containerPort + value: 8181 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].ports[0].protocol + value: "TCP" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].livenessProbe.httpGet.path + value: "/health/liveness" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].livenessProbe.httpGet.port + value: 8181 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].startupProbe.httpGet.path + value: "/health/liveness" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].startupProbe.httpGet.port + value: 8181 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].startupProbe.failureThreshold + value: 18 + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat')].resources + + - it: should validate cryostat-db settings + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-db')] + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].securityContext.capabilities.drop + value: + - ALL + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].image + value: "quay.io/cryostat/cryostat-db:latest" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].env[?(@.name=='POSTGRESQL_USER')].value + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].env[?(@.name=='POSTGRESQL_PASSWORD')].valueFrom.secretKeyRef + value: + name: "RELEASE-NAME-db" + key: "CONNECTION_KEY" + optional: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].env[?(@.name=='POSTGRESQL_DATABASE')].value + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].env[?(@.name=='PG_ENCRYPT_KEY')].valueFrom.secretKeyRef + value: + name: "RELEASE-NAME-db" + key: "ENCRYPTION_KEY" + optional: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].ports[0].containerPort + value: 5432 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].ports[0].protocol + value: "TCP" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].volumeMounts[0].mountPath + value: "/var/lib/pgsql/data" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].volumeMounts[0].name + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].volumeMounts[0].subPath + value: "postgres" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].readinessProbe.exec.command + value: + - pg_isready + - -U + - cryostat + - -d + - cryostat + + - it: should validate cryostat-storage settings + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')] + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].securityContext.capabilities.drop + value: + - ALL + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].image + value: "quay.io/cryostat/cryostat-storage:latest" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].env[?(@.name=='CRYOSTAT_BUCKETS')].value + value: "archivedrecordings,archivedreports,eventtemplates,probes" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].env[?(@.name=='CRYOSTAT_ACCESS_KEY')].value + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].env[?(@.name=='CRYOSTAT_SECRET_KEY')].valueFrom.secretKeyRef + value: + name: "RELEASE-NAME-storage" + key: "SECRET_KEY" + optional: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].env[?(@.name=='DATA_DIR')].value + value: "/data" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].env[?(@.name=='IP_BIND')].value + value: 0.0.0.0 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].ports[0].containerPort + value: 8333 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].ports[0].protocol + value: "TCP" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].volumeMounts[0].mountPath + value: "/data" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].volumeMounts[0].name + value: "cryostat" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].volumeMounts[0].subPath + value: "seaweed" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].livenessProbe.httpGet.path + value: "/status" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].livenessProbe.httpGet.port + value: 8333 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].livenessProbe.periodSeconds + value: 10 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].livenessProbe.failureThreshold + value: 2 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].startupProbe.httpGet.path + value: "/status" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].startupProbe.httpGet.port + value: 8333 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].startupProbe.periodSeconds + value: 10 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].startupProbe.failureThreshold + value: 9 + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].resources + + - it: should validate cryostat-grafana settings + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')] + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].securityContext.capabilities.drop + value: + - ALL + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].image + value: "quay.io/cryostat/cryostat-grafana-dashboard:latest" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].env[?(@.name=='GF_AUTH_ANONYMOUS_ENABLED')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].env[?(@.name=='GF_SERVER_DOMAIN')].value + value: "localhost" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].env[?(@.name=='GF_SERVER_ROOT_URL')].value + value: "http://localhost:4180/grafana/" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].env[?(@.name=='GF_SERVER_SERVE_FROM_SUB_PATH')].value + value: "true" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].env[?(@.name=='JFR_DATASOURCE_URL')].value + value: "http://localhost:8800" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].ports[0].containerPort + value: 3000 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].ports[0].protocol + value: "TCP" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].livenessProbe.httpGet.path + value: "/api/health" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].livenessProbe.httpGet.port + value: 3000 + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].resources + + - it: should validate cryostat-jfr-datasource settings + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')] + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].securityContext.capabilities.drop + value: + - ALL + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].image + value: "quay.io/cryostat/jfr-datasource:latest" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].env[?(@.name=='LISTEN_HOST')].value + value: "localhost" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].env[?(@.name=='QUARKUS_HTTP_PORT')].value + value: "8800" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].ports[0].containerPort + value: 8800 + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].ports[0].protocol + value: "TCP" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].livenessProbe.exec.command + value: + - curl + - --fail + - http://localhost:8800 + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].resources + + - it: should validate volumes and volume mounts + asserts: + - exists: + path: spec.template.spec.volumes[?(@.name=='alpha-config')] + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].volumeMounts[?(@.mountPath=='/etc/oauth2_proxy/alpha_config')] + + - it: should set image pull secrets if specified + set: + imagePullSecrets: + - name: myregistrykey + asserts: + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: "myregistrykey" + + - it: should configure the OpenShift OAuth Proxy when authentication.openshift is enabled + set: + authentication.openshift.enabled: true + asserts: + - matchRegex: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].image + pattern: "quay.io/cryostat/openshift-oauth-proxy:.*" + + - it: should configure the OAuth2 Proxy when OpenShift OAuth is disabled and OAuth2 is enabled + set: + authentication.openshift.enabled: false + authentication.oauth2.enabled: true + asserts: + - exists: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')] + - matchRegex: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].image + pattern: "quay.io/oauth2-proxy/oauth2-proxy:.*" + + - it: should apply Kubernetes specific settings when configured + set: + nodeSelector: + disktype: ssd + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: disktype + operator: In + values: + - ssd + tolerations: + - key: "key" + operator: "Equal" + value: "value" + effect: "NoSchedule" + asserts: + - exists: + path: spec.template.spec.nodeSelector + - exists: + path: spec.template.spec.affinity + - exists: + path: spec.template.spec.tolerations + + - it: should verify image pull policies for development snapshots + set: + core.image.tag: "4.0.0-snapshot" + asserts: + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].imagePullPolicy + value: Always + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].imagePullPolicy + value: Always + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].imagePullPolicy + value: Always + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].imagePullPolicy + value: "Always" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].imagePullPolicy + value: "Always" + + - it: should verify image pull policies for release versions + set: + core.image.tag: "4.1.0" + core.image.pullPolicy: "IfNotPresent" + oauth2Proxy.image.pullPolicy: "IfNotPresent" + storage.image.pullPolicy: "IfNotPresent" + grafana.image.pullPolicy: "IfNotPresent" + db.image.pullPolicy: "IfNotPresent" + datasource.image.pullPolicy: "IfNotPresent" + asserts: + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat')].imagePullPolicy + value: "IfNotPresent" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-authproxy')].imagePullPolicy + value: "IfNotPresent" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-storage')].imagePullPolicy + value: "IfNotPresent" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-grafana')].imagePullPolicy + value: "IfNotPresent" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-db')].imagePullPolicy + value: "IfNotPresent" + - equal: + path: spec.template.spec.containers[?(@.name=='cryostat-jfr-datasource')].imagePullPolicy + value: "IfNotPresent" + diff --git a/charts/cryostat/tests/ingress_test.yaml b/charts/cryostat/tests/ingress_test.yaml new file mode 100644 index 00000000..f822dd15 --- /dev/null +++ b/charts/cryostat/tests/ingress_test.yaml @@ -0,0 +1,60 @@ +suite: test ingress.yaml +templates: + - ingress.yaml + +tests: + - it: should create an Ingress with default settings + set: + core.ingress.enabled: true + core.service.httpPort: 8080 + core: + ingress: + className: nginx + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + hosts: + - host: example.com + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - example.com + secretName: example-tls + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Ingress + - matchRegex: + path: metadata.name + pattern: "RELEASE-NAME-cryostat" + - equal: + path: metadata.annotations['nginx.ingress.kubernetes.io/rewrite-target'] + value: "/" + - equal: + path: spec.rules[0].host + value: "example.com" + - equal: + path: spec.rules[0].http.paths[0].path + value: "/" + - equal: + path: spec.rules[0].http.paths[0].backend.service.name + value: "RELEASE-NAME-cryostat" + - equal: + path: spec.rules[0].http.paths[0].backend.service.port.number + value: 8080 + - equal: + path: spec.ingressClassName + value: "nginx" + - equal: + path: spec.tls[0].secretName + value: "example-tls" + + - it: should not create an Ingress when ingress is disabled + set: + core.ingress.enabled: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/notes_test.yaml b/charts/cryostat/tests/notes_test.yaml new file mode 100644 index 00000000..533a37bf --- /dev/null +++ b/charts/cryostat/tests/notes_test.yaml @@ -0,0 +1,108 @@ +suite: test NOTES.txt +templates: + - NOTES.txt + +tests: + - it: should render correct notes for enabled ingress + set: + core.ingress.enabled: true + core: + ingress: + className: nginx + hosts: + - host: example.com + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - example.com + secretName: example-tls + asserts: + - equalRaw: + value: | + + + 1. Visit the Cryostat application at: + ``` + https://example.com/ + ``` + + - it: should render notes for enabled route without TLS + set: + core.route.enabled: true + core.route.tls.enabled: false + asserts: + - equalRaw: + value: | + + 1. Tell Cryostat how to serve external traffic: + ``` + No actions required with this configuration. + ``` + + 2. Visit the Cryostat application at: + ``` + echo http://$(oc get route -n NAMESPACE RELEASE-NAME-cryostat -o jsonpath="{.status.ingress[0].host}") + ``` + + - it: should render notes for enabled route with TLS + set: + core.route.enabled: true + core.route.tls.enabled: true + asserts: + - equalRaw: + value: | + + 1. Tell Cryostat how to serve external traffic: + ``` + No actions required with this configuration. + ``` + + 2. Visit the Cryostat application at: + ``` + echo https://$(oc get route -n NAMESPACE RELEASE-NAME-cryostat -o jsonpath="{.status.ingress[0].host}") + ``` + + - it: should render notes for NodePort service without ingress or route + set: + core.service.type: "NodePort" + core.ingress.enabled: false + core.route.enabled: false + asserts: + - equalRaw: + value: | + + 1. Tell Cryostat how to serve external traffic: + ``` + export NODE_IP=$(kubectl get nodes -n NAMESPACE -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get -n NAMESPACE -o jsonpath="{.spec.ports[0].nodePort}" services RELEASE-NAME-cryostat) + kubectl -n NAMESPACE set env deploy --containers=cryostat RELEASE-NAME-cryostat QUARKUS_HTTP_HOST=$NODE_IP + ``` + + 2. Visit the Cryostat application at: + ``` + echo http://$NODE_IP:$NODE_PORT + ``` + + - it: should render notes for LoadBalancer service without ingress or route + set: + core.service.type: "LoadBalancer" + core.ingress.enabled: false + core.route.enabled: false + asserts: + - equalRaw: + value: | + + 1. Tell Cryostat how to serve external traffic: + ``` + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get -n NAMESPACE -w svc/RELEASE-NAME-cryostat' + export SERVICE_IP=$(kubectl get svc -n NAMESPACE RELEASE-NAME-cryostat --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") + kubectl -n NAMESPACE set env deploy --containers=cryostat RELEASE-NAME-cryostat QUARKUS_HTTP_HOST=$SERVICE_IP + ``` + + 2. Visit the Cryostat application at: + ``` + echo http://$SERVICE_IP:8181 + ``` diff --git a/charts/cryostat/tests/pvc_test.yaml b/charts/cryostat/tests/pvc_test.yaml new file mode 100644 index 00000000..6484d50b --- /dev/null +++ b/charts/cryostat/tests/pvc_test.yaml @@ -0,0 +1,56 @@ +suite: test pvc.yaml +templates: + - pvc.yaml + +tests: + - it: should create a PersistentVolumeClaim with correct settings + set: + pvc: + enabled: true + storage: "10Gi" + accessModes: + - "ReadWriteOnce" + storageClassName: "standard" + annotations: + "volume.beta.kubernetes.io/storage-class": "standard" + selector: + matchLabels: + app: cryostat + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: PersistentVolumeClaim + - equal: + path: metadata.name + value: "RELEASE-NAME-cryostat" + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + - equal: + path: spec.accessModes + value: + - "ReadWriteOnce" + - equal: + path: spec.resources.requests.storage + value: "10Gi" + - equal: + path: spec.storageClassName + value: "standard" + - equal: + path: spec.selector.matchLabels.app + value: "cryostat" + + - it: should not create a PersistentVolumeClaim when PVC is disabled + set: + pvc: + enabled: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/role_test.yaml b/charts/cryostat/tests/role_test.yaml new file mode 100644 index 00000000..75723b13 --- /dev/null +++ b/charts/cryostat/tests/role_test.yaml @@ -0,0 +1,141 @@ +suite: test role.yaml +templates: + - role.yaml + +tests: + - it: should create Roles in target namespace + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.namespaces: + - "default" + - "test-ns" + asserts: + - hasDocuments: + count: 2 + - equal: + path: kind + value: Role + - equal: + path: metadata.namespace + value: "default" + documentIndex: 0 + - equal: + path: metadata.namespace + value: "test-ns" + documentIndex: 1 + - matchRegex: + path: metadata.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 0 + - matchRegex: + path: metadata.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 1 + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + documentIndex: 0 + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + documentIndex: 1 + + - it: should have correct permissions for endpoints, pods, and other resources + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.namespaces: + - "default" + asserts: + - equal: + path: rules[0].apiGroups + value: [""] + - equal: + path: rules[0].resources + value: ["endpoints"] + - equal: + path: rules[0].verbs + value: ["get", "list", "watch"] + - equal: + path: rules[1].apiGroups + value: [""] + - equal: + path: rules[1].resources + value: ["pods", "replicationcontrollers"] + - equal: + path: rules[1].verbs + value: ["get"] + - equal: + path: rules[2].apiGroups + value: ["apps"] + - equal: + path: rules[2].resources + value: ["replicasets", "deployments", "daemonsets", "statefulsets"] + - equal: + path: rules[2].verbs + value: ["get"] + - equal: + path: rules[3].apiGroups + value: ["apps.openshift.io"] + - equal: + path: rules[3].resources + value: ["deploymentconfigs"] + - equal: + path: rules[3].verbs + value: ["get"] + - equal: + path: rules[4].apiGroups + value: ["route.openshift.io"] + - equal: + path: rules[4].verbs + value: ["get", "list"] + - equal: + path: rules[4].resources + value: ["routes"] + + - it: should not create any Role if RBAC is disabled + set: + rbac.create: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create any Roles when Kubernetes discovery is disabled + set: + rbac.create: true + core.discovery.kubernetes.enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should not specify a namespace if installNamespaceDisabled is true + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.installNamespaceDisabled: true + asserts: + - hasDocuments: + count: 0 + + - it: should specify the default namespace if installNamespaceDisabled is false + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.installNamespaceDisabled: false + asserts: + - hasDocuments: + count: 1 + - equal: + path: metadata.namespace + value: "NAMESPACE" diff --git a/charts/cryostat/tests/rolebinding_test.yaml b/charts/cryostat/tests/rolebinding_test.yaml new file mode 100644 index 00000000..05d36845 --- /dev/null +++ b/charts/cryostat/tests/rolebinding_test.yaml @@ -0,0 +1,124 @@ +suite: test rolebinding.yaml +templates: + - rolebinding.yaml + +tests: + - it: should create a RoleBinding in the default namespace + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.namespaces: + - "default" + - "test-ns" + asserts: + - hasDocuments: + count: 2 + - equal: + path: kind + value: RoleBinding + documentIndex: 0 + - equal: + path: kind + value: RoleBinding + documentIndex: 1 + - equal: + path: metadata.namespace + value: "default" + documentIndex: 0 + - equal: + path: metadata.namespace + value: "test-ns" + documentIndex: 1 + - matchRegex: + path: metadata.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 0 + - matchRegex: + path: metadata.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 1 + - equal: + path: roleRef.apiGroup + value: "rbac.authorization.k8s.io" + documentIndex: 0 + - equal: + path: roleRef.apiGroup + value: "rbac.authorization.k8s.io" + documentIndex: 1 + - equal: + path: roleRef.kind + value: "Role" + documentIndex: 0 + - equal: + path: roleRef.kind + value: "Role" + documentIndex: 1 + - matchRegex: + path: roleRef.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 0 + - matchRegex: + path: roleRef.name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 1 + - equal: + path: subjects[0].kind + value: "ServiceAccount" + documentIndex: 0 + - equal: + path: subjects[0].kind + value: "ServiceAccount" + documentIndex: 1 + - matchRegex: + path: subjects[0].name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 0 + - matchRegex: + path: subjects[0].name + pattern: "RELEASE-NAME-cryostat" + documentIndex: 1 + - equal: + path: subjects[0].namespace + value: "NAMESPACE" + documentIndex: 0 + - equal: + path: subjects[0].namespace + value: "NAMESPACE" + documentIndex: 1 + + - it: should not create any RoleBinding if RBAC is disabled + set: + rbac.create: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create any RoleBinding when Kubernetes discovery is disabled + set: + rbac.create: true + core.discovery.kubernetes.enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create any RoleBinding if installNamespaceDisabled is true + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.installNamespaceDisabled: true + asserts: + - hasDocuments: + count: 0 + + - it: should create a RoleBinding in the default namespace if installNamespaceDisabled is false + set: + rbac.create: true + core.discovery.kubernetes.enabled: true + core.discovery.kubernetes.namespaces: [] + core.discovery.kubernetes.installNamespaceDisabled: false + asserts: + - hasDocuments: + count: 1 + - equal: + path: metadata.namespace + value: "NAMESPACE" diff --git a/charts/cryostat/tests/route_test.yaml b/charts/cryostat/tests/route_test.yaml new file mode 100644 index 00000000..b29cabb7 --- /dev/null +++ b/charts/cryostat/tests/route_test.yaml @@ -0,0 +1,74 @@ +suite: test route.yaml +templates: + - route.yaml + +tests: + - it: should create a Route when routing is enabled + set: + core.route.enabled: true + core: + route: + annotations: + hello: world + tls: + enabled: true + termination: edge + insecureEdgeTerminationPolicy: Redirect + key: "RSA PRIVATE KEY" + destinationCACertificate: "DESTINATION CA" + caCertificate: "CA CERT" + certificate: "CERT" + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Route + - equal: + path: metadata.name + value: "RELEASE-NAME-cryostat" + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + - equal: + path: metadata.annotations.hello + value: "world" + - equal: + path: spec.to.kind + value: "Service" + - equal: + path: spec.to.name + value: "RELEASE-NAME-cryostat" + - equal: + path: spec.port.targetPort + value: 4180 + - equal: + path: spec.tls.termination + value: "edge" + - equal: + path: spec.tls.insecureEdgeTerminationPolicy + value: "Redirect" + - matchRegex: + path: spec.tls.key + pattern: ".*RSA PRIVATE KEY.*" + - matchRegex: + path: spec.tls.destinationCACertificate + pattern: ".*DESTINATION CA.*" + - matchRegex: + path: spec.tls.caCertificate + pattern: ".*CA CERT.*" + - matchRegex: + path: spec.tls.certificate + pattern: ".*CERT.*" + + - it: should not create a Route when routing is disabled + set: + core.route.enabled: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/service_test.yaml b/charts/cryostat/tests/service_test.yaml new file mode 100644 index 00000000..5fa3dd0e --- /dev/null +++ b/charts/cryostat/tests/service_test.yaml @@ -0,0 +1,120 @@ +suite: test service.yaml +templates: + - service.yaml + +tests: + - it: should create a Service with the correct settings + set: + core.service.type: ClusterIP + core.service.httpPort: 8080 + authentication.openshift.enabled: false + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Service + - equal: + path: metadata.name + value: RELEASE-NAME-cryostat + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.ports[0].port + value: 8080 + - equal: + path: spec.ports[0].targetPort + value: 4180 + - equal: + path: spec.ports[0].protocol + value: TCP + - equal: + path: spec.ports[0].name + value: cryostat-http + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + + - it: should create a Service with the correct settings when OpenShift authentication is enabled + set: + authentication.openshift.enabled: true + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Service + - equal: + path: metadata.name + value: RELEASE-NAME-cryostat + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.ports[0].port + value: 8181 + - equal: + path: spec.ports[0].targetPort + value: 4180 + - equal: + path: spec.ports[0].protocol + value: TCP + - equal: + path: spec.ports[0].name + value: cryostat-http + - equal: + path: spec.ports[1].port + value: 443 + - equal: + path: spec.ports[1].targetPort + value: 8443 + - equal: + path: spec.ports[1].protocol + value: TCP + - equal: + path: spec.ports[1].name + value: cryostat-https + - equal: + path: spec.selector + value: + app.kubernetes.io/name: cryostat + app.kubernetes.io/instance: RELEASE-NAME + - equal: + path: metadata.labels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: cryostat + app.kubernetes.io/version: "4.0.0-dev" + helm.sh/chart: cryostat-2.0.0-dev + - equal: + path: metadata.annotations + value: + service.alpha.openshift.io/serving-cert-secret-name: RELEASE-NAME-proxy-tls + + + - it: should include OpenShift specific annotations when OpenShift auth is enabled + set: + authentication.openshift.enabled: true + asserts: + - exists: + path: metadata.annotations + - equal: + path: metadata.annotations + value: + service.alpha.openshift.io/serving-cert-secret-name: RELEASE-NAME-proxy-tls + + - it: should not include OpenShift specific annotations when OpenShift auth is disabled + set: + authentication.openshift.enabled: false + asserts: + - notExists: + path: metadata.annotations.`service.alpha.openshift.io/serving-cert-secret-name` + + diff --git a/charts/cryostat/tests/serviceaccount_test.yaml b/charts/cryostat/tests/serviceaccount_test.yaml new file mode 100644 index 00000000..211aa9b3 --- /dev/null +++ b/charts/cryostat/tests/serviceaccount_test.yaml @@ -0,0 +1,37 @@ +suite: test serviceaccount.yaml +templates: + - serviceaccount.yaml + +tests: + - it: should create a ServiceAccount with OpenShift redirect annotations when OpenShift auth is enabled + set: + authentication.openshift.enabled: true + serviceAccount.create: true + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: ServiceAccount + - equal: + path: metadata.name + value: "RELEASE-NAME-cryostat" + - equal: + path: metadata.annotations + value: + serviceaccounts.openshift.io/oauth-redirectreference.primary: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"RELEASE-NAME-cryostat"}}' + + - it: should not include OpenShift specific annotations when OpenShift auth is disabled + set: + authentication.openshift.enabled: false + serviceAccount.create: true + asserts: + - notExists: + path: metadata.annotations + + - it: should not create a ServiceAccount when serviceAccount.create is disabled + set: + serviceAccount.create: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/cryostat/tests/storage_access_secret_test.yaml b/charts/cryostat/tests/storage_access_secret_test.yaml new file mode 100644 index 00000000..f5e0ab7b --- /dev/null +++ b/charts/cryostat/tests/storage_access_secret_test.yaml @@ -0,0 +1,20 @@ +suite: test storage_access_secret.yaml +templates: + - storage_access_secret.yaml + +tests: + - it: should create a Storage Access Secret with correct settings + asserts: + - hasDocuments: + count: 1 + - equal: + path: kind + value: Secret + - equal: + path: metadata.name + value: RELEASE-NAME-storage + - equal: + path: type + value: Opaque + - exists: + path: data.SECRET_KEY