@@ -4,6 +4,7 @@ import { resolve } from "path";
44// Import from source directly since we're using Bun
55import * as checkup from "../lib/checkup" ;
66import * as api from "../lib/checkup-api" ;
7+ import { createMockClient } from "./test-utils" ;
78
89
910function runCli ( args : string [ ] , env : Record < string , string > = { } ) {
@@ -19,111 +20,6 @@ function runCli(args: string[], env: Record<string, string> = {}) {
1920 } ;
2021}
2122
22- // Mock client for testing report generators
23- interface MockClientOptions {
24- settingsRows ?: any [ ] ; // Settings metric rows (tag_setting_name, tag_setting_value, etc.)
25- databaseSizesRows ?: any [ ] ;
26- dbStatsRows ?: any [ ] ; // db_stats metric rows (numbackends, xact_commit, etc.)
27- connectionStatesRows ?: any [ ] ;
28- uptimeRows ?: any [ ] ;
29- invalidIndexesRows ?: any [ ] ;
30- unusedIndexesRows ?: any [ ] ;
31- redundantIndexesRows ?: any [ ] ;
32- }
33-
34- function createMockClient ( versionRows : any [ ] , _legacySettingsRows : any [ ] , options : MockClientOptions = { } ) {
35- const {
36- settingsRows = [ ] ,
37- databaseSizesRows = [ ] ,
38- dbStatsRows = [ ] ,
39- connectionStatesRows = [ ] ,
40- uptimeRows = [ ] ,
41- invalidIndexesRows = [ ] ,
42- unusedIndexesRows = [ ] ,
43- redundantIndexesRows = [ ] ,
44- } = options ;
45-
46- return {
47- query : async ( sql : string ) => {
48- // Version query (simple inline - used by getPostgresVersion)
49- if ( sql . includes ( "server_version" ) && sql . includes ( "server_version_num" ) && sql . includes ( "pg_settings" ) && ! sql . includes ( "tag_setting_name" ) ) {
50- return { rows : versionRows } ;
51- }
52- // Settings metric query (from metrics.yml - has tag_setting_name, tag_setting_value)
53- if ( sql . includes ( "tag_setting_name" ) && sql . includes ( "tag_setting_value" ) && sql . includes ( "pg_settings" ) ) {
54- return { rows : settingsRows } ;
55- }
56- // Database sizes (simple inline - lists all databases)
57- if ( sql . includes ( "pg_database" ) && sql . includes ( "pg_database_size" ) && sql . includes ( "datistemplate" ) ) {
58- return { rows : databaseSizesRows } ;
59- }
60- // db_size metric (current database size from metrics.yml)
61- if ( sql . includes ( "pg_database_size(current_database())" ) && sql . includes ( "size_b" ) ) {
62- return { rows : [ { tag_datname : "testdb" , size_b : "1073741824" } ] } ;
63- }
64- // db_stats metric (from metrics.yml)
65- if ( sql . includes ( "pg_stat_database" ) && sql . includes ( "xact_commit" ) && sql . includes ( "pg_control_system" ) ) {
66- return { rows : dbStatsRows } ;
67- }
68- // Stats reset metric (from metrics.yml)
69- if ( sql . includes ( "stats_reset" ) && sql . includes ( "pg_stat_database" ) && sql . includes ( "seconds_since_reset" ) ) {
70- return { rows : [ {
71- tag_database_name : "testdb" ,
72- stats_reset_epoch : "1704067200" ,
73- seconds_since_reset : "2592000" // 30 days in seconds
74- } ] } ;
75- }
76- // Postmaster startup time (simple inline - used by getStatsReset)
77- if ( sql . includes ( "pg_postmaster_start_time" ) && sql . includes ( "postmaster_startup_epoch" ) ) {
78- return { rows : [ {
79- postmaster_startup_epoch : "1704067200" ,
80- postmaster_startup_time : "2024-01-01 00:00:00+00"
81- } ] } ;
82- }
83- // Connection states (simple inline)
84- if ( sql . includes ( "pg_stat_activity" ) && sql . includes ( "state" ) && sql . includes ( "group by" ) ) {
85- return { rows : connectionStatesRows } ;
86- }
87- // Uptime info (simple inline)
88- if ( sql . includes ( "pg_postmaster_start_time()" ) && sql . includes ( "uptime" ) && ! sql . includes ( "postmaster_startup_epoch" ) ) {
89- return { rows : uptimeRows } ;
90- }
91- // Invalid indexes (H001) - from metrics.yml
92- if ( sql . includes ( "indisvalid = false" ) && sql . includes ( "fk_indexes" ) ) {
93- return { rows : invalidIndexesRows } ;
94- }
95- // Unused indexes (H002) - from metrics.yml
96- if ( sql . includes ( "Never Used Indexes" ) && sql . includes ( "idx_scan = 0" ) ) {
97- return { rows : unusedIndexesRows } ;
98- }
99- // Redundant indexes (H004) - from metrics.yml
100- if ( sql . includes ( "redundant_indexes_grouped" ) && sql . includes ( "columns like" ) ) {
101- return { rows : redundantIndexesRows } ;
102- }
103- // D004: pg_stat_statements extension check
104- if ( sql . includes ( "pg_extension" ) && sql . includes ( "pg_stat_statements" ) ) {
105- return { rows : [ ] } ; // Extension not installed by default
106- }
107- // D004: pg_stat_kcache extension check
108- if ( sql . includes ( "pg_extension" ) && sql . includes ( "pg_stat_kcache" ) ) {
109- return { rows : [ ] } ; // Extension not installed by default
110- }
111- // G001: Memory settings query
112- if ( sql . includes ( "pg_size_bytes" ) && sql . includes ( "shared_buffers" ) && sql . includes ( "work_mem" ) ) {
113- return { rows : [ {
114- shared_buffers_bytes : "134217728" ,
115- wal_buffers_bytes : "4194304" ,
116- work_mem_bytes : "4194304" ,
117- maintenance_work_mem_bytes : "67108864" ,
118- effective_cache_size_bytes : "4294967296" ,
119- max_connections : 100 ,
120- } ] } ;
121- }
122- throw new Error ( `Unexpected query: ${ sql } ` ) ;
123- } ,
124- } ;
125- }
126-
12723// Unit tests for parseVersionNum
12824describe ( "parseVersionNum" , ( ) => {
12925 test ( "parses PG 16.3 version number" , ( ) => {
@@ -259,10 +155,12 @@ describe("formatBytes", () => {
259155// Mock client tests for report generators
260156describe ( "Report generators with mock client" , ( ) => {
261157 test ( "getPostgresVersion extracts version info" , async ( ) => {
262- const mockClient = createMockClient ( [
263- { name : "server_version" , setting : "16.3" } ,
264- { name : "server_version_num" , setting : "160003" } ,
265- ] , [ ] ) ;
158+ const mockClient = createMockClient ( {
159+ versionRows : [
160+ { name : "server_version" , setting : "16.3" } ,
161+ { name : "server_version_num" , setting : "160003" } ,
162+ ] ,
163+ } ) ;
266164
267165 const version = await checkup . getPostgresVersion ( mockClient as any ) ;
268166 expect ( version . version ) . toBe ( "16.3" ) ;
@@ -272,7 +170,7 @@ describe("Report generators with mock client", () => {
272170 } ) ;
273171
274172 test ( "getSettings transforms rows to keyed object" , async ( ) => {
275- const mockClient = createMockClient ( [ ] , [ ] , {
173+ const mockClient = createMockClient ( {
276174 settingsRows : [
277175 {
278176 tag_setting_name : "shared_buffers" ,
@@ -308,10 +206,12 @@ describe("Report generators with mock client", () => {
308206 } ) ;
309207
310208 test ( "generateA002 creates report with version data" , async ( ) => {
311- const mockClient = createMockClient ( [
312- { name : "server_version" , setting : "16.3" } ,
313- { name : "server_version_num" , setting : "160003" } ,
314- ] , [ ] ) ;
209+ const mockClient = createMockClient ( {
210+ versionRows : [
211+ { name : "server_version" , setting : "16.3" } ,
212+ { name : "server_version_num" , setting : "160003" } ,
213+ ] ,
214+ } ) ;
315215
316216 const report = await checkup . generateA002 ( mockClient as any , "test-node" ) ;
317217 expect ( report . checkId ) . toBe ( "A002" ) ;
@@ -323,27 +223,24 @@ describe("Report generators with mock client", () => {
323223 } ) ;
324224
325225 test ( "generateA003 creates report with settings and version" , async ( ) => {
326- const mockClient = createMockClient (
327- [
226+ const mockClient = createMockClient ( {
227+ versionRows : [
328228 { name : "server_version" , setting : "16.3" } ,
329229 { name : "server_version_num" , setting : "160003" } ,
330230 ] ,
331- [ ] ,
332- {
333- settingsRows : [
334- {
335- tag_setting_name : "shared_buffers" ,
336- tag_setting_value : "16384" ,
337- tag_unit : "8kB" ,
338- tag_category : "Resource Usage / Memory" ,
339- tag_vartype : "integer" ,
340- is_default : 1 ,
341- setting_normalized : "134217728" ,
342- unit_normalized : "bytes" ,
343- } ,
344- ] ,
345- }
346- ) ;
231+ settingsRows : [
232+ {
233+ tag_setting_name : "shared_buffers" ,
234+ tag_setting_value : "16384" ,
235+ tag_unit : "8kB" ,
236+ tag_category : "Resource Usage / Memory" ,
237+ tag_vartype : "integer" ,
238+ is_default : 1 ,
239+ setting_normalized : "134217728" ,
240+ unit_normalized : "bytes" ,
241+ } ,
242+ ] ,
243+ } ) ;
347244
348245 const report = await checkup . generateA003 ( mockClient as any , "test-node" ) ;
349246 expect ( report . checkId ) . toBe ( "A003" ) ;
@@ -355,10 +252,12 @@ describe("Report generators with mock client", () => {
355252 } ) ;
356253
357254 test ( "generateA013 creates report with minor version data" , async ( ) => {
358- const mockClient = createMockClient ( [
359- { name : "server_version" , setting : "16.3" } ,
360- { name : "server_version_num" , setting : "160003" } ,
361- ] , [ ] ) ;
255+ const mockClient = createMockClient ( {
256+ versionRows : [
257+ { name : "server_version" , setting : "16.3" } ,
258+ { name : "server_version_num" , setting : "160003" } ,
259+ ] ,
260+ } ) ;
362261
363262 const report = await checkup . generateA013 ( mockClient as any , "test-node" ) ;
364263 expect ( report . checkId ) . toBe ( "A013" ) ;
@@ -370,13 +269,11 @@ describe("Report generators with mock client", () => {
370269 } ) ;
371270
372271 test ( "generateAllReports returns reports for all checks" , async ( ) => {
373- const mockClient = createMockClient (
374- [
272+ const mockClient = createMockClient ( {
273+ versionRows : [
375274 { name : "server_version" , setting : "16.3" } ,
376275 { name : "server_version_num" , setting : "160003" } ,
377276 ] ,
378- [ ] ,
379- {
380277 settingsRows : [
381278 {
382279 tag_setting_name : "shared_buffers" ,
@@ -437,7 +334,7 @@ describe("Report generators with mock client", () => {
437334// Tests for A007 (Altered settings)
438335describe ( "A007 - Altered settings" , ( ) => {
439336 test ( "getAlteredSettings returns non-default settings" , async ( ) => {
440- const mockClient = createMockClient ( [ ] , [ ] , {
337+ const mockClient = createMockClient ( {
441338 settingsRows : [
442339 { tag_setting_name : "shared_buffers" , tag_setting_value : "256MB" , tag_unit : "" , tag_category : "Resource Usage / Memory" , tag_vartype : "string" , is_default : 0 , setting_normalized : null , unit_normalized : null } ,
443340 { tag_setting_name : "work_mem" , tag_setting_value : "64MB" , tag_unit : "" , tag_category : "Resource Usage / Memory" , tag_vartype : "string" , is_default : 0 , setting_normalized : null , unit_normalized : null } ,
@@ -454,13 +351,11 @@ describe("A007 - Altered settings", () => {
454351 } ) ;
455352
456353 test ( "generateA007 creates report with altered settings" , async ( ) => {
457- const mockClient = createMockClient (
458- [
354+ const mockClient = createMockClient ( {
355+ versionRows : [
459356 { name : "server_version" , setting : "16.3" } ,
460357 { name : "server_version_num" , setting : "160003" } ,
461358 ] ,
462- [ ] ,
463- {
464359 settingsRows : [
465360 { tag_setting_name : "max_connections" , tag_setting_value : "200" , tag_unit : "" , tag_category : "Connections and Authentication" , tag_vartype : "integer" , is_default : 0 , setting_normalized : null , unit_normalized : null } ,
466361 ] ,
@@ -481,7 +376,7 @@ describe("A007 - Altered settings", () => {
481376// Tests for A004 (Cluster information)
482377describe ( "A004 - Cluster information" , ( ) => {
483378 test ( "getDatabaseSizes returns database sizes" , async ( ) => {
484- const mockClient = createMockClient ( [ ] , [ ] , {
379+ const mockClient = createMockClient ( {
485380 databaseSizesRows : [
486381 { datname : "postgres" , size_bytes : "1073741824" } ,
487382 { datname : "mydb" , size_bytes : "536870912" } ,
@@ -496,7 +391,7 @@ describe("A004 - Cluster information", () => {
496391 } ) ;
497392
498393 test ( "getClusterInfo returns cluster metrics" , async ( ) => {
499- const mockClient = createMockClient ( [ ] , [ ] , {
394+ const mockClient = createMockClient ( {
500395 dbStatsRows : [ {
501396 numbackends : 10 ,
502397 xact_commit : 1000 ,
@@ -535,13 +430,11 @@ describe("A004 - Cluster information", () => {
535430 } ) ;
536431
537432 test ( "generateA004 creates report with cluster info and database sizes" , async ( ) => {
538- const mockClient = createMockClient (
539- [
433+ const mockClient = createMockClient ( {
434+ versionRows : [
540435 { name : "server_version" , setting : "16.3" } ,
541436 { name : "server_version_num" , setting : "160003" } ,
542437 ] ,
543- [ ] ,
544- {
545438 databaseSizesRows : [
546439 { datname : "postgres" , size_bytes : "1073741824" } ,
547440 ] ,
@@ -585,7 +478,7 @@ describe("A004 - Cluster information", () => {
585478// Tests for H001 (Invalid indexes)
586479describe ( "H001 - Invalid indexes" , ( ) => {
587480 test ( "getInvalidIndexes returns invalid indexes" , async ( ) => {
588- const mockClient = createMockClient ( [ ] , [ ] , {
481+ const mockClient = createMockClient ( {
589482 invalidIndexesRows : [
590483 { schema_name : "public" , table_name : "users" , index_name : "users_email_idx" , relation_name : "users" , index_size_bytes : "1048576" , supports_fk : false } ,
591484 ] ,
@@ -603,13 +496,11 @@ describe("H001 - Invalid indexes", () => {
603496 } ) ;
604497
605498 test ( "generateH001 creates report with invalid indexes" , async ( ) => {
606- const mockClient = createMockClient (
607- [
499+ const mockClient = createMockClient ( {
500+ versionRows : [
608501 { name : "server_version" , setting : "16.3" } ,
609502 { name : "server_version_num" , setting : "160003" } ,
610503 ] ,
611- [ ] ,
612- {
613504 invalidIndexesRows : [
614505 { schema_name : "public" , table_name : "orders" , index_name : "orders_status_idx" , relation_name : "orders" , index_size_bytes : "2097152" , supports_fk : false } ,
615506 ] ,
@@ -639,7 +530,7 @@ describe("H001 - Invalid indexes", () => {
639530// Tests for H002 (Unused indexes)
640531describe ( "H002 - Unused indexes" , ( ) => {
641532 test ( "getUnusedIndexes returns unused indexes" , async ( ) => {
642- const mockClient = createMockClient ( [ ] , [ ] , {
533+ const mockClient = createMockClient ( {
643534 unusedIndexesRows : [
644535 {
645536 schema_name : "public" ,
@@ -667,13 +558,11 @@ describe("H002 - Unused indexes", () => {
667558 } ) ;
668559
669560 test ( "generateH002 creates report with unused indexes" , async ( ) => {
670- const mockClient = createMockClient (
671- [
561+ const mockClient = createMockClient ( {
562+ versionRows : [
672563 { name : "server_version" , setting : "16.3" } ,
673564 { name : "server_version_num" , setting : "160003" } ,
674565 ] ,
675- [ ] ,
676- {
677566 unusedIndexesRows : [
678567 {
679568 schema_name : "public" ,
@@ -712,7 +601,7 @@ describe("H002 - Unused indexes", () => {
712601// Tests for H004 (Redundant indexes)
713602describe ( "H004 - Redundant indexes" , ( ) => {
714603 test ( "getRedundantIndexes returns redundant indexes" , async ( ) => {
715- const mockClient = createMockClient ( [ ] , [ ] , {
604+ const mockClient = createMockClient ( {
716605 redundantIndexesRows : [
717606 {
718607 schema_name : "public" ,
@@ -752,13 +641,11 @@ describe("H004 - Redundant indexes", () => {
752641 } ) ;
753642
754643 test ( "generateH004 creates report with redundant indexes" , async ( ) => {
755- const mockClient = createMockClient (
756- [
644+ const mockClient = createMockClient ( {
645+ versionRows : [
757646 { name : "server_version" , setting : "16.3" } ,
758647 { name : "server_version_num" , setting : "160003" } ,
759648 ] ,
760- [ ] ,
761- {
762649 redundantIndexesRows : [
763650 {
764651 schema_name : "public" ,
0 commit comments