Files
sk-react-toolkit/server/tfvarsStore.test.ts
T

152 lines
9.0 KiB
TypeScript

import assert from 'node:assert/strict'
import { after, before, test } from 'node:test'
import pg from 'pg'
import { HttpError } from './http.ts'
import { createTfvarsStore, tfvarsText, type TfvarsStore } from './tfvarsStore.ts'
// The tests create a scratch database on the server the PG* variables name, connected to through the database
// postgres, and drop it at the end.
const database = `tfvars_store_test_${process.pid}`
const admin = new pg.Client({ database: 'postgres' })
let pool: pg.Pool
let store: TfvarsStore
before(async () => {
await admin.connect()
await admin.query(`CREATE DATABASE ${database}`)
pool = new pg.Pool({ database })
store = createTfvarsStore(pool)
})
after(async () => {
await pool?.end()
await admin.query(`DROP DATABASE IF EXISTS ${database}`)
await admin.end()
})
const status = async (promise: Promise<unknown>) => {
try {
await promise
} catch (error) {
assert.ok(error instanceof HttpError, String(error))
return error.statusCode
}
return 0
}
test('modules are created, changed, listed and deleted', async () => {
await store.modules.put({ name: 'router', root: 'router/terraform', description: 'VPN router', configuratorUrl: null, configuratorDiscovery: true })
await store.modules.put({ name: 'router', root: 'router/terraform', description: 'VPN router', configuratorUrl: 'http://localhost:7083/', configuratorDiscovery: false })
await store.modules.put({ name: 'app', root: 'app', description: '', configuratorUrl: null, configuratorDiscovery: true })
assert.deepEqual(await store.modules.list(), [
{ name: 'app', root: 'app', description: '', configuratorUrl: null, configuratorDiscovery: true },
{ name: 'router', root: 'router/terraform', description: 'VPN router', configuratorUrl: 'http://localhost:7083/', configuratorDiscovery: false },
])
await store.modules.delete('app')
assert.deepEqual((await store.modules.list()).map((module) => module.name), ['router'])
assert.equal(await status(store.modules.put({ name: 'Bad', root: 'x', description: '', configuratorUrl: null, configuratorDiscovery: false })), 400)
})
test('a module registered before configurator_discovery keeps discovering its configurator; a new one does not', async () => {
// The table, the function and the procedure as they were before the column, in a schema of their own.
await pool.query(`CREATE SCHEMA earlier;
CREATE TABLE earlier.tf_modules (name text PRIMARY KEY, root text NOT NULL, description text NOT NULL DEFAULT '', configurator_url text);
INSERT INTO earlier.tf_modules VALUES ('router', 'router/terraform', '', NULL);
CREATE FUNCTION earlier.tf_modules_list() RETURNS TABLE (name text, root text, description text, configurator_url text)
LANGUAGE sql AS $$ SELECT m.name, m.root, m.description, m.configurator_url FROM earlier.tf_modules m $$;
CREATE PROCEDURE earlier.tf_module_put(a text, b text, c text, d text) LANGUAGE sql AS $$ SELECT 1 $$;`)
const earlierPool = new pg.Pool({ database, options: '-c search_path=earlier' })
try {
const earlier = createTfvarsStore(earlierPool)
await earlier.modules.put({ name: 'app', root: 'app', description: '', configuratorUrl: null, configuratorDiscovery: false })
assert.deepEqual((await earlier.modules.list()).map((module) => [module.name, module.configuratorDiscovery]), [['app', false], ['router', true]])
const { rows } = await earlierPool.query("SELECT count(*)::int AS count FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = 'earlier' AND p.proname = 'tf_module_put'")
assert.equal(rows[0].count, 1)
// Another store applies the file again over the migrated schema, which keeps the modules as they are.
assert.deepEqual((await createTfvarsStore(earlierPool).modules.list()).map((module) => [module.name, module.configuratorDiscovery]), [['app', false], ['router', true]])
} finally {
await earlierPool.end()
}
})
test('instances are created and refused for a missing module or a name in use', async () => {
await store.instances.create('router', 'platform', 'terraform_remote_state')
await store.instances.create('router', 'test', 'tf_router_test')
assert.deepEqual((await store.instances.list('router')).map((instance) => [instance.name, instance.stateSchema]), [
['platform', 'terraform_remote_state'],
['test', 'tf_router_test'],
])
assert.equal(await status(store.instances.create('missing', 'x', 'tf_missing_x')), 404)
assert.equal(await status(store.instances.create('router', 'test', 'tf_other')), 409)
assert.equal(await status(store.instances.create('router', 'other', 'tf_router_test')), 409)
assert.equal(await status(store.modules.delete('router')), 409)
})
const META = { schema: 1, producer: 'Test Configurator 1.0.0' }
test('variable files are written with their version and refused against another version', async () => {
const variables = store.variables('router', 'test')
const empty = await variables.read()
assert.deepEqual(empty.files, [])
assert.equal(empty.version, '')
assert.equal(empty.revision, null)
assert.equal(await variables.write(empty.version, { 'platform.tfvars.json': tfvarsText({ a: 1 }), 'secrets.tfvars.json': tfvarsText({ s: 'x' }) }, META), true)
const written = await variables.read()
assert.deepEqual(written.files.map((file) => [file.name, file.content.toString('utf8')]), [
['platform.tfvars.json', tfvarsText({ a: 1 })],
['secrets.tfvars.json', tfvarsText({ s: 'x' })],
])
assert.deepEqual(written.status.map((file) => file.previous), [false, false])
assert.equal(await variables.write(empty.version, { 'platform.tfvars.json': tfvarsText({ a: 2 }) }, META), false)
assert.equal(await variables.write(written.version, { 'platform.tfvars.json': tfvarsText({ a: 2 }) }, META), true)
const changed = await variables.read()
assert.deepEqual(changed.status.map((file) => file.previous), [true, false])
assert.notEqual(changed.version, written.version)
assert.equal(await variables.remove(written.version, 'secrets.tfvars.json', META), false)
assert.equal(await variables.remove(changed.version, 'secrets.tfvars.json', META), true)
assert.deepEqual((await variables.read()).files.map((file) => file.name), ['platform.tfvars.json'])
assert.deepEqual((await store.variables('router', 'platform').read()).files, [])
assert.equal(await status(variables.write((await variables.read()).version, { 'notes.json': tfvarsText({}) }, META)), 400)
assert.equal(await status(store.variables('router', 'missing').write('', { 'a.tfvars.json': tfvarsText({}) }, META)), 404)
})
test('every write is a revision with its files, schema and producer', async () => {
const variables = store.variables('router', 'test')
assert.deepEqual((await variables.revisions()).map((revision) => [revision.revision, revision.schema, revision.producer, revision.names]), [
[3, 1, META.producer, ['platform.tfvars.json']],
[2, 1, META.producer, ['platform.tfvars.json', 'secrets.tfvars.json']],
[1, 1, META.producer, ['platform.tfvars.json', 'secrets.tfvars.json']],
])
const current = await variables.read()
assert.equal(await variables.write(current.version, {}, META), true)
assert.equal(await variables.write(current.version, { 'platform.tfvars.json': tfvarsText({ a: 3 }) }, { schema: null, producer: 'manage.mjs import' }), true)
const newest = (await variables.read()).revision
assert.deepEqual(newest && [newest.revision, newest.schema, newest.producer], [4, null, 'manage.mjs import'])
const first = await variables.revision(1)
assert.deepEqual(first?.files.map((file) => [file.name, file.content.toString('utf8')]), [
['platform.tfvars.json', tfvarsText({ a: 1 })],
['secrets.tfvars.json', tfvarsText({ s: 'x' })],
])
assert.equal(await variables.revision(9), null)
assert.deepEqual(await store.variables('router', 'platform').revisions(), [])
})
test('the files of an instance without revisions become its revision 1 of an unknown producer', async () => {
await pool.query(`INSERT INTO tf_variable_files (module, instance, name, content) VALUES ('router', 'platform', 'a.tfvars.json', '{"b": 1}')`)
await pool.query('DELETE FROM tf_variable_revisions')
const again = createTfvarsStore(pool)
const revisions = await again.variables('router', 'platform').revisions()
assert.deepEqual(revisions.map((revision) => [revision.revision, revision.schema, revision.producer, revision.names]), [[1, null, 'unknown', ['a.tfvars.json']]])
assert.deepEqual((await again.variables('router', 'test').revisions()).map((revision) => revision.revision), [1])
})
test('an instance is deleted with its variable files, then its module', async () => {
await store.instances.delete('router', 'test')
await store.instances.delete('router', 'platform')
assert.deepEqual(await store.instances.list('router'), [])
assert.equal((await pool.query('SELECT count(*)::int AS n FROM tf_variable_files')).rows[0].n, 0)
assert.equal((await pool.query('SELECT count(*)::int AS n FROM tf_variable_revisions')).rows[0].n, 0)
await store.modules.delete('router')
assert.deepEqual(await store.modules.list(), [])
})