From b198f14cd88b6ec07080fe6ef353abb570b17467 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 11:42:54 -0800 Subject: [PATCH 1/7] New tests --- .helmignore | 9 + braintrust/README.md | 18 ++ braintrust/TESTING.md | 173 +++++++++++++ braintrust/ci/values-aws.yaml | 103 ++++++++ braintrust/ci/values-azure.yaml | 127 +++++++++ braintrust/ci/values-google.yaml | 105 ++++++++ braintrust/ci/values-minimal.yaml | 91 +++++++ braintrust/tests/__fixtures__/aws-values.yaml | 17 ++ .../tests/__fixtures__/azure-values.yaml | 43 ++++ .../tests/__fixtures__/base-values.yaml | 122 +++++++++ .../tests/__fixtures__/google-values.yaml | 16 ++ braintrust/tests/api-configmap_test.yaml | 184 +++++++++++++ braintrust/tests/api-deployment_test.yaml | 241 ++++++++++++++++++ braintrust/tests/api-service_test.yaml | 119 +++++++++ braintrust/tests/api-serviceaccount_test.yaml | 103 ++++++++ .../brainstore-reader-configmap_test.yaml | 184 +++++++++++++ .../tests/brainstore-reader-service_test.yaml | 107 ++++++++ braintrust/tests/brainstore-reader_test.yaml | 205 +++++++++++++++ .../tests/brainstore-serviceaccount_test.yaml | 116 +++++++++ .../brainstore-writer-configmap_test.yaml | 184 +++++++++++++ .../tests/brainstore-writer-service_test.yaml | 107 ++++++++ braintrust/tests/brainstore-writer_test.yaml | 205 +++++++++++++++ braintrust/tests/namespace_test.yaml | 70 +++++ .../tests/secretproviderclass_test.yaml | 150 +++++++++++ braintrust/tests/storageclass_test.yaml | 52 ++++ braintrust/values.yaml | 2 +- test.sh | 132 ++++++++++ 27 files changed, 2984 insertions(+), 1 deletion(-) create mode 100644 .helmignore create mode 100644 braintrust/TESTING.md create mode 100644 braintrust/ci/values-aws.yaml create mode 100644 braintrust/ci/values-azure.yaml create mode 100644 braintrust/ci/values-google.yaml create mode 100644 braintrust/ci/values-minimal.yaml create mode 100644 braintrust/tests/__fixtures__/aws-values.yaml create mode 100644 braintrust/tests/__fixtures__/azure-values.yaml create mode 100644 braintrust/tests/__fixtures__/base-values.yaml create mode 100644 braintrust/tests/__fixtures__/google-values.yaml create mode 100644 braintrust/tests/api-configmap_test.yaml create mode 100644 braintrust/tests/api-deployment_test.yaml create mode 100644 braintrust/tests/api-service_test.yaml create mode 100644 braintrust/tests/api-serviceaccount_test.yaml create mode 100644 braintrust/tests/brainstore-reader-configmap_test.yaml create mode 100644 braintrust/tests/brainstore-reader-service_test.yaml create mode 100644 braintrust/tests/brainstore-reader_test.yaml create mode 100644 braintrust/tests/brainstore-serviceaccount_test.yaml create mode 100644 braintrust/tests/brainstore-writer-configmap_test.yaml create mode 100644 braintrust/tests/brainstore-writer-service_test.yaml create mode 100644 braintrust/tests/brainstore-writer_test.yaml create mode 100644 braintrust/tests/namespace_test.yaml create mode 100644 braintrust/tests/secretproviderclass_test.yaml create mode 100644 braintrust/tests/storageclass_test.yaml create mode 100755 test.sh diff --git a/.helmignore b/.helmignore new file mode 100644 index 0000000..0b279cd --- /dev/null +++ b/.helmignore @@ -0,0 +1,9 @@ +# Patterns to ignore when building packages. +.git +.github +.gitignore +README.md +LICENSE +docs/ +*.md +!braintrust/README.md diff --git a/braintrust/README.md b/braintrust/README.md index da4bbb6..56474c4 100644 --- a/braintrust/README.md +++ b/braintrust/README.md @@ -147,6 +147,24 @@ For Standard mode clusters, create node pools with local SSDs, then deploy: - Local SSDs are automatically available via emptyDir volumes - Pod anti-affinity ensures readers and writers don't share nodes (each pod gets dedicated node access) +## Testing + +This Helm chart includes comprehensive automated tests. See [TESTING.md](TESTING.md) for detailed information on: + +- Running tests locally +- Understanding test structure +- Adding new tests +- CI integration + +Quick start: + +```bash +# Run all tests +./test.sh + +# Run only unit tests +helm unittest braintrust +``` ## Breaking Changes diff --git a/braintrust/TESTING.md b/braintrust/TESTING.md new file mode 100644 index 0000000..d6f873c --- /dev/null +++ b/braintrust/TESTING.md @@ -0,0 +1,173 @@ +# Testing the Braintrust Helm Chart + +This document describes how to test the Braintrust Helm chart locally and in CI. + +## Prerequisites + +### Install helm-unittest + +`helm-unittest` is a Helm plugin for unit testing templates. Install it with: + +```bash +helm plugin install https://github.com/quintush/helm-unittest +``` + +Verify installation: +```bash +helm unittest --version +``` + +### Install Chart Testing (ct) + +`ct` is a tool for linting and testing Helm charts. Install it with: + +**macOS:** +```bash +brew install chart-testing +``` + +**Linux:** +```bash +# Download the latest release +wget https://github.com/helm/chart-testing/releases/latest/download/ct_linux_amd64.tar.gz +tar -xzf ct_linux_amd64.tar.gz +sudo mv ct /usr/local/bin/ +``` + +**Verify installation:** +```bash +ct version +``` + +## Running Tests Locally + +### Run All Tests + +Use the provided test script to run all tests: + +```bash +./test.sh +``` + +This will: +1. Run helm-unittest on all unit test files +2. Run Chart Testing (lint, validate, test) + +### Run Unit Tests Only + +Run only the unit tests (fast, no cluster needed): + +```bash +helm unittest braintrust +``` + +Run unit tests for a specific file: + +```bash +helm unittest braintrust/tests/storageclass_test.yaml +``` + +### Run Chart Testing Only + +Run linting and validation: + +```bash +ct lint --charts braintrust +``` + +Run with specific values files: + +```bash +ct lint --charts braintrust --validate-maintainers=false +``` + +## Test Structure + +### Unit Tests + +Unit tests are located in `braintrust/tests/` and use the `helm-unittest` format. Each test file corresponds to a template file and tests: + +- Template rendering with different values +- Conditional logic (cloud provider, feature flags) +- Helper functions +- Value merging and defaults + +### Integration Tests + +Integration tests use Chart Testing and validate: + +- YAML syntax correctness +- Kubernetes schema validation +- Chart linting (best practices) +- Rendering with different values files + +Test values files are in `braintrust/ci/`: +- `values-azure.yaml` - Azure-specific configuration +- `values-google.yaml` - Google Cloud-specific configuration +- `values-aws.yaml` - AWS-specific configuration +- `values-minimal.yaml` - Minimal required values + +## Adding New Tests + +### Adding Unit Tests + +1. Create a test file in `braintrust/tests/` matching the template name (e.g., `my-template_test.yaml`) +2. Write test cases using the helm-unittest syntax +3. Run tests: `helm unittest braintrust` + +Example test structure: +```yaml +suite: test my template +templates: + - my-template.yaml +tests: + - it: should render correctly + values: + myValue: "test" + asserts: + - matchRegex: + path: metadata.name + pattern: ^my-resource +``` + +### Adding Integration Test Values + +1. Create a new values file in `braintrust/ci/` (e.g., `values-custom.yaml`) +2. The file will be automatically picked up by Chart Testing +3. Ensure it includes all required values to render the chart + +## CI Integration + +Tests run automatically in GitHub Actions on: +- Every pull request +- Every push to main/master branches + +The CI workflow: +1. Installs helm-unittest and ct +2. Runs all unit tests +3. Runs Chart Testing (lint, validate) +4. Tests with multiple values files + +## Troubleshooting + +### Unit Tests Fail + +- Check that your test values match the template expectations +- Verify template paths in assertions are correct +- Use `helm template` to manually render and inspect output + +### Chart Testing Fails + +- Ensure all required values are provided in test values files +- Check for YAML syntax errors +- Verify Kubernetes API versions are correct + +### Local Validation + +You can also use the existing `validate.sh` script for manual validation against a Kubernetes cluster: + +```bash +./validate.sh +``` + +This requires a running Kubernetes cluster and kubectl access. diff --git a/braintrust/ci/values-aws.yaml b/braintrust/ci/values-aws.yaml new file mode 100644 index 0000000..6dc4d7b --- /dev/null +++ b/braintrust/ci/values-aws.yaml @@ -0,0 +1,103 @@ +# Test values for AWS deployment +global: + orgName: "test-org" + createNamespace: false + namespace: "braintrust" + labels: {} + namespaceAnnotations: {} + controlPlaneTelemetry: "status,metrics,usage" + +cloud: "aws" + +objectStorage: + aws: + brainstoreBucket: "test-brainstore-bucket" + responseBucket: "test-response-bucket" + codeBundleBucket: "test-code-bundle-bucket" + +api: + name: "braintrust-api" + replicas: 1 + image: + repository: "public.ecr.aws/braintrust/standalone-api" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + service: + type: ClusterIP + port: 8000 + serviceAccount: + name: "braintrust-api" + awsRoleArn: "arn:aws:iam::123456789012:role/test-role" + resources: + requests: + cpu: "2" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + allowCodeFunctionExecution: true + backfillDisableHistorical: false + backfillDisableNonhistorical: false + allowInvalidBase64: false + nodeMemoryPercent: "80" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +brainstore: + serviceAccount: + name: "brainstore" + awsRoleArn: "arn:aws:iam::123456789012:role/test-role" + annotations: {} + image: + repository: "public.ecr.aws/braintrust/brainstore" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + locksBackend: "redis" + reader: + name: "brainstore-reader" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "4" + memory: "8Gi" + limits: + cpu: "8" + memory: "16Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "100Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + writer: + name: "brainstore-writer" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "8" + memory: "16Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "200Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/braintrust/ci/values-azure.yaml b/braintrust/ci/values-azure.yaml new file mode 100644 index 0000000..3a0d622 --- /dev/null +++ b/braintrust/ci/values-azure.yaml @@ -0,0 +1,127 @@ +# Test values for Azure deployment +global: + orgName: "test-org" + createNamespace: false + namespace: "braintrust" + labels: {} + namespaceAnnotations: {} + controlPlaneTelemetry: "status,metrics,usage" + +cloud: "azure" + +azure: + tenantId: "test-tenant-id" + enableAzureContainerStorageDriver: true + enableAzureKeyVaultDriver: true + keyVaultCSIclientID: "test-client-id" + keyVaultName: "test-keyvault" + +objectStorage: + azure: + storageAccountName: "teststorageaccount" + brainstoreContainer: "brainstore" + responseContainer: "responses" + codeBundleContainer: "code-bundles" + +api: + name: "braintrust-api" + replicas: 1 + image: + repository: "public.ecr.aws/braintrust/standalone-api" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + service: + type: ClusterIP + port: 8000 + serviceAccount: + name: "braintrust-api" + resources: + requests: + cpu: "2" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + allowCodeFunctionExecution: true + backfillDisableHistorical: false + backfillDisableNonhistorical: false + allowInvalidBase64: false + nodeMemoryPercent: "80" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +brainstore: + serviceAccount: + name: "brainstore" + annotations: {} + image: + repository: "public.ecr.aws/braintrust/brainstore" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + locksBackend: "redis" + reader: + name: "brainstore-reader" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "4" + memory: "8Gi" + limits: + cpu: "8" + memory: "16Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "100Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + writer: + name: "brainstore-writer" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "8" + memory: "16Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "200Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +azureKeyVaultDriver: + secrets: + - keyVaultSecretName: "redis-connection-string" + keyVaultSecretType: "secret" + kubernetesSecretKey: "REDIS_URL" + - keyVaultSecretName: "postgres-connection-string" + kubernetesSecretKey: "PG_URL" + keyVaultSecretType: "secret" + - keyVaultSecretName: "brainstore-license-key" + keyVaultSecretType: "secret" + kubernetesSecretKey: "BRAINSTORE_LICENSE_KEY" + - keyVaultSecretName: "function-secret-key" + keyVaultSecretType: "secret" + kubernetesSecretKey: "FUNCTION_SECRET_KEY" + - keyVaultSecretName: "azure-storage-connection-string" + keyVaultSecretType: "secret" + kubernetesSecretKey: "AZURE_STORAGE_CONNECTION_STRING" diff --git a/braintrust/ci/values-google.yaml b/braintrust/ci/values-google.yaml new file mode 100644 index 0000000..23f5b83 --- /dev/null +++ b/braintrust/ci/values-google.yaml @@ -0,0 +1,105 @@ +# Test values for Google Cloud deployment +global: + orgName: "test-org" + createNamespace: false + namespace: "braintrust" + labels: {} + namespaceAnnotations: {} + controlPlaneTelemetry: "status,metrics,usage" + +cloud: "google" + +google: + mode: "autopilot" + autopilotMachineFamily: "c4" + +objectStorage: + google: + brainstoreBucket: "test-brainstore-bucket" + apiBucket: "test-api-bucket" + +api: + name: "braintrust-api" + replicas: 1 + image: + repository: "public.ecr.aws/braintrust/standalone-api" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + service: + type: ClusterIP + port: 8000 + serviceAccount: + name: "braintrust-api" + resources: + requests: + cpu: "2" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + allowCodeFunctionExecution: true + backfillDisableHistorical: false + backfillDisableNonhistorical: false + allowInvalidBase64: false + nodeMemoryPercent: "80" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +brainstore: + serviceAccount: + name: "brainstore" + googleServiceAccount: "test@project.iam.gserviceaccount.com" + annotations: {} + image: + repository: "public.ecr.aws/braintrust/brainstore" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + locksBackend: "redis" + reader: + name: "brainstore-reader" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "4" + memory: "8Gi" + limits: + cpu: "8" + memory: "16Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "100Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + writer: + name: "brainstore-writer" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "8" + memory: "16Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "200Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/braintrust/ci/values-minimal.yaml b/braintrust/ci/values-minimal.yaml new file mode 100644 index 0000000..f765e52 --- /dev/null +++ b/braintrust/ci/values-minimal.yaml @@ -0,0 +1,91 @@ +# Minimal test values - just enough to render the chart +global: + orgName: "test-org" + createNamespace: false + namespace: "braintrust" + labels: {} + namespaceAnnotations: {} + controlPlaneTelemetry: "status,metrics" + +cloud: "" + +api: + name: "braintrust-api" + replicas: 1 + image: + repository: "public.ecr.aws/braintrust/standalone-api" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + service: + type: ClusterIP + port: 8000 + serviceAccount: + name: "braintrust-api" + resources: + requests: + cpu: "2" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + allowCodeFunctionExecution: true + backfillDisableHistorical: false + backfillDisableNonhistorical: false + allowInvalidBase64: false + nodeMemoryPercent: "80" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +brainstore: + serviceAccount: + name: "brainstore" + annotations: {} + image: + repository: "public.ecr.aws/braintrust/brainstore" + tag: "v1.1.28" + pullPolicy: "IfNotPresent" + locksBackend: "redis" + reader: + name: "brainstore-reader" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "4" + memory: "8Gi" + limits: + cpu: "8" + memory: "16Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + writer: + name: "brainstore-writer" + replicas: 1 + service: + type: ClusterIP + port: 4000 + resources: + requests: + cpu: "8" + memory: "16Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/braintrust/tests/__fixtures__/aws-values.yaml b/braintrust/tests/__fixtures__/aws-values.yaml new file mode 100644 index 0000000..5853e4a --- /dev/null +++ b/braintrust/tests/__fixtures__/aws-values.yaml @@ -0,0 +1,17 @@ +# AWS-specific test values +# Extends base-values.yaml with AWS configuration +cloud: "aws" + +objectStorage: + aws: + brainstoreBucket: "test-brainstore-bucket" + responseBucket: "test-response-bucket" + codeBundleBucket: "test-code-bundle-bucket" + +api: + serviceAccount: + awsRoleArn: "arn:aws:iam::123456789012:role/test-api-role" + +brainstore: + serviceAccount: + awsRoleArn: "arn:aws:iam::123456789012:role/test-brainstore-role" diff --git a/braintrust/tests/__fixtures__/azure-values.yaml b/braintrust/tests/__fixtures__/azure-values.yaml new file mode 100644 index 0000000..3f94dc2 --- /dev/null +++ b/braintrust/tests/__fixtures__/azure-values.yaml @@ -0,0 +1,43 @@ +# Azure-specific test values +# Extends base-values.yaml with Azure configuration +cloud: "azure" + +azure: + tenantId: "test-tenant-id" + enableAzureContainerStorageDriver: true + enableAzureKeyVaultDriver: true + keyVaultCSIclientID: "test-client-id" + keyVaultName: "test-keyvault" + +objectStorage: + azure: + storageAccountName: "teststorageaccount" + brainstoreContainer: "brainstore" + responseContainer: "responses" + codeBundleContainer: "code-bundles" + +api: + serviceAccount: + azureClientId: "test-api-client-id" + +brainstore: + serviceAccount: + azureClientId: "test-brainstore-client-id" + +azureKeyVaultDriver: + secrets: + - keyVaultSecretName: "redis-connection-string" + keyVaultSecretType: "secret" + kubernetesSecretKey: "REDIS_URL" + - keyVaultSecretName: "postgres-connection-string" + kubernetesSecretKey: "PG_URL" + keyVaultSecretType: "secret" + - keyVaultSecretName: "brainstore-license-key" + keyVaultSecretType: "secret" + kubernetesSecretKey: "BRAINSTORE_LICENSE_KEY" + - keyVaultSecretName: "function-secret-key" + keyVaultSecretType: "secret" + kubernetesSecretKey: "FUNCTION_SECRET_KEY" + - keyVaultSecretName: "azure-storage-connection-string" + keyVaultSecretType: "secret" + kubernetesSecretKey: "AZURE_STORAGE_CONNECTION_STRING" diff --git a/braintrust/tests/__fixtures__/base-values.yaml b/braintrust/tests/__fixtures__/base-values.yaml new file mode 100644 index 0000000..b485e11 --- /dev/null +++ b/braintrust/tests/__fixtures__/base-values.yaml @@ -0,0 +1,122 @@ +# Base test values - minimal required values (cloud-agnostic) +# Use this as a base for all tests and override specific values as needed +global: + orgName: "test-org" + createNamespace: false + namespace: "braintrust" + labels: {} + namespaceAnnotations: {} + controlPlaneTelemetry: "status,metrics" + +cloud: "" + +api: + name: "braintrust-api" + labels: {} + annotations: + configmap: {} + deployment: {} + service: {} + pod: {} + serviceaccount: {} + replicas: 1 + image: + repository: "test/api" + tag: "v1.0.0" + pullPolicy: "IfNotPresent" + service: + name: "" + type: ClusterIP + port: 8000 + portName: http + serviceAccount: + name: "braintrust-api" + resources: + requests: + cpu: "2" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + allowCodeFunctionExecution: true + backfillDisableHistorical: false + backfillDisableNonhistorical: false + allowInvalidBase64: false + nodeMemoryPercent: "80" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + +brainstore: + labels: {} + serviceAccount: + name: "brainstore" + annotations: {} + image: + repository: "test/brainstore" + tag: "v1.0.0" + pullPolicy: "IfNotPresent" + locksBackend: "redis" + reader: + name: "brainstore-reader" + labels: {} + annotations: + configmap: {} + deployment: {} + service: {} + pod: {} + replicas: 1 + service: + name: "" + type: ClusterIP + port: 4000 + portName: http + resources: + requests: + cpu: "4" + memory: "8Gi" + limits: + cpu: "8" + memory: "16Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "100Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + writer: + name: "brainstore-writer" + labels: {} + annotations: + configmap: {} + deployment: {} + service: {} + pod: {} + replicas: 1 + service: + name: "" + type: ClusterIP + port: 4000 + portName: http + resources: + requests: + cpu: "8" + memory: "16Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "50Gi" + verbose: true + volume: + size: "200Gi" + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/braintrust/tests/__fixtures__/google-values.yaml b/braintrust/tests/__fixtures__/google-values.yaml new file mode 100644 index 0000000..8655dd0 --- /dev/null +++ b/braintrust/tests/__fixtures__/google-values.yaml @@ -0,0 +1,16 @@ +# Google Cloud-specific test values +# Extends base-values.yaml with GCP configuration +cloud: "google" + +google: + mode: "autopilot" + autopilotMachineFamily: "c4" + +objectStorage: + google: + brainstoreBucket: "test-brainstore-bucket" + apiBucket: "test-api-bucket" + +brainstore: + serviceAccount: + googleServiceAccount: "test@project.iam.gserviceaccount.com" diff --git a/braintrust/tests/api-configmap_test.yaml b/braintrust/tests/api-configmap_test.yaml new file mode 100644 index 0000000..5d206bd --- /dev/null +++ b/braintrust/tests/api-configmap_test.yaml @@ -0,0 +1,184 @@ +suite: test API configmap template +templates: + - api-configmap.yaml +tests: + - it: should render API configmap with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: braintrust-api + - equal: + path: data.ORG_NAME + value: "test-org" + - equal: + path: data.BRAINSTORE_ENABLED + value: "true" + - equal: + path: data.BRAINSTORE_DEFAULT + value: "force" + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should configure AWS buckets when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.RESPONSE_BUCKET + value: "test-response-bucket" + - equal: + path: data.CODE_BUNDLE_BUCKET + value: "test-code-bundle-bucket" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_BUCKET + value: "test-brainstore-bucket" + + - it: should configure Azure storage when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AZURE_STORAGE_ACCOUNT_NAME + value: "teststorageaccount" + - equal: + path: data.RESPONSE_BUCKET + value: "responses" + - equal: + path: data.CODE_BUNDLE_BUCKET + value: "code-bundles" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_BUCKET + value: "brainstore" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_BUCKET_PREFIX + value: "brainstore/wal" + + - it: should configure Google Cloud buckets when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.RESPONSE_BUCKET + value: "test-api-bucket" + - equal: + path: data.RESPONSE_BUCKET_PREFIX + value: "response/" + - equal: + path: data.CODE_BUNDLE_BUCKET + value: "test-api-bucket" + - equal: + path: data.CODE_BUNDLE_BUCKET_PREFIX + value: "code-bundle/" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_BUCKET + value: "test-brainstore-bucket" + - equal: + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" + + - it: should configure brainstore URLs correctly + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_URL + value: "http://brainstore-reader.braintrust:4000" + - equal: + path: data.BRAINSTORE_WRITER_URL + value: "http://brainstore-writer.braintrust:4000" + + - it: should include control plane telemetry + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.CONTROL_PLANE_TELEMETRY + value: "status,metrics" + + - it: should merge global and api labels + values: + - __fixtures__/base-values.yaml + set: + api.labels.component: "api" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: api + + - it: should include configmap annotations when provided + values: + - __fixtures__/base-values.yaml + set: + api.annotations.configmap: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value + + - it: should configure backfill settings + values: + - __fixtures__/base-values.yaml + set: + api.backfillDisableHistorical: true + api.backfillDisableNonhistorical: true + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_BACKFILL_DISABLE_HISTORICAL + value: "true" + - equal: + path: data.BRAINSTORE_BACKFILL_DISABLE_NONHISTORICAL + value: "true" diff --git a/braintrust/tests/api-deployment_test.yaml b/braintrust/tests/api-deployment_test.yaml new file mode 100644 index 0000000..f495cd0 --- /dev/null +++ b/braintrust/tests/api-deployment_test.yaml @@ -0,0 +1,241 @@ +suite: test API deployment template +templates: + - api-deployment.yaml +tests: + - it: should render API deployment with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: braintrust-api + - equal: + path: spec.replicas + value: 1 + - equal: + path: spec.template.spec.containers[0].image + value: test/api:v1.0.0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should include azure workload identity label when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.metadata.labels["azure.workload.identity/use"] + value: "true" + + - it: should include Azure storage connection string env var when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: AZURE_STORAGE_CONNECTION_STRING + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: AZURE_STORAGE_CONNECTION_STRING + + - it: should include GCS env vars when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: GCS_ACCESS_KEY_ID + - contains: + path: spec.template.spec.containers[0].env + content: + name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: GCS_SECRET_ACCESS_KEY + + - it: should include Azure Key Vault volume when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: secrets-store-inline + mountPath: "/mnt/secrets-store" + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: test-keyvault + + - it: should not include Azure Key Vault volume when disabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + azure.enableAzureKeyVaultDriver: false + release: + namespace: "braintrust" + asserts: + - isNull: + path: spec.template.spec.volumes + + - it: should include extraEnvVars when provided + values: + - __fixtures__/base-values.yaml + set: + api.extraEnvVars: + - name: CUSTOM_VAR + value: "custom-value" + - name: ANOTHER_VAR + value: "another-value" + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: CUSTOM_VAR + value: "custom-value" + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANOTHER_VAR + value: "another-value" + + - it: should merge global and api labels + values: + - __fixtures__/base-values.yaml + set: + api.labels.component: "api" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: api + + - it: should include livenessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + api.livenessProbe: + httpGet: + path: / + port: 8000 + initialDelaySeconds: 30 + periodSeconds: 10 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.path + value: / + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.port + value: 8000 + - equal: + path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds + value: 30 + - equal: + path: spec.template.spec.containers[0].livenessProbe.periodSeconds + value: 10 + + - it: should include readinessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + api.readinessProbe: + httpGet: + path: /status + port: 8001 + initialDelaySeconds: 10 + periodSeconds: 5 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.path + value: /status + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.port + value: 8001 + - equal: + path: spec.template.spec.containers[0].readinessProbe.initialDelaySeconds + value: 10 + - equal: + path: spec.template.spec.containers[0].readinessProbe.periodSeconds + value: 5 + + - it: should not include probes when explicitly disabled + values: + - __fixtures__/base-values.yaml + set: + api.livenessProbe: null + api.readinessProbe: null + release: + namespace: "braintrust" + asserts: + - isNull: + path: spec.template.spec.containers[0].livenessProbe + - isNull: + path: spec.template.spec.containers[0].readinessProbe diff --git a/braintrust/tests/api-service_test.yaml b/braintrust/tests/api-service_test.yaml new file mode 100644 index 0000000..1a76bb7 --- /dev/null +++ b/braintrust/tests/api-service_test.yaml @@ -0,0 +1,119 @@ +suite: test API service template +templates: + - api-service.yaml +tests: + - it: should render API service with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Service + - equal: + path: metadata.name + value: braintrust-api + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.selector.app + value: braintrust-api + + - it: should use custom service name when provided + values: + - __fixtures__/base-values.yaml + set: + api.service.name: "custom-api-service" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.name + value: custom-api-service + + - it: should configure port correctly + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.ports[0].name + value: http + - equal: + path: spec.ports[0].port + value: 8000 + - equal: + path: spec.ports[0].targetPort + value: 8000 + - equal: + path: spec.ports[0].protocol + value: TCP + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should merge global and api labels + values: + - __fixtures__/base-values.yaml + set: + api.labels.component: "api" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: api + + - it: should include service annotations when provided + values: + - __fixtures__/base-values.yaml + set: + api.annotations.service: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value + + - it: should support LoadBalancer type + values: + - __fixtures__/base-values.yaml + set: + api.service.type: "LoadBalancer" + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.type + value: LoadBalancer diff --git a/braintrust/tests/api-serviceaccount_test.yaml b/braintrust/tests/api-serviceaccount_test.yaml new file mode 100644 index 0000000..296b2a9 --- /dev/null +++ b/braintrust/tests/api-serviceaccount_test.yaml @@ -0,0 +1,103 @@ +suite: test API serviceaccount template +templates: + - api-serviceaccount.yaml +tests: + - it: should render API serviceaccount with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: braintrust-api + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should include AWS IAM role annotation when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["eks.amazonaws.com/role-arn"] + value: arn:aws:iam::123456789012:role/test-api-role + + - it: should include Azure workload identity annotation when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["azure.workload.identity/client-id"] + value: test-api-client-id + + - it: should not include cloud-specific annotations when cloud is empty + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isNull: + path: metadata.annotations["eks.amazonaws.com/role-arn"] + - isNull: + path: metadata.annotations["azure.workload.identity/client-id"] + + - it: should merge global and api labels + values: + - __fixtures__/base-values.yaml + set: + api.labels.component: "api" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: api + + - it: should include custom serviceaccount annotations when provided + values: + - __fixtures__/base-values.yaml + set: + api.annotations.serviceaccount: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-reader-configmap_test.yaml b/braintrust/tests/brainstore-reader-configmap_test.yaml new file mode 100644 index 0000000..7626c76 --- /dev/null +++ b/braintrust/tests/brainstore-reader-configmap_test.yaml @@ -0,0 +1,184 @@ +suite: test Brainstore Reader configmap template +templates: + - brainstore-reader-configmap.yaml +tests: + - it: should render Brainstore Reader configmap with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: brainstore-reader + - equal: + path: data.BRAINSTORE_READER_ONLY_MODE + value: "true" + - equal: + path: data.BRAINSTORE_PORT + value: "4000" + - equal: + path: data.BRAINSTORE_CACHE_DIR + value: "/mnt/tmp/brainstore" + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should configure verbose mode + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.verbose: true + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_VERBOSE + value: "1" + + - it: should configure AWS URIs when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "s3://test-brainstore-bucket/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "s3://test-brainstore-bucket/brainstore/wal" + + - it: should configure Azure URIs when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AZURE_STORAGE_ACCOUNT_NAME + value: "teststorageaccount" + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "az://brainstore/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "az://brainstore/brainstore/wal" + + - it: should configure Google Cloud URIs when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "gs://test-brainstore-bucket/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "gs://test-brainstore-bucket/brainstore/wal" + + - it: should include locks URI when locksBackend is objectStorage for AWS + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "s3://test-brainstore-bucket/brainstore/locks" + + - it: should include locks URI when locksBackend is objectStorage for Azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "az://brainstore/brainstore/locks" + + - it: should include locks URI when locksBackend is objectStorage for Google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "gs://test-brainstore-bucket/brainstore/locks" + + - it: should not include locks URI when locksBackend is redis + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + set: + brainstore.locksBackend: "redis" + release: + namespace: "braintrust" + asserts: + - isNull: + path: data.BRAINSTORE_LOCKS_URI + + - it: should include control plane telemetry + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_CONTROL_PLANE_TELEMETRY + value: "status,metrics" + + - it: should merge global and reader labels + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.labels.component: "brainstore-reader" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: brainstore-reader + + - it: should include configmap annotations when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.annotations.configmap: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-reader-service_test.yaml b/braintrust/tests/brainstore-reader-service_test.yaml new file mode 100644 index 0000000..0b3e683 --- /dev/null +++ b/braintrust/tests/brainstore-reader-service_test.yaml @@ -0,0 +1,107 @@ +suite: test Brainstore Reader service template +templates: + - brainstore-reader-service.yaml +tests: + - it: should render Brainstore Reader service with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Service + - equal: + path: metadata.name + value: brainstore-reader + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.selector.app + value: brainstore-reader + + - it: should use custom service name when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.service.name: "custom-reader-service" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.name + value: custom-reader-service + + - it: should configure port correctly + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.ports[0].name + value: http + - equal: + path: spec.ports[0].port + value: 4000 + - equal: + path: spec.ports[0].targetPort + value: 4000 + - equal: + path: spec.ports[0].protocol + value: TCP + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should merge global and reader labels + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.labels.component: "brainstore-reader" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: brainstore-reader + + - it: should include service annotations when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.annotations.service: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-reader_test.yaml b/braintrust/tests/brainstore-reader_test.yaml new file mode 100644 index 0000000..4beacd1 --- /dev/null +++ b/braintrust/tests/brainstore-reader_test.yaml @@ -0,0 +1,205 @@ +suite: test Brainstore Reader deployment template +templates: + - brainstore-reader-deployment.yaml +tests: + - it: should render Brainstore Reader deployment with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: brainstore-reader + - equal: + path: spec.replicas + value: 1 + - equal: + path: spec.template.spec.containers[0].name + value: brainstore-reader + - equal: + path: spec.template.spec.containers[0].image + value: test/brainstore:v1.0.0 + + - it: should include azure workload identity label when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.metadata.labels["azure.workload.identity/use"] + value: "true" + + - it: should include gke workload identity label when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.metadata.labels["gke-workload-identity/use"] + value: "true" + - equal: + path: spec.template.metadata.annotations["iam.gke.io/gcp-service-account"] + value: test@project.iam.gserviceaccount.com + + - it: should use Azure Container Storage volume when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - isNotNull: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate + - equal: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate.spec.storageClassName + value: local + - equal: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage + value: "100Gi" + + - it: should use emptyDir volume when Azure Container Storage is disabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - isNotNull: + path: spec.template.spec.volumes[0].emptyDir + + - it: should include Azure Key Vault volume mount when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: secrets-store-inline + mountPath: "/mnt/secrets-store" + readOnly: true + + - it: should include nodeSelector for GKE Autopilot when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/machine-family"] + value: c4 + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/gke-ephemeral-storage-local-ssd"] + value: "true" + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/compute-class"] + value: "Performance" + + - it: should include BRAINSTORE_LOCKS_URI when locksBackend is redis + values: + - __fixtures__/base-values.yaml + set: + brainstore.locksBackend: "redis" + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: BRAINSTORE_LOCKS_URI + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: REDIS_URL + + - it: should include extraEnvVars when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.extraEnvVars: + - name: CUSTOM_VAR + value: "custom-value" + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: CUSTOM_VAR + value: "custom-value" + + - it: should include livenessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + brainstore.livenessProbe: + httpGet: + path: / + port: 4000 + initialDelaySeconds: 60 + periodSeconds: 10 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.path + value: / + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.port + value: 4000 + - equal: + path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds + value: 60 + - equal: + path: spec.template.spec.containers[0].livenessProbe.periodSeconds + value: 10 + + - it: should include readinessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + brainstore.readinessProbe: + httpGet: + path: /status + port: 4000 + initialDelaySeconds: 30 + periodSeconds: 5 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.path + value: /status + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.port + value: 4000 + - equal: + path: spec.template.spec.containers[0].readinessProbe.initialDelaySeconds + value: 30 + - equal: + path: spec.template.spec.containers[0].readinessProbe.periodSeconds + value: 5 + + - it: should not include probes when explicitly disabled + values: + - __fixtures__/base-values.yaml + set: + brainstore.livenessProbe: null + brainstore.readinessProbe: null + release: + namespace: "braintrust" + asserts: + - isNull: + path: spec.template.spec.containers[0].livenessProbe + - isNull: + path: spec.template.spec.containers[0].readinessProbe diff --git a/braintrust/tests/brainstore-serviceaccount_test.yaml b/braintrust/tests/brainstore-serviceaccount_test.yaml new file mode 100644 index 0000000..af26bba --- /dev/null +++ b/braintrust/tests/brainstore-serviceaccount_test.yaml @@ -0,0 +1,116 @@ +suite: test Brainstore serviceaccount template +templates: + - brainstore-serviceaccount.yaml +tests: + - it: should render Brainstore serviceaccount with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: brainstore + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should include AWS IAM role annotation when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["eks.amazonaws.com/role-arn"] + value: arn:aws:iam::123456789012:role/test-brainstore-role + + - it: should include Azure workload identity annotation when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["azure.workload.identity/client-id"] + value: test-brainstore-client-id + + - it: should include GCP service account annotation when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["iam.gke.io/gcp-service-account"] + value: test@project.iam.gserviceaccount.com + + - it: should not include cloud-specific annotations when cloud is empty + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isNull: + path: metadata.annotations["eks.amazonaws.com/role-arn"] + - isNull: + path: metadata.annotations["azure.workload.identity/client-id"] + - isNull: + path: metadata.annotations["iam.gke.io/gcp-service-account"] + + - it: should merge global and brainstore labels + values: + - __fixtures__/base-values.yaml + set: + brainstore.labels.component: "brainstore" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: brainstore + + - it: should include custom serviceaccount annotations when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.serviceAccount.annotations: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-writer-configmap_test.yaml b/braintrust/tests/brainstore-writer-configmap_test.yaml new file mode 100644 index 0000000..0de94d4 --- /dev/null +++ b/braintrust/tests/brainstore-writer-configmap_test.yaml @@ -0,0 +1,184 @@ +suite: test Brainstore Writer configmap template +templates: + - brainstore-writer-configmap.yaml +tests: + - it: should render Brainstore Writer configmap with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: brainstore-writer + - equal: + path: data.BRAINSTORE_READER_ONLY_MODE + value: "false" + - equal: + path: data.BRAINSTORE_PORT + value: "4000" + - equal: + path: data.BRAINSTORE_CACHE_DIR + value: "/mnt/tmp/brainstore" + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should configure verbose mode + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.verbose: true + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_VERBOSE + value: "1" + + - it: should configure AWS URIs when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "s3://test-brainstore-bucket/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "s3://test-brainstore-bucket/brainstore/wal" + + - it: should configure Azure URIs when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AZURE_STORAGE_ACCOUNT_NAME + value: "teststorageaccount" + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "az://brainstore/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "az://brainstore/brainstore/wal" + + - it: should configure Google Cloud URIs when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_INDEX_URI + value: "gs://test-brainstore-bucket/brainstore/index" + - equal: + path: data.BRAINSTORE_REALTIME_WAL_URI + value: "gs://test-brainstore-bucket/brainstore/wal" + + - it: should include locks URI when locksBackend is objectStorage for AWS + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "s3://test-brainstore-bucket/brainstore/locks" + + - it: should include locks URI when locksBackend is objectStorage for Azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "az://brainstore/brainstore/locks" + + - it: should include locks URI when locksBackend is objectStorage for Google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + brainstore.locksBackend: "objectStorage" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_LOCKS_URI + value: "gs://test-brainstore-bucket/brainstore/locks" + + - it: should not include locks URI when locksBackend is redis + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + set: + brainstore.locksBackend: "redis" + release: + namespace: "braintrust" + asserts: + - isNull: + path: data.BRAINSTORE_LOCKS_URI + + - it: should include control plane telemetry + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: data.BRAINSTORE_CONTROL_PLANE_TELEMETRY + value: "status,metrics" + + - it: should merge global and writer labels + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.labels.component: "brainstore-writer" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: brainstore-writer + + - it: should include configmap annotations when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.annotations.configmap: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-writer-service_test.yaml b/braintrust/tests/brainstore-writer-service_test.yaml new file mode 100644 index 0000000..66575e8 --- /dev/null +++ b/braintrust/tests/brainstore-writer-service_test.yaml @@ -0,0 +1,107 @@ +suite: test Brainstore Writer service template +templates: + - brainstore-writer-service.yaml +tests: + - it: should render Brainstore Writer service with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Service + - equal: + path: metadata.name + value: brainstore-writer + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.selector.app + value: brainstore-writer + + - it: should use custom service name when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.service.name: "custom-writer-service" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.name + value: custom-writer-service + + - it: should configure port correctly + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.ports[0].name + value: http + - equal: + path: spec.ports[0].port + value: 4000 + - equal: + path: spec.ports[0].targetPort + value: 4000 + - equal: + path: spec.ports[0].protocol + value: TCP + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should merge global and writer labels + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.labels.component: "brainstore-writer" + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: brainstore-writer + + - it: should include service annotations when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.annotations.service: + custom-annotation: "value" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value diff --git a/braintrust/tests/brainstore-writer_test.yaml b/braintrust/tests/brainstore-writer_test.yaml new file mode 100644 index 0000000..d6af6d7 --- /dev/null +++ b/braintrust/tests/brainstore-writer_test.yaml @@ -0,0 +1,205 @@ +suite: test Brainstore Writer deployment template +templates: + - brainstore-writer-deployment.yaml +tests: + - it: should render Brainstore Writer deployment with default values + values: + - __fixtures__/base-values.yaml + release: + namespace: "braintrust" + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: brainstore-writer + - equal: + path: spec.replicas + value: 1 + - equal: + path: spec.template.spec.containers[0].name + value: brainstore-writer + - equal: + path: spec.template.spec.containers[0].image + value: test/brainstore:v1.0.0 + + - it: should include azure workload identity label when cloud is azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.metadata.labels["azure.workload.identity/use"] + value: "true" + + - it: should include gke workload identity label when cloud is google + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.metadata.labels["gke-workload-identity/use"] + value: "true" + - equal: + path: spec.template.metadata.annotations["iam.gke.io/gcp-service-account"] + value: test@project.iam.gserviceaccount.com + + - it: should use Azure Container Storage volume when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - isNotNull: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate + - equal: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate.spec.storageClassName + value: local + - equal: + path: spec.template.spec.volumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage + value: "200Gi" + + - it: should use emptyDir volume when Azure Container Storage is disabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - isNotNull: + path: spec.template.spec.volumes[0].emptyDir + + - it: should include Azure Key Vault volume mount when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: secrets-store-inline + mountPath: "/mnt/secrets-store" + readOnly: true + + - it: should include nodeSelector for GKE Autopilot when enabled + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/machine-family"] + value: c4 + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/gke-ephemeral-storage-local-ssd"] + value: "true" + - equal: + path: spec.template.spec.nodeSelector["cloud.google.com/compute-class"] + value: "Performance" + + - it: should include BRAINSTORE_LOCKS_URI when locksBackend is redis + values: + - __fixtures__/base-values.yaml + set: + brainstore.locksBackend: "redis" + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: BRAINSTORE_LOCKS_URI + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: REDIS_URL + + - it: should include extraEnvVars when provided + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.extraEnvVars: + - name: CUSTOM_VAR + value: "custom-value" + release: + namespace: "braintrust" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: CUSTOM_VAR + value: "custom-value" + + - it: should include livenessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + brainstore.livenessProbe: + httpGet: + path: / + port: 4000 + initialDelaySeconds: 60 + periodSeconds: 10 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.path + value: / + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.port + value: 4000 + - equal: + path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds + value: 60 + - equal: + path: spec.template.spec.containers[0].livenessProbe.periodSeconds + value: 10 + + - it: should include readinessProbe when configured + values: + - __fixtures__/base-values.yaml + set: + brainstore.readinessProbe: + httpGet: + path: /status + port: 4000 + initialDelaySeconds: 30 + periodSeconds: 5 + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.path + value: /status + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.port + value: 4000 + - equal: + path: spec.template.spec.containers[0].readinessProbe.initialDelaySeconds + value: 30 + - equal: + path: spec.template.spec.containers[0].readinessProbe.periodSeconds + value: 5 + + - it: should not include probes when explicitly disabled + values: + - __fixtures__/base-values.yaml + set: + brainstore.livenessProbe: null + brainstore.readinessProbe: null + release: + namespace: "braintrust" + asserts: + - isNull: + path: spec.template.spec.containers[0].livenessProbe + - isNull: + path: spec.template.spec.containers[0].readinessProbe diff --git a/braintrust/tests/namespace_test.yaml b/braintrust/tests/namespace_test.yaml new file mode 100644 index 0000000..9cbb7dd --- /dev/null +++ b/braintrust/tests/namespace_test.yaml @@ -0,0 +1,70 @@ +suite: test namespace template and helper +templates: + - namespace.yaml +tests: + - it: should not render namespace when createNamespace is false + set: + global.createNamespace: false + global.namespace: "braintrust" + asserts: + - hasDocuments: + count: 0 + + - it: should render namespace when createNamespace is true + set: + global.createNamespace: true + global.namespace: "my-namespace" + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Namespace + - equal: + path: metadata.name + value: my-namespace + - equal: + path: metadata.labels.name + value: my-namespace + + - it: should include global labels in namespace + set: + global.createNamespace: true + global.namespace: "test-ns" + global.labels.environment: "production" + global.labels.team: "platform" + asserts: + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.team + value: platform + + - it: should include namespace annotations + set: + global.createNamespace: true + global.namespace: "test-ns" + global.namespaceAnnotations.custom-annotation: "value" + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: value + + - it: should include azure workload identity annotation when cloud is azure + set: + cloud: "azure" + global.createNamespace: true + global.namespace: "test-ns" + asserts: + - equal: + path: metadata.annotations["azure.workload.identity/use"] + value: "true" + + - it: should not include azure workload identity annotation when cloud is not azure + set: + cloud: "google" + global.createNamespace: true + global.namespace: "test-ns" + asserts: + - isNull: + path: metadata.annotations["azure.workload.identity/use"] diff --git a/braintrust/tests/secretproviderclass_test.yaml b/braintrust/tests/secretproviderclass_test.yaml new file mode 100644 index 0000000..1118d34 --- /dev/null +++ b/braintrust/tests/secretproviderclass_test.yaml @@ -0,0 +1,150 @@ +suite: test SecretProviderClass template +templates: + - secretproviderclass.yaml +tests: + - it: should not render when cloud is not azure + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should not render when cloud is aws + values: + - __fixtures__/base-values.yaml + - __fixtures__/aws-values.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should not render when cloud is azure but enableAzureKeyVaultDriver is false + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + azure.enableAzureKeyVaultDriver: false + asserts: + - hasDocuments: + count: 0 + + - it: should render SecretProviderClass when cloud is azure and enableAzureKeyVaultDriver is true + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - hasDocuments: + count: 1 + - isKind: + of: SecretProviderClass + - equal: + path: metadata.name + value: test-keyvault + + - it: should use correct namespace from helper when createNamespace is false + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: false + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: release-namespace + + - it: should use global namespace when createNamespace is true + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + global.namespace: "custom-ns" + global.createNamespace: true + release: + namespace: "release-namespace" + asserts: + - equal: + path: metadata.namespace + value: custom-ns + + - it: should configure Azure provider correctly + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.provider + value: azure + - equal: + path: spec.parameters.usePodIdentity + value: "false" + - equal: + path: spec.parameters.useVMManagedIdentity + value: "false" + - equal: + path: spec.parameters.keyvaultName + value: test-keyvault + - equal: + path: spec.parameters.clientID + value: test-client-id + - equal: + path: spec.parameters.tenantId + value: test-tenant-id + + - it: should configure secret objects for kubernetes secret sync + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.secretObjects[0].secretName + value: braintrust-secrets + - equal: + path: spec.secretObjects[0].type + value: Opaque + - contains: + path: spec.secretObjects[0].data + content: + key: REDIS_URL + objectName: redis-connection-string + - contains: + path: spec.secretObjects[0].data + content: + key: PG_URL + objectName: postgres-connection-string + - contains: + path: spec.secretObjects[0].data + content: + key: BRAINSTORE_LICENSE_KEY + objectName: brainstore-license-key + - contains: + path: spec.secretObjects[0].data + content: + key: FUNCTION_SECRET_KEY + objectName: function-secret-key + - contains: + path: spec.secretObjects[0].data + content: + key: AZURE_STORAGE_CONNECTION_STRING + objectName: azure-storage-connection-string + + - it: should include global labels + values: + - __fixtures__/base-values.yaml + - __fixtures__/azure-values.yaml + set: + global.labels.environment: "production" + release: + namespace: "braintrust" + asserts: + - equal: + path: metadata.labels.environment + value: production diff --git a/braintrust/tests/storageclass_test.yaml b/braintrust/tests/storageclass_test.yaml new file mode 100644 index 0000000..2b1fb7c --- /dev/null +++ b/braintrust/tests/storageclass_test.yaml @@ -0,0 +1,52 @@ +suite: test StorageClass template +templates: + - storageclass.yaml +tests: + - it: should not render when cloud is not azure + set: + cloud: "google" + azure.enableAzureContainerStorageDriver: true + asserts: + - hasDocuments: + count: 0 + + - it: should not render when cloud is azure but enableAzureContainerStorageDriver is false + set: + cloud: "azure" + azure.enableAzureContainerStorageDriver: false + asserts: + - hasDocuments: + count: 0 + + - it: should render StorageClass when cloud is azure and enableAzureContainerStorageDriver is true + set: + cloud: "azure" + azure.enableAzureContainerStorageDriver: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: StorageClass + - equal: + path: metadata.name + value: local + - equal: + path: provisioner + value: localdisk.csi.acstor.io + - equal: + path: reclaimPolicy + value: Delete + - equal: + path: volumeBindingMode + value: WaitForFirstConsumer + - equal: + path: allowVolumeExpansion + value: true + + - it: should not render when cloud is aws + set: + cloud: "aws" + azure.enableAzureContainerStorageDriver: true + asserts: + - hasDocuments: + count: 0 diff --git a/braintrust/values.yaml b/braintrust/values.yaml index ee1875c..c253e09 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -105,7 +105,7 @@ api: # Brainstore backfill configuration. These defaults are fine for most cases. backfillDisableHistorical: false backfillDisableNonhistorical: false - allowInvalidBase64: false # By default, we will error on invalid base64 strings. Setting this to true will allow invalid base64 strings to be processed. + allowInvalidBase64: false # By default, we will error on invalid base64 strings. Setting this to true will allow invalid base64 strings to be processed. nodeMemoryPercent: "80" extraEnvVars: # Example: diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..6629763 --- /dev/null +++ b/test.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +# Test script for Braintrust Helm chart +# Runs both unit tests and integration tests + +set -e + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +# Change to the script's directory +cd "$SCRIPT_DIR" || exit 1 + +CHART_DIR="braintrust" + +echo "==========================================" +echo "Testing Braintrust Helm Chart" +echo "==========================================" +echo "" + +# Check if helm is installed +if ! command -v helm &> /dev/null; then + echo "❌ Helm is not installed. Please install Helm first." + exit 1 +fi + +# Check if helm-unittest is installed using helm plugin list +# Suppress stderr to avoid plugin loading errors from other plugins +HELM_UNITTEST_INSTALLED=false +if helm plugin list 2>/dev/null | grep -q "unittest"; then + HELM_UNITTEST_INSTALLED=true +fi + +# If not found, try to install it +if [ "$HELM_UNITTEST_INSTALLED" = false ]; then + echo "⚠️ helm-unittest plugin not found. Installing..." + # Suppress plugin loading errors by redirecting stderr + helm plugin install https://github.com/helm-unittest/helm-unittest.git --verify=false 2>/dev/null || { + echo "❌ Failed to install helm-unittest plugin" + echo " You may need to fix corrupted helm plugins first." + echo " Try: helm plugin uninstall helm-diff (if causing issues)" + exit 1 + } + HELM_UNITTEST_INSTALLED=true +fi + +# Check if ct is installed +if ! command -v ct &> /dev/null; then + echo "⚠️ Chart Testing (ct) is not installed." + echo " Install it with: brew install chart-testing (macOS) or download from https://github.com/helm/chart-testing" + echo " Skipping Chart Testing validation..." + SKIP_CT=true +else + SKIP_CT=false +fi + +echo "" +echo "==========================================" +echo "1. Running Unit Tests (helm-unittest)" +echo "==========================================" +echo "" + +# Run helm unittest, suppressing plugin loading errors from stderr +if helm unittest "$CHART_DIR" 2>/dev/null; then + echo "" + echo "✅ Unit tests passed" +else + echo "" + echo "❌ Unit tests failed" + exit 1 +fi + +echo "" +echo "==========================================" +echo "2. Testing Chart Rendering" +echo "==========================================" +echo "" + +# Test rendering with different values files +VALUES_FILES=( + "$CHART_DIR/ci/values-azure.yaml" + "$CHART_DIR/ci/values-google.yaml" + "$CHART_DIR/ci/values-aws.yaml" + "$CHART_DIR/ci/values-minimal.yaml" +) + +RENDER_FAILED=false + +for values_file in "${VALUES_FILES[@]}"; do + if [ -f "$values_file" ]; then + echo "Testing with $(basename "$values_file")..." + if helm template test-release "$CHART_DIR" --values "$values_file" > /dev/null 2>&1; then + echo " ✅ Rendered successfully" + else + echo " ❌ Failed to render" + RENDER_FAILED=true + fi + else + echo " ⚠️ Values file not found: $values_file" + fi +done + +if [ "$RENDER_FAILED" = true ]; then + echo "" + echo "❌ Chart rendering tests failed" + exit 1 +fi + +echo "" +echo "✅ Chart rendering tests passed" + +if [ "$SKIP_CT" = false ]; then + echo "" + echo "==========================================" + echo "3. Running Chart Testing (ct lint)" + echo "==========================================" + echo "" + + if ct lint --charts "$CHART_DIR" --validate-maintainers=false; then + echo "" + echo "✅ Chart linting passed" + else + echo "" + echo "❌ Chart linting failed" + exit 1 + fi +fi + +echo "" +echo "==========================================" +echo "✅ All tests passed!" +echo "==========================================" From add4ac14b488617ef0c5da8e2e018ee2e9cec4b1 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:42:34 -0800 Subject: [PATCH 2/7] Updates --- .github/workflows/test-helm-chart.yml | 74 +++++++++++++++++++++++++++ braintrust/README.md | 10 +--- test.sh | 42 ++++----------- 3 files changed, 86 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/test-helm-chart.yml diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml new file mode 100644 index 0000000..73c3e8a --- /dev/null +++ b/.github/workflows/test-helm-chart.yml @@ -0,0 +1,74 @@ +name: Test Helm Chart + +on: + pull_request: + paths: + - 'braintrust/**' + - '.github/workflows/test-helm-chart.yml' + push: + branches: + - main + - master + paths: + - 'braintrust/**' + - '.github/workflows/test-helm-chart.yml' + +jobs: + unittest: + name: Unit Tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: 'latest' + + - name: Install helm-unittest + run: | + helm plugin install https://github.com/quintush/helm-unittest + + - name: Run unit tests + run: | + helm unittest braintrust + + lint-test: + name: Lint and Test + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: 'latest' + + - name: Lint chart + run: helm lint braintrust --strict + + test-values: + name: Test with Values Files + runs-on: ubuntu-latest + strategy: + matrix: + values-file: + - braintrust/ci/values-azure.yaml + - braintrust/ci/values-google.yaml + - braintrust/ci/values-aws.yaml + - braintrust/ci/values-minimal.yaml + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: 'latest' + + - name: Test chart rendering with ${{ matrix.values-file }} + run: | + helm template test-release braintrust --values ${{ matrix.values-file }} > /dev/null + echo "✅ Chart rendered successfully with ${{ matrix.values-file }}" diff --git a/braintrust/README.md b/braintrust/README.md index 56474c4..b359cfa 100644 --- a/braintrust/README.md +++ b/braintrust/README.md @@ -149,21 +149,13 @@ For Standard mode clusters, create node pools with local SSDs, then deploy: ## Testing -This Helm chart includes comprehensive automated tests. See [TESTING.md](TESTING.md) for detailed information on: - -- Running tests locally -- Understanding test structure -- Adding new tests -- CI integration +This Helm chart includes comprehensive automated tests. See [TESTING.md](TESTING.md). Quick start: ```bash # Run all tests ./test.sh - -# Run only unit tests -helm unittest braintrust ``` ## Breaking Changes diff --git a/test.sh b/test.sh index 6629763..fbce312 100755 --- a/test.sh +++ b/test.sh @@ -13,11 +13,6 @@ cd "$SCRIPT_DIR" || exit 1 CHART_DIR="braintrust" -echo "==========================================" -echo "Testing Braintrust Helm Chart" -echo "==========================================" -echo "" - # Check if helm is installed if ! command -v helm &> /dev/null; then echo "❌ Helm is not installed. Please install Helm first." @@ -37,28 +32,15 @@ if [ "$HELM_UNITTEST_INSTALLED" = false ]; then # Suppress plugin loading errors by redirecting stderr helm plugin install https://github.com/helm-unittest/helm-unittest.git --verify=false 2>/dev/null || { echo "❌ Failed to install helm-unittest plugin" - echo " You may need to fix corrupted helm plugins first." - echo " Try: helm plugin uninstall helm-diff (if causing issues)" exit 1 } HELM_UNITTEST_INSTALLED=true fi -# Check if ct is installed -if ! command -v ct &> /dev/null; then - echo "⚠️ Chart Testing (ct) is not installed." - echo " Install it with: brew install chart-testing (macOS) or download from https://github.com/helm/chart-testing" - echo " Skipping Chart Testing validation..." - SKIP_CT=true -else - SKIP_CT=false -fi - echo "" echo "==========================================" echo "1. Running Unit Tests (helm-unittest)" echo "==========================================" -echo "" # Run helm unittest, suppressing plugin loading errors from stderr if helm unittest "$CHART_DIR" 2>/dev/null; then @@ -109,21 +91,19 @@ fi echo "" echo "✅ Chart rendering tests passed" -if [ "$SKIP_CT" = false ]; then +echo "" +echo "==========================================" +echo "3. Running Helm Lint" +echo "==========================================" +echo "" + +if helm lint "$CHART_DIR" --strict; then echo "" - echo "==========================================" - echo "3. Running Chart Testing (ct lint)" - echo "==========================================" + echo "✅ Chart linting passed" +else echo "" - - if ct lint --charts "$CHART_DIR" --validate-maintainers=false; then - echo "" - echo "✅ Chart linting passed" - else - echo "" - echo "❌ Chart linting failed" - exit 1 - fi + echo "❌ Chart linting failed" + exit 1 fi echo "" From d00f66013989155723be5e4580a63953610bf77d Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:44:12 -0800 Subject: [PATCH 3/7] Dont filter --- .github/workflows/test-helm-chart.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml index 73c3e8a..be07f25 100644 --- a/.github/workflows/test-helm-chart.yml +++ b/.github/workflows/test-helm-chart.yml @@ -2,16 +2,9 @@ name: Test Helm Chart on: pull_request: - paths: - - 'braintrust/**' - - '.github/workflows/test-helm-chart.yml' push: branches: - main - - master - paths: - - 'braintrust/**' - - '.github/workflows/test-helm-chart.yml' jobs: unittest: From 7bd695864671c93d334df01471647334efb151f4 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:47:41 -0800 Subject: [PATCH 4/7] Remove testing info --- braintrust/README.md | 4 +- braintrust/TESTING.md | 173 ------------------------------------------ 2 files changed, 1 insertion(+), 176 deletions(-) diff --git a/braintrust/README.md b/braintrust/README.md index b359cfa..8c37a5f 100644 --- a/braintrust/README.md +++ b/braintrust/README.md @@ -149,9 +149,7 @@ For Standard mode clusters, create node pools with local SSDs, then deploy: ## Testing -This Helm chart includes comprehensive automated tests. See [TESTING.md](TESTING.md). - -Quick start: +This Helm chart includes comprehensive automated unit tests. ```bash # Run all tests diff --git a/braintrust/TESTING.md b/braintrust/TESTING.md index d6f873c..e69de29 100644 --- a/braintrust/TESTING.md +++ b/braintrust/TESTING.md @@ -1,173 +0,0 @@ -# Testing the Braintrust Helm Chart - -This document describes how to test the Braintrust Helm chart locally and in CI. - -## Prerequisites - -### Install helm-unittest - -`helm-unittest` is a Helm plugin for unit testing templates. Install it with: - -```bash -helm plugin install https://github.com/quintush/helm-unittest -``` - -Verify installation: -```bash -helm unittest --version -``` - -### Install Chart Testing (ct) - -`ct` is a tool for linting and testing Helm charts. Install it with: - -**macOS:** -```bash -brew install chart-testing -``` - -**Linux:** -```bash -# Download the latest release -wget https://github.com/helm/chart-testing/releases/latest/download/ct_linux_amd64.tar.gz -tar -xzf ct_linux_amd64.tar.gz -sudo mv ct /usr/local/bin/ -``` - -**Verify installation:** -```bash -ct version -``` - -## Running Tests Locally - -### Run All Tests - -Use the provided test script to run all tests: - -```bash -./test.sh -``` - -This will: -1. Run helm-unittest on all unit test files -2. Run Chart Testing (lint, validate, test) - -### Run Unit Tests Only - -Run only the unit tests (fast, no cluster needed): - -```bash -helm unittest braintrust -``` - -Run unit tests for a specific file: - -```bash -helm unittest braintrust/tests/storageclass_test.yaml -``` - -### Run Chart Testing Only - -Run linting and validation: - -```bash -ct lint --charts braintrust -``` - -Run with specific values files: - -```bash -ct lint --charts braintrust --validate-maintainers=false -``` - -## Test Structure - -### Unit Tests - -Unit tests are located in `braintrust/tests/` and use the `helm-unittest` format. Each test file corresponds to a template file and tests: - -- Template rendering with different values -- Conditional logic (cloud provider, feature flags) -- Helper functions -- Value merging and defaults - -### Integration Tests - -Integration tests use Chart Testing and validate: - -- YAML syntax correctness -- Kubernetes schema validation -- Chart linting (best practices) -- Rendering with different values files - -Test values files are in `braintrust/ci/`: -- `values-azure.yaml` - Azure-specific configuration -- `values-google.yaml` - Google Cloud-specific configuration -- `values-aws.yaml` - AWS-specific configuration -- `values-minimal.yaml` - Minimal required values - -## Adding New Tests - -### Adding Unit Tests - -1. Create a test file in `braintrust/tests/` matching the template name (e.g., `my-template_test.yaml`) -2. Write test cases using the helm-unittest syntax -3. Run tests: `helm unittest braintrust` - -Example test structure: -```yaml -suite: test my template -templates: - - my-template.yaml -tests: - - it: should render correctly - values: - myValue: "test" - asserts: - - matchRegex: - path: metadata.name - pattern: ^my-resource -``` - -### Adding Integration Test Values - -1. Create a new values file in `braintrust/ci/` (e.g., `values-custom.yaml`) -2. The file will be automatically picked up by Chart Testing -3. Ensure it includes all required values to render the chart - -## CI Integration - -Tests run automatically in GitHub Actions on: -- Every pull request -- Every push to main/master branches - -The CI workflow: -1. Installs helm-unittest and ct -2. Runs all unit tests -3. Runs Chart Testing (lint, validate) -4. Tests with multiple values files - -## Troubleshooting - -### Unit Tests Fail - -- Check that your test values match the template expectations -- Verify template paths in assertions are correct -- Use `helm template` to manually render and inspect output - -### Chart Testing Fails - -- Ensure all required values are provided in test values files -- Check for YAML syntax errors -- Verify Kubernetes API versions are correct - -### Local Validation - -You can also use the existing `validate.sh` script for manual validation against a Kubernetes cluster: - -```bash -./validate.sh -``` - -This requires a running Kubernetes cluster and kubectl access. From a5a6ba42ef84818f03deacfb471ec7947e42346e Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:47:51 -0800 Subject: [PATCH 5/7] Remove test --- braintrust/TESTING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 braintrust/TESTING.md diff --git a/braintrust/TESTING.md b/braintrust/TESTING.md deleted file mode 100644 index e69de29..0000000 From 923d300c9395aa2687de8905fecb9ebcfa014f40 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:50:39 -0800 Subject: [PATCH 6/7] turn verify off for helm-unittest --- .github/workflows/test-helm-chart.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml index be07f25..ff118b0 100644 --- a/.github/workflows/test-helm-chart.yml +++ b/.github/workflows/test-helm-chart.yml @@ -21,7 +21,7 @@ jobs: - name: Install helm-unittest run: | - helm plugin install https://github.com/quintush/helm-unittest + helm plugin install https://github.com/quintush/helm-unittest --verify=false - name: Run unit tests run: | From c28685073e471af4c0035a0e3fb4e942c62b5d23 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Wed, 21 Jan 2026 13:52:29 -0800 Subject: [PATCH 7/7] Dont do matrix. Just run in serial --- .github/workflows/test-helm-chart.yml | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml index ff118b0..2c62c82 100644 --- a/.github/workflows/test-helm-chart.yml +++ b/.github/workflows/test-helm-chart.yml @@ -45,13 +45,6 @@ jobs: test-values: name: Test with Values Files runs-on: ubuntu-latest - strategy: - matrix: - values-file: - - braintrust/ci/values-azure.yaml - - braintrust/ci/values-google.yaml - - braintrust/ci/values-aws.yaml - - braintrust/ci/values-minimal.yaml steps: - name: Checkout code uses: actions/checkout@v4 @@ -61,7 +54,22 @@ jobs: with: version: 'latest' - - name: Test chart rendering with ${{ matrix.values-file }} + - name: Test chart rendering with Azure values run: | - helm template test-release braintrust --values ${{ matrix.values-file }} > /dev/null - echo "✅ Chart rendered successfully with ${{ matrix.values-file }}" + helm template test-release braintrust --values braintrust/ci/values-azure.yaml > /dev/null + echo "✅ Chart rendered successfully with braintrust/ci/values-azure.yaml" + + - name: Test chart rendering with Google values + run: | + helm template test-release braintrust --values braintrust/ci/values-google.yaml > /dev/null + echo "✅ Chart rendered successfully with braintrust/ci/values-google.yaml" + + - name: Test chart rendering with AWS values + run: | + helm template test-release braintrust --values braintrust/ci/values-aws.yaml > /dev/null + echo "✅ Chart rendered successfully with braintrust/ci/values-aws.yaml" + + - name: Test chart rendering with Minimal values + run: | + helm template test-release braintrust --values braintrust/ci/values-minimal.yaml > /dev/null + echo "✅ Chart rendered successfully with braintrust/ci/values-minimal.yaml"