Skip to content

Commit 31e8790

Browse files
committed
sqlite: split up large test file
The original test/parallel/test-sqlite.js test appears to time out in the CI occasionally. This commit splits the test into several smaller test files. Fixes: #54006
1 parent 277ed9f commit 31e8790

7 files changed

+732
-665
lines changed

test/parallel/parallel.status

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ test-fs-read-stream-concurrent-reads: PASS, FLAKY
1919
# https://github.com/nodejs/node/issues/52630
2020
test-error-serdes: PASS, FLAKY
2121

22-
# https://github.com/nodejs/node/issues/54006
23-
test-sqlite: PASS, FLAKY
24-
2522
[$system==win32]
2623

2724
# Windows on ARM
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Flags: --experimental-sqlite
2+
'use strict';
3+
require('../common');
4+
const tmpdir = require('../common/tmpdir');
5+
const { join } = require('node:path');
6+
const { DatabaseSync } = require('node:sqlite');
7+
const { suite, test } = require('node:test');
8+
let cnt = 0;
9+
10+
tmpdir.refresh();
11+
12+
function nextDb() {
13+
return join(tmpdir.path, `database-${cnt++}.db`);
14+
}
15+
16+
suite('data binding and mapping', () => {
17+
test('supported data types', (t) => {
18+
const u8a = new TextEncoder().encode('a☃b☃c');
19+
const db = new DatabaseSync(nextDb());
20+
const setup = db.exec(`
21+
CREATE TABLE types(
22+
key INTEGER PRIMARY KEY,
23+
int INTEGER,
24+
double REAL,
25+
text TEXT,
26+
buf BLOB
27+
) STRICT;
28+
`);
29+
t.assert.strictEqual(setup, undefined);
30+
const stmt = db.prepare('INSERT INTO types (key, int, double, text, buf) ' +
31+
'VALUES (?, ?, ?, ?, ?)');
32+
t.assert.deepStrictEqual(
33+
stmt.run(1, 42, 3.14159, 'foo', u8a),
34+
{ changes: 1, lastInsertRowid: 1 },
35+
);
36+
t.assert.deepStrictEqual(
37+
stmt.run(2, null, null, null, null),
38+
{ changes: 1, lastInsertRowid: 2 }
39+
);
40+
t.assert.deepStrictEqual(
41+
stmt.run(3, Number(8), Number(2.718), String('bar'), Buffer.from('x☃y☃')),
42+
{ changes: 1, lastInsertRowid: 3 },
43+
);
44+
t.assert.deepStrictEqual(
45+
stmt.run(4, 99n, 0xf, '', new Uint8Array()),
46+
{ changes: 1, lastInsertRowid: 4 },
47+
);
48+
49+
const query = db.prepare('SELECT * FROM types WHERE key = ?');
50+
t.assert.deepStrictEqual(query.get(1), {
51+
key: 1,
52+
int: 42,
53+
double: 3.14159,
54+
text: 'foo',
55+
buf: u8a,
56+
});
57+
t.assert.deepStrictEqual(query.get(2), {
58+
key: 2,
59+
int: null,
60+
double: null,
61+
text: null,
62+
buf: null,
63+
});
64+
t.assert.deepStrictEqual(query.get(3), {
65+
key: 3,
66+
int: 8,
67+
double: 2.718,
68+
text: 'bar',
69+
buf: new TextEncoder().encode('x☃y☃'),
70+
});
71+
t.assert.deepStrictEqual(query.get(4), {
72+
key: 4,
73+
int: 99,
74+
double: 0xf,
75+
text: '',
76+
buf: new Uint8Array(),
77+
});
78+
});
79+
80+
test('unsupported data types', (t) => {
81+
const db = new DatabaseSync(nextDb());
82+
const setup = db.exec(
83+
'CREATE TABLE types(key INTEGER PRIMARY KEY, val INTEGER) STRICT;'
84+
);
85+
t.assert.strictEqual(setup, undefined);
86+
87+
[
88+
undefined,
89+
() => {},
90+
Symbol(),
91+
/foo/,
92+
Promise.resolve(),
93+
new Map(),
94+
new Set(),
95+
].forEach((val) => {
96+
t.assert.throws(() => {
97+
db.prepare('INSERT INTO types (key, val) VALUES (?, ?)').run(1, val);
98+
}, {
99+
code: 'ERR_INVALID_ARG_TYPE',
100+
message: /Provided value cannot be bound to SQLite parameter 2/,
101+
});
102+
});
103+
104+
t.assert.throws(() => {
105+
const stmt = db.prepare('INSERT INTO types (key, val) VALUES ($k, $v)');
106+
stmt.run({ $k: 1, $v: () => {} });
107+
}, {
108+
code: 'ERR_INVALID_ARG_TYPE',
109+
message: /Provided value cannot be bound to SQLite parameter 2/,
110+
});
111+
});
112+
113+
test('throws when binding a BigInt that is too large', (t) => {
114+
const max = 9223372036854775807n; // Largest 64-bit signed integer value.
115+
const db = new DatabaseSync(nextDb());
116+
const setup = db.exec(
117+
'CREATE TABLE types(key INTEGER PRIMARY KEY, val INTEGER) STRICT;'
118+
);
119+
t.assert.strictEqual(setup, undefined);
120+
const stmt = db.prepare('INSERT INTO types (key, val) VALUES (?, ?)');
121+
t.assert.deepStrictEqual(
122+
stmt.run(1, max),
123+
{ changes: 1, lastInsertRowid: 1 },
124+
);
125+
t.assert.throws(() => {
126+
stmt.run(1, max + 1n);
127+
}, {
128+
code: 'ERR_INVALID_ARG_VALUE',
129+
message: /BigInt value is too large to bind/,
130+
});
131+
});
132+
133+
test('statements are unbound on each call', (t) => {
134+
const db = new DatabaseSync(nextDb());
135+
const setup = db.exec(
136+
'CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;'
137+
);
138+
t.assert.strictEqual(setup, undefined);
139+
const stmt = db.prepare('INSERT INTO data (key, val) VALUES (?, ?)');
140+
t.assert.deepStrictEqual(
141+
stmt.run(1, 5),
142+
{ changes: 1, lastInsertRowid: 1 },
143+
);
144+
t.assert.deepStrictEqual(
145+
stmt.run(),
146+
{ changes: 1, lastInsertRowid: 2 },
147+
);
148+
t.assert.deepStrictEqual(
149+
db.prepare('SELECT * FROM data ORDER BY key').all(),
150+
[{ key: 1, val: 5 }, { key: 2, val: null }],
151+
);
152+
});
153+
});
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Flags: --experimental-sqlite
2+
'use strict';
3+
require('../common');
4+
const tmpdir = require('../common/tmpdir');
5+
const { existsSync } = require('node:fs');
6+
const { join } = require('node:path');
7+
const { DatabaseSync, StatementSync } = require('node:sqlite');
8+
const { suite, test } = require('node:test');
9+
let cnt = 0;
10+
11+
tmpdir.refresh();
12+
13+
function nextDb() {
14+
return join(tmpdir.path, `database-${cnt++}.db`);
15+
}
16+
17+
suite('DatabaseSync() constructor', () => {
18+
test('throws if called without new', (t) => {
19+
t.assert.throws(() => {
20+
DatabaseSync();
21+
}, {
22+
code: 'ERR_CONSTRUCT_CALL_REQUIRED',
23+
message: /Cannot call constructor without `new`/,
24+
});
25+
});
26+
27+
test('throws if database path is not a string', (t) => {
28+
t.assert.throws(() => {
29+
new DatabaseSync();
30+
}, {
31+
code: 'ERR_INVALID_ARG_TYPE',
32+
message: /The "path" argument must be a string/,
33+
});
34+
});
35+
36+
test('throws if options is provided but is not an object', (t) => {
37+
t.assert.throws(() => {
38+
new DatabaseSync('foo', null);
39+
}, {
40+
code: 'ERR_INVALID_ARG_TYPE',
41+
message: /The "options" argument must be an object/,
42+
});
43+
});
44+
45+
test('throws if options.open is provided but is not a boolean', (t) => {
46+
t.assert.throws(() => {
47+
new DatabaseSync('foo', { open: 5 });
48+
}, {
49+
code: 'ERR_INVALID_ARG_TYPE',
50+
message: /The "options\.open" argument must be a boolean/,
51+
});
52+
});
53+
});
54+
55+
suite('DatabaseSync.prototype.open()', () => {
56+
test('opens a database connection', (t) => {
57+
const dbPath = nextDb();
58+
const db = new DatabaseSync(dbPath, { open: false });
59+
60+
t.assert.strictEqual(existsSync(dbPath), false);
61+
t.assert.strictEqual(db.open(), undefined);
62+
t.assert.strictEqual(existsSync(dbPath), true);
63+
});
64+
65+
test('throws if database is already open', (t) => {
66+
const db = new DatabaseSync(nextDb(), { open: false });
67+
68+
db.open();
69+
t.assert.throws(() => {
70+
db.open();
71+
}, {
72+
code: 'ERR_INVALID_STATE',
73+
message: /database is already open/,
74+
});
75+
});
76+
});
77+
78+
suite('DatabaseSync.prototype.close()', () => {
79+
test('closes an open database connection', (t) => {
80+
const db = new DatabaseSync(nextDb());
81+
82+
t.assert.strictEqual(db.close(), undefined);
83+
});
84+
85+
test('throws if database is not open', (t) => {
86+
const db = new DatabaseSync(nextDb(), { open: false });
87+
88+
t.assert.throws(() => {
89+
db.close();
90+
}, {
91+
code: 'ERR_INVALID_STATE',
92+
message: /database is not open/,
93+
});
94+
});
95+
});
96+
97+
suite('DatabaseSync.prototype.prepare()', () => {
98+
test('returns a prepared statement', (t) => {
99+
const db = new DatabaseSync(nextDb());
100+
const stmt = db.prepare('CREATE TABLE webstorage(key TEXT)');
101+
t.assert.ok(stmt instanceof StatementSync);
102+
});
103+
104+
test('throws if database is not open', (t) => {
105+
const db = new DatabaseSync(nextDb(), { open: false });
106+
107+
t.assert.throws(() => {
108+
db.prepare();
109+
}, {
110+
code: 'ERR_INVALID_STATE',
111+
message: /database is not open/,
112+
});
113+
});
114+
115+
test('throws if sql is not a string', (t) => {
116+
const db = new DatabaseSync(nextDb());
117+
118+
t.assert.throws(() => {
119+
db.prepare();
120+
}, {
121+
code: 'ERR_INVALID_ARG_TYPE',
122+
message: /The "sql" argument must be a string/,
123+
});
124+
});
125+
});
126+
127+
suite('DatabaseSync.prototype.exec()', () => {
128+
test('executes SQL', (t) => {
129+
const db = new DatabaseSync(nextDb());
130+
const result = db.exec(`
131+
CREATE TABLE data(
132+
key INTEGER PRIMARY KEY,
133+
val INTEGER
134+
) STRICT;
135+
INSERT INTO data (key, val) VALUES (1, 2);
136+
INSERT INTO data (key, val) VALUES (8, 9);
137+
`);
138+
t.assert.strictEqual(result, undefined);
139+
const stmt = db.prepare('SELECT * FROM data ORDER BY key');
140+
t.assert.deepStrictEqual(stmt.all(), [
141+
{ key: 1, val: 2 },
142+
{ key: 8, val: 9 },
143+
]);
144+
});
145+
146+
test('reports errors from SQLite', (t) => {
147+
const db = new DatabaseSync(nextDb());
148+
149+
t.assert.throws(() => {
150+
db.exec('CREATE TABLEEEE');
151+
}, {
152+
code: 'ERR_SQLITE_ERROR',
153+
message: /syntax error/,
154+
});
155+
});
156+
157+
test('throws if database is not open', (t) => {
158+
const db = new DatabaseSync(nextDb(), { open: false });
159+
160+
t.assert.throws(() => {
161+
db.exec();
162+
}, {
163+
code: 'ERR_INVALID_STATE',
164+
message: /database is not open/,
165+
});
166+
});
167+
168+
test('throws if sql is not a string', (t) => {
169+
const db = new DatabaseSync(nextDb());
170+
171+
t.assert.throws(() => {
172+
db.exec();
173+
}, {
174+
code: 'ERR_INVALID_ARG_TYPE',
175+
message: /The "sql" argument must be a string/,
176+
});
177+
});
178+
});

0 commit comments

Comments
 (0)