const { describe, test } = require("node:test"); const assert = require("node:assert"); const { PostgreSqlContainer } = require("@testcontainers/postgresql"); const { PostgresMonitorType } = require("../../../server/monitor-types/postgres"); const { UP, PENDING } = require("../../../src/util"); describe( "Postgres Single Node", { skip: !!process.env.CI && (process.platform !== "linux" || process.arch !== "x64"), }, () => { test("check() sets status to UP when Postgres server is reachable", async () => { // The default timeout of 30 seconds might not be enough for the container to start const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), }; const heartbeat = { msg: "", status: PENDING, }; try { await postgresMonitor.check(monitor, heartbeat, {}); assert.strictEqual(heartbeat.status, UP); } finally { postgresContainer.stop(); } }); test("check() rejects when Postgres server is not reachable", async () => { const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: "http://localhost:15432", }; const heartbeat = { msg: "", status: PENDING, }; // regex match any string const regex = /.+/; await assert.rejects(postgresMonitor.check(monitor, heartbeat, {}), regex); }); test("check() sets status to UP when custom query returns single value", async () => { // The default timeout of 30 seconds might not be enough for the container to start const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 42", conditions: "[]", }; const heartbeat = { msg: "", status: PENDING, }; try { await postgresMonitor.check(monitor, heartbeat, {}); assert.strictEqual(heartbeat.status, UP, `Expected status ${UP} but got ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); test("check() sets status to UP when custom query result meets condition", async () => { const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 42 AS value", conditions: JSON.stringify([ { type: "expression", andOr: "and", variable: "result", operator: "equals", value: "42", }, ]), }; const heartbeat = { msg: "", status: PENDING, }; try { await postgresMonitor.check(monitor, heartbeat, {}); assert.strictEqual(heartbeat.status, UP, `Expected status ${UP} but got ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); test("check() rejects when custom query result does not meet condition", async () => { const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 99 AS value", conditions: JSON.stringify([ { type: "expression", andOr: "and", variable: "result", operator: "equals", value: "42", }, ]), }; const heartbeat = { msg: "", status: PENDING, }; try { await assert.rejects( postgresMonitor.check(monitor, heartbeat, {}), new Error("Query result did not meet the specified conditions (99)") ); assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); test("check() rejects when query returns no results with conditions", async () => { const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 1 WHERE 1 = 0", conditions: JSON.stringify([ { type: "expression", andOr: "and", variable: "result", operator: "equals", value: "1", }, ]), }; const heartbeat = { msg: "", status: PENDING, }; try { await assert.rejects( postgresMonitor.check(monitor, heartbeat, {}), new Error("Database connection/query failed: Query returned no results") ); assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); test("check() rejects when query returns multiple rows with conditions", async () => { const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 1 UNION ALL SELECT 2", conditions: JSON.stringify([ { type: "expression", andOr: "and", variable: "result", operator: "equals", value: "1", }, ]), }; const heartbeat = { msg: "", status: PENDING, }; try { await assert.rejects( postgresMonitor.check(monitor, heartbeat, {}), new Error("Database connection/query failed: Multiple values were found, expected only one value") ); assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); test("check() rejects when query returns multiple columns with conditions", async () => { const postgresContainer = await new PostgreSqlContainer("postgres:latest") .withStartupTimeout(60000) .start(); const postgresMonitor = new PostgresMonitorType(); const monitor = { databaseConnectionString: postgresContainer.getConnectionUri(), databaseQuery: "SELECT 1 AS col1, 2 AS col2", conditions: JSON.stringify([ { type: "expression", andOr: "and", variable: "result", operator: "equals", value: "1", }, ]), }; const heartbeat = { msg: "", status: PENDING, }; try { await assert.rejects( postgresMonitor.check(monitor, heartbeat, {}), new Error("Database connection/query failed: Multiple columns were found, expected only one value") ); assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`); } finally { await postgresContainer.stop(); } }); } );