mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 01:29:56 +00:00
* refactor(sessions): reconcile hydration with current worker context * fix(sessions): remove unused hydration worker type export Keep the hydration input private to its shared worker union owner while retaining the externally consumed SQLite target input export. This clears the unused-export finding without changing emitted runtime code. * fix(sessions): publish transcript projections through canonical workers Move deferred projection writes and readiness reads onto the existing worker owners while preserving compressed transcript bytes, navigation, and FTS identity maintenance. Join the exact in-progress database close before readiness re-admission. Preserve finalized receipts when retirement prevents a new orphan sweep; the next preflight still repairs derived orphan rows. Validation: 73 focused cases, 16 current-main composition cases, causal SQL control, complete supported lint stripes and selected guards, current union types, and independent P0-P2 feature and lint-delta reviews. * fix(sessions): stream full hydration within worker memory limits Transfer canonical transcript chunks through the existing history worker while retaining one read-only snapshot and complete caller-side results. Preserve SQLite text encodings, BOM errors, cancellation, current-owner checks, and native cleanup without raising the worker heap limit. * fix(sessions): preserve deferred projection ownership Carry the admitted database environment through post-commit publication. Register the projection worker protocol and route its test consumers through the host broker. Synchronize cancellation and planner fixtures with the real projection task and completed reconciliation owner. * test(sessions): align hydration error controls with streaming Model interactive admission and the canonical streaming result in the existing quarantine error fixture, preserving its cleanup and retirement assertions. Remove a redundant unknown-alias assertion from the reader; emitted production JavaScript is unchanged. The complete 21-case worker error file, assertion ratchet, owning types, scoped lint, and fresh P0-P2 review pass. * fix(sessions): preserve maintenance publication and CI ownership * test(sessions): preserve projection worker ownership * test(sessions): drain rewrite fixtures before removing inputs * test(gateway): keep history worker tests with their canonical owner * fix(sessions): preserve projection wait cancellation errors * test(gateway): drain transcript reader fixtures before cleanup * test(gateway): match the landed placement policy fixture * fix(gateway): preserve transcript event source ordering * fix(sessions): refresh stale discovery within captured authority Refresh pure physical-target discovery once when registry facts change, keeping source retirement and worker failures terminal. Align Gateway fixtures with shared-state and projection lifetimes while preserving their assertions. * fix(sessions): resume scoped reads after healthy verification Start a new topology read with current admission for the original physical database and captured owner scopes. Keep startup reads sticky and reject old replies, replaced files, and expired maintenance or schema scopes. Allow bounded accepted exact-row facts to materialize while their page remains pinned. Preserve foreground priority for new worker reads and the existing archive and source guards. Update request-authority fixtures to hold the real worker snapshot, and carry the canonical updater VM fixture repair from691d2e5cd4. * test(gateway): capture the published chat fixture store * test(gateway): exclude test support from production callsites * test(ci): compose canonical fixture repairs Retain the actual coalescing assertion alongside the canonical capped-chunk comparison. Keep native routing entries sorted without changing membership, preserve the older-schema fixture index lifecycle, and include the existing plugin disposal module in wrapper closure. Canonical fixes:cb3e6df656. Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com> * test(ci): preserve shard coverage across planner formatting Retain canonical gatewayPatterns factoring from449fc2e6and move the unchanged coalescing assertion earlier in the same case. This resolves the actual one-file main conflict without importing unrelated source or changing coverage, ordering inputs, capacity checks or dependencies. Validation: exact assertion byte parity and clean three-way file union; owning case, root-test types, scoped lint/format and P2 review pass. * test(sessions): qualify publication through physical replacement Hold the real committed finalizer reply before host delivery. Prove that canonical close waits for the original notification, then replace the closed physical file and verify the successor contains only its own transcript. Reuse the existing publication fixture and transparent worker-operation interception; preserve all native admission and cleanup parameters. The new case closes the final-effect proof gap without changing production, adding a Gateway boot, or using a timer or test-only production hook. Validation: six publication cases pass; new case 1.766s, wrapper 85.48s including compilation. Owning types/lint/format, ratchets and independent P2 review pass. * test(ci): compare precise plans with their canonical templates The UI fallback fixture compared precise parent-job metadata with a measured complete plan that intentionally repacks different siblings. Compare each branch with its actual canonical producer and retain all coverage, uniqueness, worker, runner, concurrency, fallback and memory assertions. The original two-worker-vs-undefined parent environment mismatch reproduced. Adding changed-path context alone still failed; matching the precise template owner passes in 59.79s wrapper wall. Root-test types, lint/format, both ratchets and independent P2 review pass. No production limits or policy changed. * perf(cli): reuse pinned config for proxy validation Carry the exact canonical correction from488ce1e590(#158071), preserving its guarded fallback to the same synchronous config getter. All 73 owning CLI tests, core and config-CLI types, scoped lint/formatting and managed P2 review pass on this composition. The historical 30-second CI timeouts remain unattributed; this is a measured cold-import improvement, not proof of their cause. * test(ci): align precise assertions with canonical runtime inventory Adopt the canonical88e2ebeff4template reference and explicit deferred-runtime exclusion, retaining changed-path context for the dedicated UI comparison. Preserve all capacity and coverage assertions. The exact three-way file union is clean; the owning case, root-test types, lint/formatting and managed P2 review pass. No production or dependency changes. * fix(models): preserve explicit catalog discovery provenance Compose the reviewed #158113 successor5d9c2d766band canonical36def8be39consumer. Record successful legacy results while keeping bundled static and advisory results explicitly non-discovery. Preserve the strict retention rule and original worker/source authority. All 40 postimages match the supplier; focused composition tests, types, lint, formatting, ratchet and managed P2 review pass. Matching canonical producer/freshness proof is reused with its original source binding. * fix(plugin-sdk): compose explicit static catalog outcomes Compose the qualified six-file successor from #158113 at4f1acb78a3. Preserve strict discovery and mark generated static catalogs as non-discovery; move the loader type to its canonical leaf without changing its public export. All six postimages match the supplier. The 18-case owner file, core and SDK types, lint, formatting, both cycle guards, and managed P2 review pass. * refactor(state): separate independent read byte accounting Relocate the unchanged deletion snapshot and journal clauses after the repository selector clause so canonical cron byte accounting can merge without an insertion collision. Exact formulas, command discriminants, source authority and input capture are unchanged. The 35-case worker owner suite, core types, lint and formatting pass; managed P2 review is clean and the exact fixed-main file union preserves all clauses. * fix(models): compose captured discovery alias scope Compose canonical #158139 (52fc3daa84) with the qualified #158113 catalog correction. Preserve captured alias normalization only for outcome filtering, original hook scope, explicit outcome authority, and single evaluation of accepted legacy projections. Clarify the legacy omitted-outcome compatibility exception in the combined documentation. All 16 alias/legacy controls, core and owning types, lint/formatting, both cycle guards and managed P2 review pass. * fix(models): remove unlanded catalog inference detour Restore all 43 differing detour paths to canonical main52fc3daa84f71b15a052f7bd60caa7096ed5b31a, as verified against the canonical reversal manifest. Preserve the Projection implementation, strict36def retention consumer, canonical alias scope, and #158115 validated HTTP-success fixture correction. The separate legacy-retention repair is not imported. Validation: 45 native-worker/catalog-builder cases pass; the original discovery lifecycle and credential-free full-refresh cases pass. Core and three owning type projects, scoped lint/formatting, both cycle guards and managed P2 review pass. The longer native Gateway tour reached its final proof marker then hit its unchanged120-second deadline during cleanup, followed by one shutdown cascade; that gap is retained without a retry or deadline change. Current-head CI and installed-upgrade proof remain required. * fix(gateway): compose early model shutdown cancellation Compose the exact qualified nine-file shutdown correction from #158047 at541451990b7395eb25c449f0f3a4d4106004e601. Retain cancellation before bootstrap and join the shared prelude only after admitted Gateway owners fence new work. Preserve main's heartbeat-before-cron ordering and all original Projection publication/authority semantics. Validation: all19 held-acquisition and metadata lifecycle cases pass in this composition; core plus four owning test type projects, scoped lint/formatting, both cycle guards and fresh managed P2 review pass. Supplier real SIGTERM and import-fault proof retains its original source binding. The earlier native-tour cleanup timeout remains unattributed and was not rerun or relabeled; installed-upgrade proof and final exact-head CI remain pending. * refactor(state): align sandbox read reply construction Resolve the actual duplicate-extraction conflict by adopting canonical main's registry dispatcher postimage. The existing admitted constant supplies the same primitive ok/sourceAdmitted fields to each fresh reply; commands, kernel calls, arguments and admission behavior are unchanged. All11 owning native sandbox read cases, core types, lint/formatting and fresh managed P2 review pass. Prior724 hosted CI and installed-upgrade proof retain their applicable source and contract bindings; no broad main carry or dependency change. * test(gateway): retain first sign-in timeout phases --------- Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
251 lines
10 KiB
TypeScript
251 lines
10 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { afterEach, assert, beforeAll, expect, it } from "vitest";
|
|
import { resolveConfig } from "vitest/node";
|
|
import { buildVitestRunPlans } from "../scripts/test-projects.test-support.mts";
|
|
import { createPatternFileHelper } from "./helpers/pattern-file.js";
|
|
import { createCliVitestConfig } from "./vitest/vitest.cli.config.ts";
|
|
import { databaseWorkerCoreTestFiles } from "./vitest/vitest.database-worker-core-paths.mjs";
|
|
import { createDatabaseWorkerWatchVitestConfig } from "./vitest/vitest.database-worker-watch.config.ts";
|
|
import { diagnosticForksPool } from "./vitest/vitest.forks-pool.ts";
|
|
import { createGatewayClientVitestConfig } from "./vitest/vitest.gateway-client.config.ts";
|
|
import { createGatewayCoreVitestConfig } from "./vitest/vitest.gateway-core.config.ts";
|
|
import { createGatewayDatabaseWorkersVitestConfig } from "./vitest/vitest.gateway-database-workers.config.ts";
|
|
import { createGatewayMethodsIsolatedVitestConfig } from "./vitest/vitest.gateway-methods-isolated.config.ts";
|
|
import { createGatewayMethodsVitestConfig } from "./vitest/vitest.gateway-methods.config.ts";
|
|
import { createGatewayServerIsolatedVitestConfig } from "./vitest/vitest.gateway-server-isolated.config.ts";
|
|
import { gatewayDatabaseWorkerTestFiles } from "./vitest/vitest.gateway-server-paths.mjs";
|
|
import { createGatewayServerVitestConfig } from "./vitest/vitest.gateway-server.config.ts";
|
|
import { createGatewayVitestConfig } from "./vitest/vitest.gateway.config.ts";
|
|
import { createInfraVitestConfig } from "./vitest/vitest.infra.config.ts";
|
|
import { createToolingVitestConfig } from "./vitest/vitest.tooling.config.ts";
|
|
|
|
const patternFiles = createPatternFileHelper("gateway-watch-ownership-");
|
|
afterEach(() => patternFiles.cleanup());
|
|
|
|
function gatewayProjectFiles(filters: string[], env: Record<string, string | undefined> = {}) {
|
|
const originalArgv = process.argv;
|
|
process.argv = ["node", "vitest", "run", ...filters];
|
|
try {
|
|
return Object.fromEntries<string[]>(
|
|
[
|
|
createGatewayCoreVitestConfig,
|
|
createGatewayDatabaseWorkersVitestConfig,
|
|
createGatewayClientVitestConfig,
|
|
createGatewayMethodsVitestConfig,
|
|
createGatewayMethodsIsolatedVitestConfig,
|
|
createGatewayServerVitestConfig,
|
|
createGatewayServerIsolatedVitestConfig,
|
|
].map((createConfig) => {
|
|
const config = createConfig(env);
|
|
const test = config.test!;
|
|
assert(typeof test.name === "string");
|
|
const dir = test.dir ?? config.root!;
|
|
const files = fs
|
|
.globSync(test.include ?? [], { cwd: dir, exclude: test.exclude })
|
|
.map((file) => path.relative(config.root!, path.join(dir, file)).replaceAll("\\", "/"))
|
|
.filter((file) => selectedByFilters(file, filters))
|
|
.toSorted();
|
|
return [test.name, files];
|
|
}),
|
|
);
|
|
} finally {
|
|
process.argv = originalArgv;
|
|
}
|
|
}
|
|
|
|
function selectedByFilters(file: string, filters: string[]): boolean {
|
|
return (
|
|
filters.length === 0 ||
|
|
filters.some((filter) => file === filter || file.startsWith(`${filter}/`))
|
|
);
|
|
}
|
|
|
|
let canonicalGatewayFiles: ReturnType<typeof gatewayProjectFiles>;
|
|
beforeAll(() => {
|
|
canonicalGatewayFiles = gatewayProjectFiles([]);
|
|
});
|
|
|
|
it.each([
|
|
...[
|
|
"src/gateway/link-understanding.product.test.ts",
|
|
"src/gateway/server-methods/chat.abort-live-proof.test.ts",
|
|
"src/gateway/server-methods/models-auth-api-key.integration.test.ts",
|
|
"src/gateway/server-methods/models-auth-login.catalog.integration.test.ts",
|
|
"src/gateway/server-methods/models-auth-refresh.catalog.integration.test.ts",
|
|
"src/gateway/server-methods/models-auth-refresh.integration.test.ts",
|
|
"src/gateway/server-methods/models-connect-publication.integration.test.ts",
|
|
"src/gateway/server-methods/models-list.discovery-lifecycle.integration.test.ts",
|
|
"src/gateway/server-methods/models-manual-policy.integration.test.ts",
|
|
"src/gateway/server/ws-connection.startup.test.ts",
|
|
"src/gateway/session-message-events.test.ts",
|
|
"src/gateway/worker-environments/worker-session-tool-executor.test.ts",
|
|
"test/plugins/codex-model-catalog.gateway.test.ts",
|
|
"src/gateway/server-methods/models-list.freshness.integration.test.ts",
|
|
"src/gateway/setup-inference.first-signin.integration.test.ts",
|
|
].map((file) => ({ file, owner: "gateway-database-workers" })),
|
|
...[
|
|
"src/gateway/server.chat-cli-auth.test.ts",
|
|
"src/gateway/server.cli-watchdog.test.ts",
|
|
"src/gateway/server.codex-failure-recovery.test.ts",
|
|
].map((file) => ({ file, owner: "gateway-server-isolated" })),
|
|
])("keeps Gateway callers on their declared fork owner: $file", ({ file, owner }) => {
|
|
const owners = Object.entries(gatewayProjectFiles([file]))
|
|
.filter(([, files]) => files.includes(file))
|
|
.map(([name]) => name);
|
|
expect(owners).toEqual([owner]);
|
|
});
|
|
|
|
it("excludes the full Gateway TLS producer from threaded tooling", () => {
|
|
const file = "test/e2e/qa-lab/runtime/gateway-tls-pinning.test.ts";
|
|
const config = createToolingVitestConfig({
|
|
OPENCLAW_VITEST_INCLUDE_FILE: patternFiles.writePatternFile("tls-tooling.json", [file]),
|
|
});
|
|
assert(config.test);
|
|
assert(config.root);
|
|
const test = config.test;
|
|
const files = fs.globSync(test.include ?? [], {
|
|
cwd: test.dir ?? config.root,
|
|
exclude: test.exclude,
|
|
});
|
|
expect(files).toEqual([]);
|
|
});
|
|
|
|
it("routes resume local-node handshakes only through the core broker fork", () => {
|
|
const file = "src/cli/resume-cli.test.ts";
|
|
expect(buildVitestRunPlans([file])).toEqual([
|
|
{
|
|
config: "test/vitest/vitest.infra.config.ts",
|
|
forwardedArgs: [],
|
|
includePatterns: [file],
|
|
watchMode: false,
|
|
},
|
|
]);
|
|
const env = {
|
|
OPENCLAW_VITEST_INCLUDE_FILE: patternFiles.writePatternFile("resume-owner.json", [file]),
|
|
};
|
|
const worker = createInfraVitestConfig(env);
|
|
const previous = createCliVitestConfig(env);
|
|
assert(worker.test);
|
|
expect(worker.test.pool).toBe(diagnosticForksPool);
|
|
for (const [config, expected] of [
|
|
[worker, [file]],
|
|
[previous, []],
|
|
] as const) {
|
|
assert(config.test);
|
|
assert(config.root);
|
|
const root = config.root;
|
|
const dir = config.test.dir ?? root;
|
|
const selected = fs
|
|
.globSync(config.test.include ?? [], {
|
|
cwd: dir,
|
|
exclude: config.test.exclude,
|
|
})
|
|
.map((entry) => path.relative(root, path.join(dir, entry)).replaceAll("\\", "/"));
|
|
expect(selected).toEqual(expected);
|
|
}
|
|
});
|
|
|
|
it.each([
|
|
{
|
|
target: "src/gateway/config-reload.telegram-policy.test.ts",
|
|
ownership: { config: "test/vitest/vitest.gateway.config.ts" },
|
|
},
|
|
{
|
|
target: "src/gateway",
|
|
ownership: {
|
|
config: "test/vitest/vitest.database-worker-watch.config.ts",
|
|
databaseWorkerWatchOwner: "test/vitest/vitest.gateway.config.ts",
|
|
databaseWorkerWatchTests: databaseWorkerCoreTestFiles.filter((file) =>
|
|
file.startsWith("src/gateway/"),
|
|
),
|
|
},
|
|
},
|
|
])("preserves mixed Gateway worker watch selection with $target", async ({ target, ownership }) => {
|
|
const [workerFile] = gatewayDatabaseWorkerTestFiles;
|
|
assert(workerFile);
|
|
const filters = [workerFile, target];
|
|
const forwardedArgs = ["--reporter=dot", "--coverage"];
|
|
const plans = buildVitestRunPlans(["--watch", ...filters, ...forwardedArgs]);
|
|
expect(plans).toEqual([
|
|
{
|
|
...ownership,
|
|
forwardedArgs,
|
|
includePatterns: [
|
|
filters[0],
|
|
target.endsWith(".test.ts") ? target : `${target}/**/*.test.ts`,
|
|
],
|
|
watchMode: true,
|
|
},
|
|
]);
|
|
const includeFile = patternFiles.writePatternFile("include.json", plans[0]!.includePatterns);
|
|
const canonical = canonicalGatewayFiles;
|
|
const expected = Object.fromEntries(
|
|
Object.entries(canonical).map(([name, files]) => [
|
|
name,
|
|
files.filter((file) => selectedByFilters(file, filters)),
|
|
]),
|
|
);
|
|
const selected = gatewayProjectFiles([], { OPENCLAW_VITEST_INCLUDE_FILE: includeFile });
|
|
expect(selected).toEqual(expected);
|
|
expect(selected["gateway-database-workers"]).toEqual(
|
|
gatewayDatabaseWorkerTestFiles.filter((file) => selectedByFilters(file, filters)),
|
|
);
|
|
expect(selected["gateway-core"]).toContain("src/gateway/config-reload.telegram-policy.test.ts");
|
|
const workerFiles: string[] = [];
|
|
if (plans[0]?.databaseWorkerWatchTests) {
|
|
const env = { OPENCLAW_VITEST_INCLUDE_FILE: includeFile };
|
|
const config = createDatabaseWorkerWatchVitestConfig(
|
|
createGatewayVitestConfig(env),
|
|
plans[0].databaseWorkerWatchTests,
|
|
env,
|
|
);
|
|
const resolved = await resolveConfig({ config: false }, config);
|
|
const worker = resolved.test.resolvedProjects.find(
|
|
({ projectConfig }) => projectConfig.name === "infra",
|
|
)?.projectConfig;
|
|
assert(worker);
|
|
expect(worker.pool).toBe(diagnosticForksPool.name);
|
|
workerFiles.push(
|
|
...fs
|
|
.globSync(worker.include, { cwd: worker.dir, exclude: worker.exclude })
|
|
.map((file) =>
|
|
path.relative(worker.root, path.join(worker.dir, file)).replaceAll("\\", "/"),
|
|
),
|
|
);
|
|
}
|
|
expect(workerFiles.toSorted()).toEqual(
|
|
databaseWorkerCoreTestFiles.filter((file) => selectedByFilters(file, filters)).toSorted(),
|
|
);
|
|
const files = [...Object.values(selected).flat(), ...workerFiles];
|
|
expect(new Set(files).size).toBe(files.length);
|
|
if (target.endsWith(".test.ts")) {
|
|
expect(files.toSorted()).toEqual(filters.toSorted());
|
|
}
|
|
});
|
|
|
|
it.each(
|
|
[
|
|
["src/gateway"],
|
|
["src/gateway/server"],
|
|
["src/gateway/server-methods"],
|
|
["src/gateway/worker-environments"],
|
|
["src/gateway/server.sessions.compaction-read-errors.test.ts"],
|
|
...gatewayDatabaseWorkerTestFiles.map((file) => [file]),
|
|
["src/gateway/server", "src/gateway/worker-environments"],
|
|
].map((filters) => ({ filters })),
|
|
)("preserves canonical project ownership for $filters", ({ filters }) => {
|
|
const canonical = canonicalGatewayFiles;
|
|
expect(canonical["gateway-database-workers"]).toEqual(gatewayDatabaseWorkerTestFiles);
|
|
const expected = Object.fromEntries(
|
|
Object.entries(canonical).map(([name, files]) => [
|
|
name,
|
|
files.filter((file) => selectedByFilters(file, filters)),
|
|
]),
|
|
);
|
|
|
|
expect(gatewayProjectFiles(filters)).toEqual(expected);
|
|
const selected = Object.values(expected).flat();
|
|
expect(selected.length).toBeGreaterThan(0);
|
|
expect(new Set(selected).size).toBe(selected.length);
|
|
});
|