pgsql-test 2.18.3 → 2.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/stream.js +58 -5
- package/package.json +4 -4
- package/stream.d.ts +31 -0
- package/stream.js +58 -5
package/esm/stream.js
CHANGED
|
@@ -22,22 +22,75 @@ function stringToStream(text) {
|
|
|
22
22
|
});
|
|
23
23
|
return stream;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Executes SQL statements by streaming them to psql.
|
|
27
|
+
*
|
|
28
|
+
* IMPORTANT: PostgreSQL stderr handling
|
|
29
|
+
* -------------------------------------
|
|
30
|
+
* PostgreSQL sends different message types to stderr, not just errors:
|
|
31
|
+
* - ERROR: Actual SQL errors (should fail)
|
|
32
|
+
* - WARNING: Potential issues (informational)
|
|
33
|
+
* - NOTICE: Informational messages (should NOT fail)
|
|
34
|
+
* - INFO: Informational messages (should NOT fail)
|
|
35
|
+
* - DEBUG: Debug messages (should NOT fail)
|
|
36
|
+
*
|
|
37
|
+
* Example scenario that previously caused false failures:
|
|
38
|
+
* When running SQL like:
|
|
39
|
+
* GRANT administrator TO app_user;
|
|
40
|
+
*
|
|
41
|
+
* If app_user is already a member of administrator, PostgreSQL outputs:
|
|
42
|
+
* NOTICE: role "app_user" is already a member of role "administrator"
|
|
43
|
+
*
|
|
44
|
+
* This is NOT an error - the GRANT succeeded (it's idempotent). But because
|
|
45
|
+
* this message goes to stderr, the old implementation would reject the promise
|
|
46
|
+
* and fail the test, even though nothing was wrong.
|
|
47
|
+
*
|
|
48
|
+
* Solution:
|
|
49
|
+
* 1. Buffer stderr instead of rejecting immediately on any output
|
|
50
|
+
* 2. Use ON_ERROR_STOP=1 so psql exits with non-zero code on actual SQL errors
|
|
51
|
+
* 3. Only reject if the exit code is non-zero, using buffered stderr as the error message
|
|
52
|
+
*
|
|
53
|
+
* This way, NOTICE/WARNING messages are collected but don't cause failures,
|
|
54
|
+
* while actual SQL errors still properly fail with meaningful error messages.
|
|
55
|
+
*/
|
|
25
56
|
export async function streamSql(config, sql) {
|
|
26
|
-
const args =
|
|
57
|
+
const args = [
|
|
58
|
+
...setArgs(config),
|
|
59
|
+
// ON_ERROR_STOP=1 makes psql exit with a non-zero code when it encounters
|
|
60
|
+
// an actual SQL error. Without this, psql might continue executing subsequent
|
|
61
|
+
// statements and exit with code 0 even if some statements failed.
|
|
62
|
+
'-v', 'ON_ERROR_STOP=1'
|
|
63
|
+
];
|
|
27
64
|
return new Promise((resolve, reject) => {
|
|
28
65
|
const sqlStream = stringToStream(sql);
|
|
66
|
+
// Buffer stderr instead of rejecting immediately. This allows us to collect
|
|
67
|
+
// all output (including harmless NOTICE messages) and only use it for error
|
|
68
|
+
// reporting if the process actually fails.
|
|
69
|
+
let stderrBuffer = '';
|
|
29
70
|
const proc = spawn('psql', args, {
|
|
30
71
|
env: getSpawnEnvWithPg(config)
|
|
31
72
|
});
|
|
32
73
|
sqlStream.pipe(proc.stdin);
|
|
74
|
+
// Collect stderr output. We don't reject here because stderr may contain
|
|
75
|
+
// harmless NOTICE/WARNING messages that shouldn't cause test failures.
|
|
76
|
+
proc.stderr.on('data', (data) => {
|
|
77
|
+
stderrBuffer += data.toString();
|
|
78
|
+
});
|
|
79
|
+
// Determine success/failure based on exit code, not stderr content.
|
|
80
|
+
// Exit code 0 = success (even if there were NOTICE messages on stderr)
|
|
81
|
+
// Exit code non-zero = actual error occurred
|
|
33
82
|
proc.on('close', (code) => {
|
|
34
|
-
|
|
83
|
+
if (code !== 0) {
|
|
84
|
+
// Include the buffered stderr in the error message for debugging
|
|
85
|
+
reject(new Error(stderrBuffer || `psql exited with code ${code}`));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
resolve();
|
|
89
|
+
}
|
|
35
90
|
});
|
|
91
|
+
// Handle spawn errors (e.g., psql not found)
|
|
36
92
|
proc.on('error', (error) => {
|
|
37
93
|
reject(error);
|
|
38
94
|
});
|
|
39
|
-
proc.stderr.on('data', (data) => {
|
|
40
|
-
reject(new Error(data.toString()));
|
|
41
|
-
});
|
|
42
95
|
});
|
|
43
96
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgsql-test",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.5",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "pgsql-test offers isolated, role-aware, and rollback-friendly PostgreSQL environments for integration tests — giving developers realistic test coverage without external state pollution",
|
|
6
6
|
"main": "index.js",
|
|
@@ -60,16 +60,16 @@
|
|
|
60
60
|
"makage": "^0.1.9"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@pgpmjs/core": "^3.1.
|
|
63
|
+
"@pgpmjs/core": "^3.1.4",
|
|
64
64
|
"@pgpmjs/env": "^2.8.8",
|
|
65
65
|
"@pgpmjs/logger": "^1.3.5",
|
|
66
66
|
"@pgpmjs/server-utils": "^2.8.8",
|
|
67
67
|
"@pgpmjs/types": "^2.12.6",
|
|
68
68
|
"csv-parse": "^6.1.0",
|
|
69
69
|
"pg": "^8.16.3",
|
|
70
|
-
"pg-cache": "^1.6.
|
|
70
|
+
"pg-cache": "^1.6.9",
|
|
71
71
|
"pg-copy-streams": "^7.0.0",
|
|
72
72
|
"pg-env": "^1.2.4"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "c61d285656df312ee59fdf2659e63cbaadff2370"
|
|
75
75
|
}
|
package/stream.d.ts
CHANGED
|
@@ -1,2 +1,33 @@
|
|
|
1
1
|
import { PgConfig } from 'pg-env';
|
|
2
|
+
/**
|
|
3
|
+
* Executes SQL statements by streaming them to psql.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: PostgreSQL stderr handling
|
|
6
|
+
* -------------------------------------
|
|
7
|
+
* PostgreSQL sends different message types to stderr, not just errors:
|
|
8
|
+
* - ERROR: Actual SQL errors (should fail)
|
|
9
|
+
* - WARNING: Potential issues (informational)
|
|
10
|
+
* - NOTICE: Informational messages (should NOT fail)
|
|
11
|
+
* - INFO: Informational messages (should NOT fail)
|
|
12
|
+
* - DEBUG: Debug messages (should NOT fail)
|
|
13
|
+
*
|
|
14
|
+
* Example scenario that previously caused false failures:
|
|
15
|
+
* When running SQL like:
|
|
16
|
+
* GRANT administrator TO app_user;
|
|
17
|
+
*
|
|
18
|
+
* If app_user is already a member of administrator, PostgreSQL outputs:
|
|
19
|
+
* NOTICE: role "app_user" is already a member of role "administrator"
|
|
20
|
+
*
|
|
21
|
+
* This is NOT an error - the GRANT succeeded (it's idempotent). But because
|
|
22
|
+
* this message goes to stderr, the old implementation would reject the promise
|
|
23
|
+
* and fail the test, even though nothing was wrong.
|
|
24
|
+
*
|
|
25
|
+
* Solution:
|
|
26
|
+
* 1. Buffer stderr instead of rejecting immediately on any output
|
|
27
|
+
* 2. Use ON_ERROR_STOP=1 so psql exits with non-zero code on actual SQL errors
|
|
28
|
+
* 3. Only reject if the exit code is non-zero, using buffered stderr as the error message
|
|
29
|
+
*
|
|
30
|
+
* This way, NOTICE/WARNING messages are collected but don't cause failures,
|
|
31
|
+
* while actual SQL errors still properly fail with meaningful error messages.
|
|
32
|
+
*/
|
|
2
33
|
export declare function streamSql(config: PgConfig, sql: string): Promise<void>;
|
package/stream.js
CHANGED
|
@@ -25,22 +25,75 @@ function stringToStream(text) {
|
|
|
25
25
|
});
|
|
26
26
|
return stream;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Executes SQL statements by streaming them to psql.
|
|
30
|
+
*
|
|
31
|
+
* IMPORTANT: PostgreSQL stderr handling
|
|
32
|
+
* -------------------------------------
|
|
33
|
+
* PostgreSQL sends different message types to stderr, not just errors:
|
|
34
|
+
* - ERROR: Actual SQL errors (should fail)
|
|
35
|
+
* - WARNING: Potential issues (informational)
|
|
36
|
+
* - NOTICE: Informational messages (should NOT fail)
|
|
37
|
+
* - INFO: Informational messages (should NOT fail)
|
|
38
|
+
* - DEBUG: Debug messages (should NOT fail)
|
|
39
|
+
*
|
|
40
|
+
* Example scenario that previously caused false failures:
|
|
41
|
+
* When running SQL like:
|
|
42
|
+
* GRANT administrator TO app_user;
|
|
43
|
+
*
|
|
44
|
+
* If app_user is already a member of administrator, PostgreSQL outputs:
|
|
45
|
+
* NOTICE: role "app_user" is already a member of role "administrator"
|
|
46
|
+
*
|
|
47
|
+
* This is NOT an error - the GRANT succeeded (it's idempotent). But because
|
|
48
|
+
* this message goes to stderr, the old implementation would reject the promise
|
|
49
|
+
* and fail the test, even though nothing was wrong.
|
|
50
|
+
*
|
|
51
|
+
* Solution:
|
|
52
|
+
* 1. Buffer stderr instead of rejecting immediately on any output
|
|
53
|
+
* 2. Use ON_ERROR_STOP=1 so psql exits with non-zero code on actual SQL errors
|
|
54
|
+
* 3. Only reject if the exit code is non-zero, using buffered stderr as the error message
|
|
55
|
+
*
|
|
56
|
+
* This way, NOTICE/WARNING messages are collected but don't cause failures,
|
|
57
|
+
* while actual SQL errors still properly fail with meaningful error messages.
|
|
58
|
+
*/
|
|
28
59
|
async function streamSql(config, sql) {
|
|
29
|
-
const args =
|
|
60
|
+
const args = [
|
|
61
|
+
...setArgs(config),
|
|
62
|
+
// ON_ERROR_STOP=1 makes psql exit with a non-zero code when it encounters
|
|
63
|
+
// an actual SQL error. Without this, psql might continue executing subsequent
|
|
64
|
+
// statements and exit with code 0 even if some statements failed.
|
|
65
|
+
'-v', 'ON_ERROR_STOP=1'
|
|
66
|
+
];
|
|
30
67
|
return new Promise((resolve, reject) => {
|
|
31
68
|
const sqlStream = stringToStream(sql);
|
|
69
|
+
// Buffer stderr instead of rejecting immediately. This allows us to collect
|
|
70
|
+
// all output (including harmless NOTICE messages) and only use it for error
|
|
71
|
+
// reporting if the process actually fails.
|
|
72
|
+
let stderrBuffer = '';
|
|
32
73
|
const proc = (0, child_process_1.spawn)('psql', args, {
|
|
33
74
|
env: (0, pg_env_1.getSpawnEnvWithPg)(config)
|
|
34
75
|
});
|
|
35
76
|
sqlStream.pipe(proc.stdin);
|
|
77
|
+
// Collect stderr output. We don't reject here because stderr may contain
|
|
78
|
+
// harmless NOTICE/WARNING messages that shouldn't cause test failures.
|
|
79
|
+
proc.stderr.on('data', (data) => {
|
|
80
|
+
stderrBuffer += data.toString();
|
|
81
|
+
});
|
|
82
|
+
// Determine success/failure based on exit code, not stderr content.
|
|
83
|
+
// Exit code 0 = success (even if there were NOTICE messages on stderr)
|
|
84
|
+
// Exit code non-zero = actual error occurred
|
|
36
85
|
proc.on('close', (code) => {
|
|
37
|
-
|
|
86
|
+
if (code !== 0) {
|
|
87
|
+
// Include the buffered stderr in the error message for debugging
|
|
88
|
+
reject(new Error(stderrBuffer || `psql exited with code ${code}`));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
resolve();
|
|
92
|
+
}
|
|
38
93
|
});
|
|
94
|
+
// Handle spawn errors (e.g., psql not found)
|
|
39
95
|
proc.on('error', (error) => {
|
|
40
96
|
reject(error);
|
|
41
97
|
});
|
|
42
|
-
proc.stderr.on('data', (data) => {
|
|
43
|
-
reject(new Error(data.toString()));
|
|
44
|
-
});
|
|
45
98
|
});
|
|
46
99
|
}
|