Tests pass under heavy host load (closes #233) #234

Merged
clawbot merged 1 commits from issue-233-test-load-timeouts into next 2026-11-10 22:55:29 +01:00
5 changed files with 35 additions and 4 deletions

No files matched your search

+8
View File
@@ -26,6 +26,14 @@ declares one.
# Completed Steps # Completed Steps
- 2026-11-10: The test suite passes on a host under heavy load
(https://git.eeqj.de/sneak/quak/issues/233). vitest runs at most four workers
instead of one per CPU core. `test/cli/bin.test.ts` compiles the sources
`bin/quak.ts` imports and starts libsodium once, before its tests run. The
fake accounts of `test/ente-server.ts` and
`test/thumbnails/thumbnails.test.ts` stretch their passwords at libsodium's
lowest Argon2id cost, since every login stretches the password again.
- 2026-10-26: On an empty cache, `quak helper fix-missing-thumbnails --file` - 2026-10-26: On an empty cache, `quak helper fix-missing-thumbnails --file`
stops fetching collections' files once it finds every file it names stops fetching collections' files once it finds every file it names
(https://git.eeqj.de/sneak/quak/issues/223). It used to wait for a refresh, (https://git.eeqj.de/sneak/quak/issues/223). It used to wait for a refresh,
+10
View File
@@ -7,6 +7,11 @@
* Each test runs `bin/quak.ts`, as the smoke test does, with its session loader * Each test runs `bin/quak.ts`, as the smoke test does, with its session loader
* replaced by one that records the options it is given and reports no session, * replaced by one that records the options it is given and reports no session,
* so the command stops before it makes any request. * so the command stops before it makes any request.
*
* The first load of the sources `bin/quak.ts` imports compiles them, and the
* first `init()` starts libsodium. On a loaded host that takes longer than a
* test's timeout, so both happen here, before the tests run. Each test's
* `vi.resetModules()` then only runs the compiled sources again.
*/ */
import { mkdtempSync, rmSync } from "node:fs"; import { mkdtempSync, rmSync } from "node:fs";
@@ -14,8 +19,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import type { ApiClientOptions } from "../../src/api/client.js"; import type { ApiClientOptions } from "../../src/api/client.js";
import "../../src/cli-commands.js";
import { init } from "../../src/crypto/index.js";
import "../../src/index.js";
import { UNATTENDED_RETRY_OPTIONS } from "../../src/retry.js"; import { UNATTENDED_RETRY_OPTIONS } from "../../src/retry.js";
await init();
const loaded = vi.hoisted(() => [] as (ApiClientOptions | undefined)[]); const loaded = vi.hoisted(() => [] as (ApiClientOptions | undefined)[]);
vi.mock("../../src/cli-session.js", () => ({ vi.mock("../../src/cli-session.js", () => ({
+5 -2
View File
@@ -19,8 +19,11 @@ import { SRP, SrpServer } from "fast-srp-hap";
import { toBase64, deriveKEK, deriveLoginSubkey } from "../src/crypto/index.js"; import { toBase64, deriveKEK, deriveLoginSubkey } from "../src/crypto/index.js";
import type { KeyAttributes } from "../src/auth/types.js"; import type { KeyAttributes } from "../src/auth/types.js";
const TEST_OPS = 2; // The account's password is stretched at libsodium's lowest Argon2id cost.
const TEST_MEM = 64 * 1024 * 1024; // Every login stretches it again, and at a realistic cost that takes seconds on
// a loaded host.
const TEST_OPS = 1;
const TEST_MEM = 8192;
export interface MetaMockState { export interface MetaMockState {
verifier: Buffer; verifier: Buffer;
+5 -2
View File
@@ -57,8 +57,11 @@ import type { RetryOptions } from "../../src/retry.js";
const TEST_EMAIL = "thumb@example.com"; const TEST_EMAIL = "thumb@example.com";
const TEST_PASSWORD = "thumbpass"; const TEST_PASSWORD = "thumbpass";
const TEST_OPS = 2; // The password is stretched at libsodium's lowest Argon2id cost. Each test
const TEST_MEM = 64 * 1024 * 1024; // builds an account and logs in, and at a realistic cost that takes seconds on
// a loaded host.
const TEST_OPS = 1;
const TEST_MEM = 8192;
const TEST_TIME = 1700000000000000; const TEST_TIME = 1700000000000000;
interface ThumbMockState { interface ThumbMockState {
+7
View File
@@ -3,8 +3,15 @@ import { configDefaults, defineConfig } from "vitest/config";
// vitest does not read .gitignore when looking for tests. A checkout nested // vitest does not read .gitignore when looking for tests. A checkout nested
// under .claude/ has its own test/ tree, and without this exclude the suite // under .claude/ has its own test/ tree, and without this exclude the suite
// runs once per nested checkout and still reports success. // runs once per nested checkout and still reports success.
//
// vitest starts one worker per CPU core by default, and a shared host has
// dozens. Four keep the suite well inside the Dockerfile's time limit. vitest
// 2 rejects a maxWorkers below its default minWorkers, so minWorkers is set
// too.
export default defineConfig({ export default defineConfig({
test: { test: {
exclude: [...configDefaults.exclude, ".claude/**"], exclude: [...configDefaults.exclude, ".claude/**"],
minWorkers: 1,
maxWorkers: 4,
}, },
}); });