From b4740f65560d2468c3be11e83623e50e88afe2aa Mon Sep 17 00:00:00 2001 From: ppawlowski Date: Thu, 25 Jun 2026 07:53:08 +0200 Subject: [PATCH 1/3] Migrate unit tests --- helm/flowfuse/tests/configmap_test.yaml | 101 ++++++++++++++++++ .../tests/file_storage_configmap_test.yaml | 27 +++++ 2 files changed, 128 insertions(+) create mode 100644 helm/flowfuse/tests/file_storage_configmap_test.yaml diff --git a/helm/flowfuse/tests/configmap_test.yaml b/helm/flowfuse/tests/configmap_test.yaml index 494c0ad8..52f3646b 100644 --- a/helm/flowfuse/tests/configmap_test.yaml +++ b/helm/flowfuse/tests/configmap_test.yaml @@ -5,6 +5,107 @@ templates: set: forge.domain: "chart-unit-tests.com" tests: + - it: should render core server settings (host, port, domain) + set: + forge.domain: example.com + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "host: 0\\.0\\.0\\.0" + - matchRegex: + path: data["flowforge.yml"] + pattern: "port: 3000" + - matchRegex: + path: data["flowforge.yml"] + pattern: "domain: example\\.com" + + - it: should configure the postgres database + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "db:\\n\\s+type: postgres" + + - it: should configure the kubernetes driver + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "driver:\\n\\s+type: kubernetes" + + - it: should render default logging configuration + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "logging:\\n\\s+level: info\\n\\s+http: info" + + - it: should render the email block when email is configured + set: + forge.email: + from: '"FlowForge" ' + ses: + region: eu-west-1 + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "email:\\n\\s+enabled: true" + + - it: should default the email block to disabled when email is not configured + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "email:\\n\\s+enabled: false" + + - it: should render broker url and public_url when broker is enabled + set: + forge.broker: + enabled: true + url: mqtt://flowforge-broker.default:1883 + public_url: wss://mqtt.example.com + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "broker:" + - matchRegex: + path: data["flowforge.yml"] + pattern: "url: mqtt://flowforge-broker\\.default:1883" + - matchRegex: + path: data["flowforge.yml"] + pattern: "public_url: wss://mqtt\\.example\\.com" + + - it: should render the fileStore url when fileStore is enabled + release: + namespace: default + set: + forge.fileStore.enabled: true + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "fileStore:\\n\\s+url: http://flowforge-file\\.default" + + - it: should render sentry telemetry for frontend and backend + set: + forge.telemetry.sentry: + production_mode: false + frontend_dsn: https://sentry.io/flowforge/flowforge-frontend + backend_dsn: https://sentry.io/flowforge/flowforge-backend + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "dsn: https://sentry\\.io/flowforge/flowforge-frontend" + - matchRegex: + path: data["flowforge.yml"] + pattern: "dsn: https://sentry\\.io/flowforge/flowforge-backend" + - matchRegex: + path: data["flowforge.yml"] + pattern: "production_mode: false" + + - it: should render prometheus enabled in backend telemetry + set: + forge.telemetry.backend.prometheus.enabled: true + asserts: + - matchRegex: + path: data["flowforge.yml"] + pattern: "prometheus:\\n\\s+enabled: true" + - it: should not include projectProbes by default asserts: - notMatchRegex: diff --git a/helm/flowfuse/tests/file_storage_configmap_test.yaml b/helm/flowfuse/tests/file_storage_configmap_test.yaml new file mode 100644 index 00000000..df0b873a --- /dev/null +++ b/helm/flowfuse/tests/file_storage_configmap_test.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: test file storage configmap +templates: + - file-storage-configmap.yaml +set: + forge.domain: "chart-unit-tests.com" + forge.fileStore.enabled: true +tests: + - it: should create the flowfuse-file-config configmap + documentSelector: + path: metadata.name + value: flowfuse-file-config + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: flowfuse-file-config + + - it: should enable http logging in the file storage config + documentSelector: + path: metadata.name + value: flowfuse-file-config + asserts: + - matchRegex: + path: data["flowforge-storage.yml"] + pattern: "logging:\\n\\s+level: info\\n\\s+http: info" From a48b60dd8c9cad672221ad55d134423683167cb9 Mon Sep 17 00:00:00 2001 From: ppawlowski Date: Thu, 25 Jun 2026 07:53:52 +0200 Subject: [PATCH 2/3] Remove deprecated unit tests --- test/.eslintrc | 29 ------- test/customizations-teambroker.yml | 104 ------------------------ test/customizations.yml | 79 ------------------ test/package.json | 20 ----- test/unit/configmap_spec.js | 126 ----------------------------- test/unit/ingres_spec.js | 24 ------ test/unit/services_spec.js | 31 ------- test/unit/setup.js | 54 ------------- 8 files changed, 467 deletions(-) delete mode 100644 test/.eslintrc delete mode 100644 test/customizations-teambroker.yml delete mode 100644 test/customizations.yml delete mode 100644 test/package.json delete mode 100644 test/unit/configmap_spec.js delete mode 100644 test/unit/ingres_spec.js delete mode 100644 test/unit/services_spec.js delete mode 100644 test/unit/setup.js diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index 8f35d5c8..00000000 --- a/test/.eslintrc +++ /dev/null @@ -1,29 +0,0 @@ -{ - "env": { - "browser": true, - "commonjs": true, - "es2021": true, - "mocha": true - }, - "plugins": [ - "no-only-tests" - ], - "extends": [ - "standard", - "plugin:vue/vue3-essential" - ], - "parserOptions": { - "ecmaVersion": 12 - }, - "rules": { - "indent": ["error", 4], - "vue/html-indent": ["error", 4], - "no-only-tests/no-only-tests": "error", - "object-shorthand": ["error"] - }, - "globals": { - "cy": true, - "expect": true, - "Cypress": true - } -} diff --git a/test/customizations-teambroker.yml b/test/customizations-teambroker.yml deleted file mode 100644 index 3ebb2c2e..00000000 --- a/test/customizations-teambroker.yml +++ /dev/null @@ -1,104 +0,0 @@ -forge: - domain: example.com - entryPoint: app.example - https: true - localPostgresql: false - cloudProvider: aws - managementSelector: - role: management - projectSelector: - role: projects - aws: - IAMRole: arn:aws:iam::xxxxxxxxxxxxxxxxxxx:role/flowforge_service_account_role - email: - from: "\"FlowForge\" " - ses: - region: eu-west-1 - broker: - enabled: true - url: mqtt://flowforge-broker.default:1883 - public_url: wss://mqtt.example.com - teamBroker: - enabled: true - - ee: - billing: - stripe: - key: sk_live_dfadfsajflsadfafsafsajfdsfdsflfdladjfjf - wh_secret: whsec_fkjdflksajflgljfajfdlahfdkhflksahfhf - team_price: price_123456 - team_product: prod_123456 - project_price: price_1123456 - project_product: prod_123456 - device_price: price_8888 - device_product: prod_8888 - new_customer_free_credit: 1500 - teams: - starter: - price: price_123456 - product: prod_123456 - userCost: 0 - telemetry: - enabled: true - posthog: - capture_pageview: false - apikey: phc_fdlksajfdfadfsafsaf - sentry: - production_mode: false - frontend_dsn: 'https://sentry.io/flowforge/flowforge-frontend' - backend_dsn: 'https://sentry.io/flowforge/flowforge-backend' - backend: - prometheus: - enabled: true - support: - enabled: true - hubspot: 12345678 - fileStore: - enabled: true - type: s3 - options: - bucket: flowforge-production-files - forcePathStyle: true - region: eu-west-1 - credentials: - accessKeyId: ACCESSKEY - secretAccessKey: SECRETKEY - context: - type: sequelize - options: - type: postgres - branding: - account: - signUpTopBanner: HelloWorld - rate_limits: - enabled: true - -postgresql: - host: flowforge-postgresql - auth: - username: forge - password: password - database: flowforge - postgresPassword: postgres-password - -broker: - listenersServiceTemplate: - metadata: - annotations: - service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing - service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp - service.beta.kubernetes.io/aws-load-balancer-type: nlb - service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:eu-west-1:xxxxxxxxxx:certificate/4d561d45-35e4-4bef-9aac-07bfb13e5fdd - service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "8883,443" - service.beta.kubernetes.io/aws-load-balancer-eip-allocations: eipalloc-0e44de88ccacc13be,eipalloc-0e9e5f05c5d860ff9,eipalloc-08a3321a6b27e6d26 - spec: - type: LoadBalancer - ports: - - name: wss-wrap - protocol: TCP - port: 443 - targetPort: 8080 - - name: tls-wrap - protocol: TCP - port: 8883 - targetPort: 1883 diff --git a/test/customizations.yml b/test/customizations.yml deleted file mode 100644 index 4b5a719b..00000000 --- a/test/customizations.yml +++ /dev/null @@ -1,79 +0,0 @@ -forge: - domain: example.com - entryPoint: app.example - https: true - localPostgresql: false - cloudProvider: aws - managementSelector: - role: management - projectSelector: - role: projects - aws: - IAMRole: arn:aws:iam::xxxxxxxxxxxxxxxxxxx:role/flowforge_service_account_role - email: - from: "\"FlowForge\" " - ses: - region: eu-west-1 - broker: - enabled: true - url: mqtt://flowforge-broker.default:1883 - public_url: wss://mqtt.example.com - ee: - billing: - stripe: - key: sk_live_dfadfsajflsadfafsafsajfdsfdsflfdladjfjf - wh_secret: whsec_fkjdflksajflgljfajfdlahfdkhflksahfhf - team_price: price_123456 - team_product: prod_123456 - project_price: price_1123456 - project_product: prod_123456 - device_price: price_8888 - device_product: prod_8888 - new_customer_free_credit: 1500 - teams: - starter: - price: price_123456 - product: prod_123456 - userCost: 0 - telemetry: - enabled: true - posthog: - capture_pageview: false - apikey: phc_fdlksajfdfadfsafsaf - sentry: - production_mode: false - frontend_dsn: 'https://sentry.io/flowforge/flowforge-frontend' - backend_dsn: 'https://sentry.io/flowforge/flowforge-backend' - backend: - prometheus: - enabled: true - support: - enabled: true - hubspot: 12345678 - fileStore: - enabled: true - type: s3 - options: - bucket: flowforge-production-files - forcePathStyle: true - region: eu-west-1 - credentials: - accessKeyId: ACCESSKEY - secretAccessKey: SECRETKEY - context: - type: sequelize - options: - type: postgres - branding: - account: - signUpTopBanner: HelloWorld - rate_limits: - enabled: true - -postgresql: - host: flowforge-postgresql - auth: - username: forge - password: password - database: flowforge - postgresPassword: postgres-password diff --git a/test/package.json b/test/package.json deleted file mode 100644 index 842676e8..00000000 --- a/test/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "helm-test", - "version": "1.0.0", - "test": true, - "description": "Tests for FlowForge Helm Chart", - "main": "index.js", - "scripts": { - "test": "mocha unit/**_spec.js" - }, - "author": { - "name": "FlowFlow Inc." - }, - "license": "Apache-2.0", - "devDependencies": { - "mocha": "^10.2.0", - "mocha-cli": "^1.0.1", - "should": "^13.2.3", - "yaml": "^2.2.0" - } -} diff --git a/test/unit/configmap_spec.js b/test/unit/configmap_spec.js deleted file mode 100644 index d083cdfe..00000000 --- a/test/unit/configmap_spec.js +++ /dev/null @@ -1,126 +0,0 @@ -const should = require('should') // eslint-disable-line -const setup = require('./setup') -const yaml = require('yaml') - -describe('Examine Config Maps', function () { - let configMaps - before(async function () { - const { docs } = await setup() - configMaps = docs.filter(d => d && d.kind === 'ConfigMap') - }) - - describe('FlowForge.yml', async function () { - let ffYML - beforeEach(function () { - const d = configMaps.filter(doc => doc.metadata.name === 'flowforge-config')[0] - ffYML = yaml.parse(d.data['flowforge.yml']) - }) - it('has host', function () { - ffYML.should.have.property('host') - ffYML.host.should.equal('0.0.0.0') - }) - it('has domain', function () { - ffYML.should.have.property('domain') - ffYML.domain.should.equal('example.com') - }) - it('has port', function () { - ffYML.should.have.property('port') - }) - describe('has db', function () { - it('has db', function () { - ffYML.should.have.property('db') - }) - it('has db.type', function () { - ffYML.db.should.have.property('type') - ffYML.db.type.should.equal('postgres') - }) - }) - describe('has driver', function () { - it('has driver', function () { - ffYML.should.have.property('driver') - }) - it('has driver.type', function () { - ffYML.driver.should.have.property('type') - ffYML.driver.type.should.equal('kubernetes') - }) - }) - describe('has logging', function () { - it('has logging', function () { - ffYML.should.have.property('logging') - }) - it('default', function () { - ffYML.logging.should.have.property('level') - ffYML.logging.level.should.equal('info') - }) - it('http', function () { - ffYML.logging.should.have.property('http') - ffYML.logging.http.should.equal('info') - }) - }) - describe('has broker', function () { - it('has broker', function () { - ffYML.should.have.property('broker') - }) - it('has broker.url', function () { - ffYML.broker.should.have.property('url') - ffYML.broker.url.should.equal('mqtt://flowforge-broker.default:1883') - }) - it('has broker.public_url', function () { - ffYML.broker.should.have.property('public_url') - ffYML.broker.public_url.should.equal('wss://mqtt.example.com') - }) - it('has mosquitto.conf', function () { - // need to check values - }) - }) - describe('has email', function () { - it('has email', function () { - ffYML.should.have.property('email') - }) - }) - describe('has fileStore', function () { - it('has fileStore', function () { - ffYML.should.have.property('fileStore') - }) - it('has fileStore.url', function () { - ffYML.fileStore.should.have.property('url') - ffYML.fileStore.url.should.equal('http://flowforge-file.default') - }) - it('has configmap', function () { - const cm = configMaps.filter(s => s.metadata.name === 'flowfuse-file-config') - cm.should.have.length(1) - }) - it('http logging enabled', function () { - const d = configMaps.filter(s => s.metadata.name === 'flowfuse-file-config')[0] - fsYML = yaml.parse(d.data['flowforge-storage.yml']) - fsYML.should.have.property('logging') - fsYML.logging.should.have.property('http') - }) - }) - }) - - describe('customizations.yml', async function () { - let yml - beforeEach(function () { - const d = configMaps.filter(doc => doc.metadata.name === 'flowforge-config')[0] - yml = yaml.parse(d.data['flowforge.yml']) - }) - - it('has sentry telemetry', function () { - yml.telemetry.frontend.sentry.should.have.property('production_mode') - yml.telemetry.frontend.sentry.production_mode.should.equal(false) - - yml.telemetry.frontend.sentry.should.have.property('dsn') - yml.telemetry.frontend.sentry.dsn.should.equal('https://sentry.io/flowforge/flowforge-frontend') - - yml.telemetry.backend.sentry.should.have.property('dsn') - yml.telemetry.backend.sentry.dsn.should.equal('https://sentry.io/flowforge/flowforge-backend') - }) - - describe('using Prometheus', function () { - it('has prometheus enabled', function() { - yml.telemetry.backend.prometheus.enabled.should.equal(true) - }) - }) - }) -}) diff --git a/test/unit/ingres_spec.js b/test/unit/ingres_spec.js deleted file mode 100644 index 290d82ae..00000000 --- a/test/unit/ingres_spec.js +++ /dev/null @@ -1,24 +0,0 @@ -const should = require('should') // eslint-disable-line -const setup = require('./setup') - -describe('Examine Ingress', function () { - let ingresses - before(async function () { - const { docs } = await setup() - ingresses = docs.filter(d => d && d.kind === 'Ingress') - }) - - describe('flowforge', function () { - it('has ingres', function () { - const ingress = ingresses.filter(s => s.metadata.name === 'flowforge-ingress') - ingress.should.have.length(1) - }) - }) - - describe('broker', function () { - it('has ingres', function () { - const ingress = ingresses.filter(s => s.metadata.name === 'flowforge-broker') - ingress.should.have.length(1) - }) - }) -}) diff --git a/test/unit/services_spec.js b/test/unit/services_spec.js deleted file mode 100644 index 1de8a6ce..00000000 --- a/test/unit/services_spec.js +++ /dev/null @@ -1,31 +0,0 @@ -const should = require('should') // eslint-disable-line -const setup = require('./setup') - -describe('Examine Services', function () { - let services - before(async function () { - const { docs } = await setup() - services = docs.filter(d => d && d.kind === 'Service') - }) - - describe('flowforge', function () { - it('has service', function () { - const service = services.filter(s => s.metadata.name === 'forge') - service.should.have.length(1) - }) - }) - - describe('file-server', function () { - it('has service', function () { - const service = services.filter(s => s.metadata.name === 'flowforge-file') - service.should.have.length(1) - }) - }) - - describe('broker', function () { - it('has service', function () { - const service = services.filter(s => s.metadata.name === 'flowforge-broker') - service.should.have.length(1) - }) - }) -}) diff --git a/test/unit/setup.js b/test/unit/setup.js deleted file mode 100644 index 1385d340..00000000 --- a/test/unit/setup.js +++ /dev/null @@ -1,54 +0,0 @@ -const { exec } = require('child_process') -const { join } = require('path') -const yaml = require('yaml') - -async function setup () { - const rootDir = join(__dirname, '../../helm') - const testDir = join(__dirname, '..') - const child = exec([ - 'helm', - 'template', - 'flowfuse', - 'flowfuse', - '--api-versions', - 'apps.emqx.io/v2beta1', - '-f', - `${testDir}/customizations.yml` - ].join(' '), { - cwd: rootDir - }) - - const promise = new Promise((resolve, reject) => { - let stdout = '' - let stderr = '' - - child.stdout.on('data', data => { - // console.log('out', data) - stdout += data - }) - - child.stderr.on('data', data => { - // console.log('err:', data) - stderr += data - }) - - child.on('exit', (code) => { - // console.log(stdout) - // console.log(stderr) - // console.log('exit', code) - if (code === 0) { - const documents = yaml.parseAllDocuments(stdout) - const docs = documents.map(d => d.toJS()) - resolve({ - docs - }) - } else { - const err = new Error(stderr) - reject(err, code) - } - }) - }) - return promise -} - -module.exports = setup From ea856324ef261b30d28d9e1119da383e4d495ad7 Mon Sep 17 00:00:00 2001 From: ppawlowski Date: Thu, 25 Jun 2026 07:54:11 +0200 Subject: [PATCH 3/3] Remove deprecated unit tests workflow --- .github/workflows/test.yml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 45292b3d..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Default test - -on: - push: - branches: [ main ] - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - name: Use Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: 24 - - name: Install Helm - uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 - with: - version: v3.11.0 - - name: test - run: | - cd test - npm install - npm run test \ No newline at end of file