Skip to content
Merged
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
17 changes: 16 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,22 @@
"no-dupe-keys": "off",
"unicorn/no-useless-spread": "off",
"unicorn/no-invalid-fetch-options": "off",
"oxc/const-comparisons": "off"
"oxc/const-comparisons": "off",
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "node:assert/strict",
"message": "Use plain node:assert; call assert.strictEqual/deepStrictEqual for strict checks (AGENTS.md test style)."
},
{
"name": "assert/strict",
"message": "Use plain node:assert; call assert.strictEqual/deepStrictEqual for strict checks (AGENTS.md test style)."
}
]
}
]
},
"settings": {
"jsdoc": {
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,4 @@ source tree — which permanently shadows git's config file. Every subsequent ag
- `contextStorage` (AsyncLocalStorage) carries per-request context (user, transaction) across async boundaries — this is how authorization and transactions work without explicit parameter threading.
- Tests under `unitTests/apiTests/` require the server to be stopped first (`node ./dist/bin/harper.js stop`) — `test:unit:apitests` does this automatically.
- `@export` annotation on a schema class auto-generates a REST API for that table — this is the primary developer-facing API.
- Test style: write new unit tests with `assert` (the bare `node:assert` module) against real modules — **do not add new uses of `sinon` or `rewire`**. Use plain `assert`, **not** `node:assert/strict` — strict mode's deep-equality and coercion rules cause more friction and surprising failures than they prevent; plain `assert` is the house style. Older tests in `unitTests/security/` and `unitTests/utility/` still depend on them but they are not the target shape; match newer tests in `unitTests/config/*`, `unitTests/resources/*`, `unitTests/components/*`. If you can't write a test without stubbing, comment on the issue describing what's missing and stop — don't reach for sinon/rewire as a shortcut.
- Test style: write new unit tests with `assert` (the bare `node:assert` module) against real modules — **do not add new uses of `sinon` or `rewire`**. Use plain `assert`, **not** `node:assert/strict` — strict mode's deep-equality and coercion rules cause more friction and surprising failures than they prevent; plain `assert` is the house style. When a specific check genuinely needs strict/deep-strict semantics, call `assert.strictEqual`/`assert.deepStrictEqual` explicitly (both exist on plain `assert`) rather than importing `/strict`. This is lint-enforced: oxlint's `no-restricted-imports` rule rejects `node:assert/strict` and `assert/strict` imports. Older tests in `unitTests/security/` and `unitTests/utility/` still depend on them but they are not the target shape; match newer tests in `unitTests/config/*`, `unitTests/resources/*`, `unitTests/components/*`. If you can't write a test without stubbing, comment on the issue describing what's missing and stop — don't reach for sinon/rewire as a shortcut.
2 changes: 1 addition & 1 deletion benchmarks/ycsb/harness.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* node --test benchmarks/ycsb/
*/
import { test } from 'node:test';
import { strictEqual } from 'node:assert/strict';
import { strictEqual } from 'node:assert';
import { medianByThroughput, parseOptions } from './harness.mts';
import type { PhaseResult } from './workload.mts';

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/ycsb/to-benchmark-json.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* node --test benchmarks/ycsb/
*/
import { test } from 'node:test';
import { strictEqual, deepStrictEqual } from 'node:assert/strict';
import { strictEqual, deepStrictEqual } from 'node:assert';
import { convert, type Results } from './to-benchmark-json.mts';

const latency = { read: { p50: 1, p99: 2 } };
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/ycsb/workload.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* key model, latency stats). Run standalone with: node --test benchmarks/ycsb/
*/
import { test } from 'node:test';
import { strictEqual, ok } from 'node:assert/strict';
import { strictEqual, ok } from 'node:assert';
import {
WORKLOADS,
makeKeyChooser,
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/alter-user.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* minimum schema/tables that the role's permission map references.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';

Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/authentication.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* Harper-on-Bun instead of a graceful 401. Tracked in issue #696.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/blob.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* under Harper-on-Bun in CI.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import path from 'node:path';
import os from 'node:os';
import fs from 'fs-extra';
Expand Down
6 changes: 3 additions & 3 deletions integrationTests/apiTests/components.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Skipped on Bun: component restarts are not reliable under Harper-on-Bun in CI.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { setTimeout } from 'node:timers/promises';
Expand Down Expand Up @@ -367,9 +367,9 @@ suite('Component lifecycle', { skip: skipSuite }, (ctx) => {
.send({ operation: 'get_custom_functions' })
.expect((r) => {
assert.ok(r.body.hasOwnProperty('test-deploy'), r.text);
assert.notEqual(r.body['test-deploy']['routes'], undefined, r.text);
assert.notStrictEqual(r.body['test-deploy']['routes'], undefined, r.text);
assert.equal(r.body['test-deploy']['routes'][0], 'examples', r.text);
assert.notEqual(r.body['test-deploy']['helpers'], undefined, r.text);
assert.notStrictEqual(r.body['test-deploy']['helpers'], undefined, r.text);
assert.equal(r.body['test-deploy']['helpers'][0], 'example', r.text);
})
.expect(200);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* (HarperFast/harper#549).
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/configuration.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* its `owner_id` attribute are created inline by the tests themselves.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/delete.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* delete tests.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* the cluster topology that hid the bug.
*/
import { suite, test, before, after } from 'node:test';
import { ok, strictEqual } from 'node:assert/strict';
import { ok, strictEqual } from 'node:assert';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/graphql.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* (HarperFast/harper#549).
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
import { installAppComponent } from './utils/components.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/headers.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* with a local fixture but ultimately depends on the same restart path.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
import { restartHttpWorkers } from './utils/lifecycle.mjs';
Expand Down
16 changes: 8 additions & 8 deletions integrationTests/apiTests/northwind.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Skipped on Windows: csv_file_load uses Linux-style absolute paths.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -2167,7 +2167,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
const job = jobResp.body[0];
assert.ok(job, `No job found in response: ${jobResp.text}`);
if (_expectedError) {
assert.notEqual(job.status, 'COMPLETE', jobResp.text);
assert.notStrictEqual(job.status, 'COMPLETE', jobResp.text);
const msgStr = typeof job.message === 'string' ? job.message : JSON.stringify(job.message);
assert.ok(msgStr.includes(_expectedError), jobResp.text);
} else {
Expand Down Expand Up @@ -2229,7 +2229,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
const job = jobResp.body[0];
assert.ok(job, `No job found in response: ${jobResp.text}`);
if (expectedErrorMsg) {
assert.notEqual(job.status, 'COMPLETE', jobResp.text);
assert.notStrictEqual(job.status, 'COMPLETE', jobResp.text);
const msgStr = typeof job.message === 'string' ? job.message : JSON.stringify(job.message);
assert.ok(msgStr.includes(expectedErrorMsg), jobResp.text);
} else {
Expand Down Expand Up @@ -2546,7 +2546,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
})
.expect((r) => {
let randomNumber = Math.floor(Math.random() * 29);
assert.notEqual(r.body[randomNumber], null, r.text);
assert.notStrictEqual(r.body[randomNumber], null, r.text);
assert.equal(r.body.length, 29, r.text);
let keys = Object.keys(r.body[randomNumber]);
if (keys.indexOf('__updatedtime__') > -1 && keys.indexOf('__createdtime__') > -1) {
Expand Down Expand Up @@ -4607,7 +4607,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
await client
.req()
.send({ operation: 'sql', sql: "SELECT __createdtime__ FROM northnwd.customers WHERE customerid = 'TEST3'" })
.expect((r) => assert.notEqual(r.body[0].__createdtime__, 'bad value', r.text))
.expect((r) => assert.notStrictEqual(r.body[0].__createdtime__, 'bad value', r.text))
.expect(200);
});

Expand Down Expand Up @@ -4960,7 +4960,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
const keys = Object.keys(row);
assert.equal(keys.length, 16, r.text);
Object.keys(row).forEach((key) => {
assert.notEqual(row[key], undefined, r.text);
assert.notStrictEqual(row[key], undefined, r.text);
});
});
})
Expand All @@ -4980,7 +4980,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
const keys = Object.keys(row);
assert.equal(keys.length, 11, r.text);
Object.keys(row).forEach((key) => {
assert.notEqual(row[key], undefined, r.text);
assert.notStrictEqual(row[key], undefined, r.text);
});
});
})
Expand Down Expand Up @@ -7526,7 +7526,7 @@ suite('Northwind operations', { skip: skipSuite }, (ctx) => {
get_attributes: [`employeeid`, '__createdtime__'],
})
.expect((r) => assert.equal(r.body[0].employeeid, 1, r.text))
.expect((r) => assert.notEqual(r.body[0].__createdtime__, 'bad value', r.text))
.expect((r) => assert.notStrictEqual(r.body[0].__createdtime__, 'bad value', r.text))
.expect(200);
});

Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/open-api.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* (HarperFast/harper#549).
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
import { installAppComponent } from './utils/components.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/param-routes.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* Covers HarperFast/harper#602.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
import { installAppComponent } from './utils/components.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/rest.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* `headers.test.mjs`.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/schema-enforcement.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* single-worker model (HarperFast/harper#549).
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
4 changes: 2 additions & 2 deletions integrationTests/apiTests/system-information.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* hermetic, and safe to run concurrently with other test files.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';

Expand All @@ -27,7 +27,7 @@ suite('System Information', (ctx) => {
const response = await client.req().send({ operation: 'system_information' }).expect(200);
const attributes = ['system', 'time', 'cpu', 'memory', 'disk', 'network', 'harperdb_processes', 'table_size'];
for (const attribute of attributes) {
assert.notEqual(response.body[attribute], undefined, `missing attribute "${attribute}": ${response.text}`);
assert.notStrictEqual(response.body[attribute], undefined, `missing attribute "${attribute}": ${response.text}`);
}
});

Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/terminology.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* S3 and csv_url_load tests are skipped (require external infrastructure).
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
Expand Down
14 changes: 7 additions & 7 deletions integrationTests/apiTests/token-auth.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* indefinitely under Harper-on-Bun. Tracked in issue #697.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import request from 'supertest';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down Expand Up @@ -80,7 +80,7 @@ suite('Token authentication', (ctx) => {
if (authorizeLocal) {
// Loopback caller is auto-authorized → mints a token.
assert.equal(r.status, 200, r.text);
assert.notEqual(r.body.operation_token, undefined, r.text);
assert.notStrictEqual(r.body.operation_token, undefined, r.text);
} else {
assert.equal(r.status, 401, r.text);
assert.equal(r.body.error, 'Must login', r.text);
Expand Down Expand Up @@ -121,8 +121,8 @@ suite('Token authentication', (ctx) => {
})
.expect(200);

assert.notEqual(response.body.operation_token, undefined, response.text);
assert.notEqual(response.body.refresh_token, undefined, response.text);
assert.notStrictEqual(response.body.operation_token, undefined, response.text);
assert.notStrictEqual(response.body.refresh_token, undefined, response.text);
operationToken = response.body.operation_token;
refreshToken = response.body.refresh_token;
});
Expand Down Expand Up @@ -173,7 +173,7 @@ suite('Token authentication', (ctx) => {
.send({ operation: 'refresh_operation_token' })
.expect(200);

assert.notEqual(response.body.operation_token, undefined, response.text);
assert.notStrictEqual(response.body.operation_token, undefined, response.text);
operationToken = response.body.operation_token;
}
);
Expand All @@ -190,7 +190,7 @@ suite('Token authentication', (ctx) => {

test('create_authentication_tokens with basic-auth current user works', async () => {
const response = await client.req().send({ operation: 'create_authentication_tokens' }).expect(200);
assert.notEqual(response.body.operation_token, undefined, response.text);
assert.notEqual(response.body.refresh_token, undefined, response.text);
assert.notStrictEqual(response.body.operation_token, undefined, response.text);
assert.notStrictEqual(response.body.refresh_token, undefined, response.text);
});
});
2 changes: 1 addition & 1 deletion integrationTests/apiTests/transaction-logs.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Harper instance.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/transactions.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* we just pass `logging.auditLog: true` to `startHarper` at boot.
*/
import { suite, test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';
import { startHarper, teardownHarper } from '@harperfast/integration-testing';
import { createApiClient } from './utils/client.mjs';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/ttl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* Skipped on Bun: timing-sensitive TTL tests are not reliable under Harper-on-Bun in CI.
*/
import { suite, test, before, after } from 'node:test';
import { ok, strictEqual } from 'node:assert/strict';
import { ok, strictEqual } from 'node:assert';
import { setTimeout as sleep } from 'node:timers/promises';
import request from 'supertest';
import { startHarper, teardownHarper, type ContextWithHarper } from '@harperfast/integration-testing';
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/utils/components.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { restartHttpWorkers } from './lifecycle.mjs';

/**
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/utils/lifecycle.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';

const DEFAULT_READINESS_TIMEOUT_MS = 60000;
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/apiTests/utils/operations.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import assert from 'node:assert/strict';
import assert from 'node:assert';
import { setTimeout } from 'node:timers/promises';

/**
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/components/acl-connect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* and $SYS monitoring events.
*/
import { suite, test, before, after } from 'node:test';
import { strictEqual, ok } from 'node:assert/strict';
import { strictEqual, ok } from 'node:assert';
import { setTimeout as sleep } from 'node:timers/promises';
import { randomUUID } from 'node:crypto';
import { resolve } from 'node:path';
Expand Down
Loading