Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions integration-tests/tests/async.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,29 @@ test.serial("Query timeout option interrupts long-running query", async (t) => {
db.close();
});

test.serial("Query timeout option interrupts long-running Statement.get()", async (t) => {
const [db, errorType] = await connect(":memory:", { defaultQueryTimeout: 100 });
const stmt = await db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

const error = await t.throwsAsync(async () => {
await stmt.get();
});
t.truthy(error);
t.true(error instanceof Error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));
t.is(error.code, "SQLITE_INTERRUPT");

db.close();
});

test.serial("Query timeout option allows short-running query", async (t) => {
const [db] = await connect(":memory:", { defaultQueryTimeout: 100 });
const stmt = await db.prepare("SELECT 1 AS value");
Expand Down Expand Up @@ -464,6 +487,57 @@ test.serial("Per-query timeout option interrupts long-running Statement.all()",
db.close();
});

test.serial("Per-query timeout option interrupts long-running Statement.get()", async (t) => {
const [db, errorType] = await connect(":memory:");
const stmt = await db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

const error = await t.throwsAsync(async () => {
await stmt.get(undefined, { queryTimeout: 100 });
});
t.truthy(error);
t.true(error instanceof Error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));
t.is(error.code, "SQLITE_INTERRUPT");

db.close();
});

test.serial("Timeout on Statement.get() does not leak into later prepare()/EXPLAIN", async (t) => {
t.timeout(30_000);
const [db, errorType] = await connect(":memory:");
const longRunningStmt = await db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

for (let i = 0; i < 20; i++) {
const error = await t.throwsAsync(async () => {
await longRunningStmt.get(undefined, { queryTimeout: 50 });
});
t.truthy(error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));

const explainStmt = await db.prepare("EXPLAIN QUERY PLAN SELECT 1");
const explainRows = await explainStmt.all();
t.true(explainRows.length > 0);
}

db.close();
});

test.serial("Per-query timeout option is accepted by Database.exec()", async (t) => {
const [db] = await connect(":memory:");
await db.exec("SELECT 1", { queryTimeout: 100 });
Expand Down
89 changes: 89 additions & 0 deletions integration-tests/tests/sync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,34 @@ test.serial("Query timeout option interrupts long-running query", async (t) => {
db.close();
});

test.serial("Query timeout option interrupts long-running Statement.get()", async (t) => {
if (t.context.provider === "sqlite") {
t.assert(true);
return;
}

const [db, errorType] = await connect(":memory:", { defaultQueryTimeout: 100 });
const stmt = db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

const error = t.throws(() => {
stmt.get();
});
t.truthy(error);
t.true(error instanceof Error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));
t.is(error.code, "SQLITE_INTERRUPT");

db.close();
});

test.serial("Query timeout option allows short-running query", async (t) => {
if (t.context.provider === "sqlite") {
t.assert(true);
Expand Down Expand Up @@ -513,6 +541,67 @@ test.serial("Per-query timeout option interrupts long-running Statement.all()",
db.close();
});

test.serial("Per-query timeout option interrupts long-running Statement.get()", async (t) => {
if (t.context.provider === "sqlite") {
t.assert(true);
return;
}

const [db, errorType] = await connect(":memory:");
const stmt = db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

const error = t.throws(() => {
stmt.get(undefined, { queryTimeout: 100 });
});
t.truthy(error);
t.true(error instanceof Error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));
t.is(error.code, "SQLITE_INTERRUPT");

db.close();
});

test.serial("Timeout on Statement.get() does not leak into later prepare()/EXPLAIN", async (t) => {
if (t.context.provider === "sqlite") {
t.assert(true);
return;
}

t.timeout(30_000);
const [db, errorType] = await connect(":memory:");
const longRunningStmt = db.prepare(`
WITH RECURSIVE numbers(value) AS (
SELECT 1
UNION ALL
SELECT value + 1 FROM numbers WHERE value < 1000000000
)
SELECT sum(value) FROM numbers;
`);

for (let i = 0; i < 20; i++) {
const error = t.throws(() => {
longRunningStmt.get(undefined, { queryTimeout: 50 });
});
t.truthy(error);
t.true(error instanceof errorType);
t.true(error.message.toLowerCase().includes("interrupt"));

const explainStmt = db.prepare("EXPLAIN QUERY PLAN SELECT 1");
const explainRows = explainStmt.all();
t.true(explainRows.length > 0);
}

db.close();
});

test.serial("Per-query timeout option is accepted by Database.exec()", async (t) => {
if (t.context.provider === "sqlite") {
t.assert(true);
Expand Down
Loading
Loading