Skip to content

Commit 1efef64

Browse files
committed
added test multi-plexing
1 parent d0e13a7 commit 1efef64

12 files changed

+1670
-32
lines changed

.yamlize/versions/14-latest.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
env:
2-
JOB: pg-14
2+
PGENV: pg-14
33
LIBPG_REPO: https://github.com/pganalyze/libpg_query.git
44
LIBPG_COMMIT: 1577ef7c6c349542149e34ffbfafc244ab942ec6
55
LIBPG_BRANCH: 14-latest

.yamlize/versions/15-latest.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
env:
2-
JOB: pg-15
2+
PGENV: pg-15
33
LIBPG_REPO: https://github.com/pganalyze/libpg_query.git
44
LIBPG_COMMIT: db39825bc7c1ddd45962ec6a626d740b7f8f027a
55
LIBPG_BRANCH: 15-latest

.yamlize/versions/16-latest.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
env:
2-
JOB: pg-16
2+
PGENV: pg-16
33
LIBPG_REPO: https://github.com/pganalyze/libpg_query.git
44
LIBPG_COMMIT: 1ec38940e5c6f09a4c1d17a46d839a881c4f2db7
55
LIBPG_BRANCH: 16-latest

package.json

+13-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"generate:workflows:no-win": "node script/generate-non-win-workflows.js",
4444
"generate:workflows": "npm run generate:workflows:win && npm run generate:workflows:no-win",
4545
"generate:build": "node script/utils/generate.js",
46-
"test": "mocha --timeout 5000",
46+
"test": "node run-tests.js",
4747
"binary:build": "node-pre-gyp rebuild package",
4848
"binary:publish": "AWS_PROFILE=supabase-dev node-pre-gyp publish"
4949
},
@@ -83,5 +83,16 @@
8383
"module_path": "./build/Release/",
8484
"host": "https://supabase-public-artifacts-bucket.s3.amazonaws.com",
8585
"remote_path": "./libpg-query-node/"
86+
},
87+
"libpgQueryConfig": {
88+
"PGENV": "pg-15",
89+
"LIBPG_REPO": "https://github.com/pganalyze/libpg_query.git",
90+
"LIBPG_COMMIT": "db39825bc7c1ddd45962ec6a626d740b7f8f027a",
91+
"LIBPG_BRANCH": "15-latest",
92+
"PGSQL_TYPES": "15.0.2",
93+
"OPERATING_SYSTEMS": [
94+
"linux",
95+
"mac"
96+
]
8697
}
87-
}
98+
}

run-tests.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const { exec } = require('child_process');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
const packagePath = path.join(__dirname, 'package.json');
6+
const package = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
7+
const pgEnv = package.libpgQueryConfig.PGENV;
8+
9+
// Construct the Mocha command
10+
const testCommand = `mocha --timeout 5000 "test/${pgEnv}.test.js"`;
11+
12+
console.log(`Running tests: ${pgEnv}`);
13+
console.log(`Executing: ${testCommand}`);
14+
15+
// Execute the Mocha command
16+
exec(testCommand, (error, stdout, stderr) => {
17+
if (error) {
18+
console.error(`Error: ${error.message}`);
19+
return;
20+
}
21+
if (stderr) {
22+
console.error(`stderr: ${stderr}`);
23+
return;
24+
}
25+
console.log(stdout);
26+
});

script/env.generated.json

-11
This file was deleted.

script/utils/generate.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ const {
1616
getTemplates
1717
} = require('./get-templates');
1818

19-
// Read the JOB from the command line arguments
20-
const jobFilter = process.argv[2];
21-
console.log({jobFilter})
19+
// Read the PGENV from the command line arguments
20+
const envFilter = process.argv[2];
21+
console.log({envFilter})
2222

23-
if (!jobFilter) {
23+
if (!envFilter) {
2424
console.error('Usage: node script.js <ENV>');
2525
console.error('ENV is PG version, e.g. pg-15');
2626
process.exit(1);
@@ -31,10 +31,10 @@ const templates = getTemplates(templatesDir);
3131
const configs = getConfig(configDir);
3232

3333
// Filter configurations based on the command line input
34-
const filteredConfigs = configs.filter(config => config.JOB === jobFilter);
34+
const filteredConfigs = configs.filter(config => config.PGENV === envFilter);
3535

3636
if (filteredConfigs.length === 0) {
37-
console.error(`No configurations found for ENV: ${jobFilter}`);
37+
console.error(`No configurations found for ENV: ${envFilter}`);
3838
process.exit(1);
3939
}
4040

@@ -52,6 +52,7 @@ const packageJsonPath = path.join(__dirname, '../../package.json');
5252
let packageJson = fs.readFileSync(packageJsonPath, 'utf8');
5353
packageJson = JSON.parse(packageJson);
5454
packageJson.dependencies['@pgsql/types'] = config.PGSQL_TYPES;
55+
packageJson.libpgQueryConfig = config;
5556
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
5657

5758
// Generate build files from the templates
@@ -66,11 +67,6 @@ templates.forEach(template => {
6667

6768
// Define the output path for the processed template
6869
const outputFile = path.join(outputDir, `${template.name}`);
69-
const generatedEnv = path.join(outputDir, `env.generated.json`);
70-
71-
// Write the processed template to the output directory
72-
fs.writeFileSync(generatedEnv, JSON.stringify(config, null, 2), 'utf8');
73-
7470

7571
// Determine the file extension
7672
const extension = path.extname(outputFile).toLowerCase();
File renamed without changes.

test/pg-15.test.js

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
const query = require("../");
2+
const { expect } = require("chai");
3+
const { omit, cloneDeepWith } = require("lodash");
4+
5+
describe("Queries", () => {
6+
describe("Sync Parsing", () => {
7+
it("should return a single-item parse result for common queries", () => {
8+
const queries = ["select 1", "select null", "select ''", "select a, b"];
9+
const results = queries.map(query.parseQuerySync);
10+
results.forEach((res) => {
11+
expect(res.stmts).to.have.lengthOf(1);
12+
});
13+
14+
// Do some rough asserting on the shape of the result.
15+
// These tests aren't really meant to test the parsing functionality
16+
// itself, but doing a bit for sanity doesn't hurt.
17+
const selectedDatas = results.map(
18+
(it) => it.stmts[0].stmt.SelectStmt.targetList
19+
);
20+
21+
expect(selectedDatas[0][0].ResTarget.val.A_Const.ival.ival).to.eq(
22+
1
23+
);
24+
expect(selectedDatas[1][0].ResTarget.val.A_Const.isnull).to.eq(
25+
true
26+
);
27+
expect(selectedDatas[2][0].ResTarget.val.A_Const.sval.sval).to.eq(
28+
""
29+
);
30+
expect(selectedDatas[3]).to.have.lengthOf(2);
31+
});
32+
33+
it("should support parsing multiple queries", () => {
34+
const res = query.parseQuerySync("select 1; select null;");
35+
const changedProps = [
36+
"stmt_len",
37+
"stmt_location",
38+
"stmt.SelectStmt.targetList[0].ResTarget.location",
39+
"stmt.SelectStmt.targetList[0].ResTarget.val.A_Const.location",
40+
];
41+
const removeChangedProps = (stmt) => omit(stmt, changedProps);
42+
expect(res.stmts.map(removeChangedProps)).to.deep.eq([
43+
...query.parseQuerySync("select 1;").stmts.map(removeChangedProps),
44+
...query.parseQuerySync("select null;").stmts.map(removeChangedProps),
45+
]);
46+
});
47+
48+
it("should not parse a bogus query", () => {
49+
expect(() => query.parseQuerySync("NOT A QUERY")).to.throw(Error);
50+
});
51+
});
52+
53+
describe("Async parsing", () => {
54+
it("should return a promise resolving to same result", async () => {
55+
const testQuery = "select * from john;";
56+
const resPromise = query.parseQuery(testQuery);
57+
const res = await resPromise;
58+
59+
expect(resPromise).to.be.instanceof(Promise);
60+
expect(res).to.deep.eq(query.parseQuerySync(testQuery));
61+
});
62+
63+
it("should reject on bogus queries", async () => {
64+
return query.parseQuery("NOT A QUERY").then(
65+
() => {
66+
throw new Error("should have rejected");
67+
},
68+
(e) => {
69+
expect(e).instanceof(Error);
70+
expect(e.message).to.match(/NOT/);
71+
}
72+
);
73+
});
74+
});
75+
76+
describe("Fingerprint", () => {
77+
context("sync", () => {
78+
it("should not fingerprint a bogus query", () => {
79+
expect(() => query.fingerprintSync("NOT A QUERY")).to.throw(Error);
80+
});
81+
82+
it("should fingerprint a query", () => {
83+
const queries = ["select 1", "select null", "select ''", "select a, b"];
84+
const results = queries.map(query.fingerprintSync);
85+
86+
results.forEach((res) => {
87+
expect(res).to.have.lengthOf(16);
88+
});
89+
});
90+
});
91+
92+
context("async", () => {
93+
it("should not fingerprint a bogus query", () => {
94+
return query.fingerprint("NOT A QUERY").then(
95+
() => {
96+
throw new Error("should have rejected");
97+
},
98+
(e) => {
99+
expect(e).instanceof(Error);
100+
expect(e.message).to.match(/NOT/);
101+
}
102+
);
103+
});
104+
105+
it("should fingerprint a query", async () => {
106+
const queries = ["select 1", "select null", "select ''", "select a, b"];
107+
const results = await Promise.all(queries.map(query.fingerprint));
108+
109+
results.forEach((res) => {
110+
expect(res).to.have.lengthOf(16);
111+
});
112+
});
113+
});
114+
});
115+
});
116+
117+
describe("PlPgSQL (async)", () => {
118+
it("should parse a function", async () => {
119+
const testFunction = `
120+
CREATE FUNCTION t() RETURNS trigger AS
121+
$BODY$
122+
DECLARE
123+
resultVal integer;
124+
finalVal integer;
125+
BEGIN
126+
resultVal = 0;
127+
IF (resultVal >= 5)
128+
THEN finalVal = 'Yes';
129+
ELSE finalVal = 'No';
130+
END IF;
131+
RETURN finalVal;
132+
END;
133+
$BODY$
134+
LANGUAGE plpgsql;
135+
`;
136+
137+
const resPromise = query.parsePlPgSQL(testFunction);
138+
const res = await resPromise;
139+
140+
expect(resPromise).to.be.instanceof(Promise);
141+
expect(res).to.deep.have.property("0.PLpgSQL_function");
142+
});
143+
});

0 commit comments

Comments
 (0)