mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:10:44 +00:00
test(channels): shard registry-backed contracts
This commit is contained in:
@@ -14,17 +14,26 @@ function listContractTestFiles(rootDir = "src/channels/plugins/contracts") {
|
||||
|
||||
const CONTRACT_FILE_WEIGHTS = new Map([
|
||||
["channel-import-guardrails.test.ts", 18],
|
||||
["directory.registry-backed.contract.test.ts", 12],
|
||||
["outbound-payload.contract.test.ts", 18],
|
||||
["plugin.registry-backed.contract.test.ts", 34],
|
||||
["plugins-core.catalog.paths.contract.test.ts", 28],
|
||||
["plugins-core.catalog.entries.contract.test.ts", 16],
|
||||
["session-binding.registry-backed.contract.test.ts", 16],
|
||||
["surfaces-only.registry-backed.contract.test.ts", 36],
|
||||
]);
|
||||
|
||||
function resolveContractFileWeight(file) {
|
||||
const name = file.replaceAll("\\", "/").split("/").pop();
|
||||
if (name.startsWith("plugin.registry-backed-shard-")) {
|
||||
return 5;
|
||||
}
|
||||
if (name.startsWith("surfaces-only.registry-backed-shard-")) {
|
||||
return 5;
|
||||
}
|
||||
if (name.startsWith("directory.registry-backed-shard-")) {
|
||||
return 4;
|
||||
}
|
||||
if (name.startsWith("threading.registry-backed-shard-")) {
|
||||
return 4;
|
||||
}
|
||||
return CONTRACT_FILE_WEIGHTS.get(name) ?? 8;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 0, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 1, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 2, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 3, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 4, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 5, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 6, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installDirectoryContractRegistryShard({ shardIndex: 7, shardCount: 8 });
|
||||
@@ -1,14 +0,0 @@
|
||||
import { describe } from "vitest";
|
||||
import { getDirectoryContractRegistry } from "../../../../test/helpers/channels/surface-contract-registry.js";
|
||||
import { installChannelDirectoryContractSuite } from "../../../../test/helpers/channels/threading-directory-contract-suites.js";
|
||||
|
||||
for (const entry of getDirectoryContractRegistry()) {
|
||||
describe(`${entry.id} directory contract`, () => {
|
||||
installChannelDirectoryContractSuite({
|
||||
plugin: entry.plugin,
|
||||
coverage: entry.coverage,
|
||||
cfg: entry.cfg,
|
||||
accountId: entry.accountId,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 0, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 1, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 2, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 3, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 4, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 5, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 6, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installPluginContractRegistryShard({ shardIndex: 7, shardCount: 8 });
|
||||
@@ -1,11 +0,0 @@
|
||||
import { describe } from "vitest";
|
||||
import { installChannelPluginContractSuite } from "../../../../test/helpers/channels/registry-contract-suites.js";
|
||||
import { getPluginContractRegistry } from "../../../../test/helpers/channels/registry-plugin.js";
|
||||
|
||||
for (const entry of getPluginContractRegistry()) {
|
||||
describe(`${entry.id} plugin contract`, () => {
|
||||
installChannelPluginContractSuite({
|
||||
plugin: entry.plugin,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 0, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 1, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 2, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 3, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 4, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 5, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 6, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installSurfaceContractRegistryShard({ shardIndex: 7, shardCount: 8 });
|
||||
@@ -1,14 +0,0 @@
|
||||
import { describe } from "vitest";
|
||||
import { getSurfaceContractRegistry } from "../../../../test/helpers/channels/surface-contract-registry.js";
|
||||
import { installChannelSurfaceContractSuite } from "../../../../test/helpers/channels/surface-contract-suite.js";
|
||||
|
||||
for (const entry of getSurfaceContractRegistry()) {
|
||||
for (const surface of entry.surfaces) {
|
||||
describe(`${entry.id} ${surface} surface contract`, () => {
|
||||
installChannelSurfaceContractSuite({
|
||||
plugin: entry.plugin,
|
||||
surface,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 0, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 1, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 2, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 3, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 4, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 5, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 6, shardCount: 8 });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js";
|
||||
|
||||
installThreadingContractRegistryShard({ shardIndex: 7, shardCount: 8 });
|
||||
@@ -1,11 +0,0 @@
|
||||
import { describe } from "vitest";
|
||||
import { getThreadingContractRegistry } from "../../../../test/helpers/channels/surface-contract-registry.js";
|
||||
import { installChannelThreadingContractSuite } from "../../../../test/helpers/channels/threading-directory-contract-suites.js";
|
||||
|
||||
for (const entry of getThreadingContractRegistry()) {
|
||||
describe(`${entry.id} threading contract`, () => {
|
||||
installChannelThreadingContractSuite({
|
||||
plugin: entry.plugin,
|
||||
});
|
||||
});
|
||||
}
|
||||
92
test/helpers/channels/registry-backed-contract-shards.ts
Normal file
92
test/helpers/channels/registry-backed-contract-shards.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { describe, it } from "vitest";
|
||||
import { installChannelPluginContractSuite } from "./registry-contract-suites.js";
|
||||
import { getPluginContractRegistryShard } from "./registry-plugin.js";
|
||||
import {
|
||||
getDirectoryContractRegistryShard,
|
||||
getSurfaceContractRegistryShard,
|
||||
getThreadingContractRegistryShard,
|
||||
} from "./surface-contract-registry.js";
|
||||
import { installChannelSurfaceContractSuite } from "./surface-contract-suite.js";
|
||||
import {
|
||||
installChannelDirectoryContractSuite,
|
||||
installChannelThreadingContractSuite,
|
||||
} from "./threading-directory-contract-suites.js";
|
||||
|
||||
type ContractShardParams = {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
};
|
||||
|
||||
function installEmptyShardSuite(label: string) {
|
||||
describe(label, () => {
|
||||
it("has no matching bundled channels", () => {
|
||||
// Keeps intentionally empty id-based shards visible to Vitest.
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function installSurfaceContractRegistryShard(params: ContractShardParams) {
|
||||
const entries = getSurfaceContractRegistryShard(params);
|
||||
if (entries.length === 0) {
|
||||
installEmptyShardSuite("surface contract registry shard");
|
||||
return;
|
||||
}
|
||||
for (const entry of entries) {
|
||||
for (const surface of entry.surfaces) {
|
||||
describe(`${entry.id} ${surface} surface contract`, () => {
|
||||
installChannelSurfaceContractSuite({
|
||||
plugin: entry.plugin,
|
||||
surface,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function installDirectoryContractRegistryShard(params: ContractShardParams) {
|
||||
const entries = getDirectoryContractRegistryShard(params);
|
||||
if (entries.length === 0) {
|
||||
installEmptyShardSuite("directory contract registry shard");
|
||||
return;
|
||||
}
|
||||
for (const entry of entries) {
|
||||
describe(`${entry.id} directory contract`, () => {
|
||||
installChannelDirectoryContractSuite({
|
||||
plugin: entry.plugin,
|
||||
coverage: entry.coverage,
|
||||
cfg: entry.cfg,
|
||||
accountId: entry.accountId,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function installThreadingContractRegistryShard(params: ContractShardParams) {
|
||||
const entries = getThreadingContractRegistryShard(params);
|
||||
if (entries.length === 0) {
|
||||
installEmptyShardSuite("threading contract registry shard");
|
||||
return;
|
||||
}
|
||||
for (const entry of entries) {
|
||||
describe(`${entry.id} threading contract`, () => {
|
||||
installChannelThreadingContractSuite({
|
||||
plugin: entry.plugin,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function installPluginContractRegistryShard(params: ContractShardParams) {
|
||||
const entries = getPluginContractRegistryShard(params);
|
||||
if (entries.length === 0) {
|
||||
installEmptyShardSuite("plugin contract registry shard");
|
||||
return;
|
||||
}
|
||||
for (const entry of entries) {
|
||||
describe(`${entry.id} plugin contract`, () => {
|
||||
installChannelPluginContractSuite({
|
||||
plugin: entry.plugin,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
import { listBundledChannelPlugins } from "../../../src/channels/plugins/bundled.js";
|
||||
import {
|
||||
getBundledChannelPlugin,
|
||||
listBundledChannelPluginIds,
|
||||
listBundledChannelPlugins,
|
||||
} from "../../../src/channels/plugins/bundled.js";
|
||||
import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js";
|
||||
import { normalizeChannelMeta } from "../../../src/channels/plugins/meta-normalization.js";
|
||||
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
|
||||
|
||||
@@ -7,12 +12,35 @@ type PluginContractEntry = {
|
||||
plugin: Pick<ChannelPlugin, "id" | "meta" | "capabilities" | "config">;
|
||||
};
|
||||
|
||||
export function getPluginContractRegistry(): PluginContractEntry[] {
|
||||
return listBundledChannelPlugins().map((plugin) => ({
|
||||
function toPluginContractEntry(plugin: ChannelPlugin): PluginContractEntry {
|
||||
return {
|
||||
id: plugin.id,
|
||||
plugin: {
|
||||
...plugin,
|
||||
meta: normalizeChannelMeta({ id: plugin.id, meta: plugin.meta }),
|
||||
},
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
function getBundledChannelPluginIdsForShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): readonly ChannelId[] {
|
||||
return listBundledChannelPluginIds().filter(
|
||||
(_id, index) => index % params.shardCount === params.shardIndex,
|
||||
);
|
||||
}
|
||||
|
||||
export function getPluginContractRegistry(): PluginContractEntry[] {
|
||||
return listBundledChannelPlugins().map(toPluginContractEntry);
|
||||
}
|
||||
|
||||
export function getPluginContractRegistryShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): PluginContractEntry[] {
|
||||
return getBundledChannelPluginIdsForShard(params).flatMap((id) => {
|
||||
const plugin = getBundledChannelPlugin(id);
|
||||
return plugin ? [toPluginContractEntry(plugin)] : [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import {
|
||||
getBundledChannelPlugin,
|
||||
listBundledChannelPluginIds,
|
||||
listBundledChannelPlugins,
|
||||
setBundledChannelRuntime,
|
||||
} from "../../../src/channels/plugins/bundled.js";
|
||||
import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js";
|
||||
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
import {
|
||||
@@ -53,18 +56,52 @@ setBundledChannelRuntime("line", {
|
||||
} as never);
|
||||
|
||||
let surfaceContractRegistryCache: SurfaceContractEntry[] | undefined;
|
||||
const surfaceContractEntryCache = new Map<ChannelId, SurfaceContractEntry | null>();
|
||||
let threadingContractRegistryCache: ThreadingContractEntry[] | undefined;
|
||||
let directoryContractRegistryCache: DirectoryContractEntry[] | undefined;
|
||||
|
||||
export function getSurfaceContractRegistry(): SurfaceContractEntry[] {
|
||||
surfaceContractRegistryCache ??= listBundledChannelPlugins().map((plugin) => ({
|
||||
function toSurfaceContractEntry(plugin: ChannelPlugin): SurfaceContractEntry {
|
||||
return {
|
||||
id: plugin.id,
|
||||
plugin,
|
||||
surfaces: channelPluginSurfaceKeys.filter((surface) => Boolean(plugin[surface])),
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
function getBundledChannelPluginIdsForShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): readonly ChannelId[] {
|
||||
return listBundledChannelPluginIds().filter(
|
||||
(_id, index) => index % params.shardCount === params.shardIndex,
|
||||
);
|
||||
}
|
||||
|
||||
function getSurfaceContractEntry(id: ChannelId): SurfaceContractEntry | undefined {
|
||||
if (surfaceContractEntryCache.has(id)) {
|
||||
return surfaceContractEntryCache.get(id) ?? undefined;
|
||||
}
|
||||
const plugin = getBundledChannelPlugin(id);
|
||||
const entry = plugin ? toSurfaceContractEntry(plugin) : null;
|
||||
surfaceContractEntryCache.set(id, entry);
|
||||
return entry ?? undefined;
|
||||
}
|
||||
|
||||
export function getSurfaceContractRegistry(): SurfaceContractEntry[] {
|
||||
surfaceContractRegistryCache ??= listBundledChannelPlugins().map(toSurfaceContractEntry);
|
||||
return surfaceContractRegistryCache;
|
||||
}
|
||||
|
||||
export function getSurfaceContractRegistryShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): SurfaceContractEntry[] {
|
||||
return getBundledChannelPluginIdsForShard(params).flatMap((id) => {
|
||||
const entry = getSurfaceContractEntry(id);
|
||||
return entry ? [entry] : [];
|
||||
});
|
||||
}
|
||||
|
||||
export function getThreadingContractRegistry(): ThreadingContractEntry[] {
|
||||
threadingContractRegistryCache ??= getSurfaceContractRegistry()
|
||||
.filter((entry) => entry.surfaces.includes("threading"))
|
||||
@@ -75,6 +112,18 @@ export function getThreadingContractRegistry(): ThreadingContractEntry[] {
|
||||
return threadingContractRegistryCache;
|
||||
}
|
||||
|
||||
export function getThreadingContractRegistryShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): ThreadingContractEntry[] {
|
||||
return getSurfaceContractRegistryShard(params)
|
||||
.filter((entry) => entry.surfaces.includes("threading"))
|
||||
.map((entry) => ({
|
||||
id: entry.id,
|
||||
plugin: entry.plugin,
|
||||
}));
|
||||
}
|
||||
|
||||
const directoryPresenceOnlyIds = new Set(["whatsapp", "zalouser"]);
|
||||
|
||||
export function getDirectoryContractRegistry(): DirectoryContractEntry[] {
|
||||
@@ -87,3 +136,16 @@ export function getDirectoryContractRegistry(): DirectoryContractEntry[] {
|
||||
}));
|
||||
return directoryContractRegistryCache;
|
||||
}
|
||||
|
||||
export function getDirectoryContractRegistryShard(params: {
|
||||
shardIndex: number;
|
||||
shardCount: number;
|
||||
}): DirectoryContractEntry[] {
|
||||
return getSurfaceContractRegistryShard(params)
|
||||
.filter((entry) => entry.surfaces.includes("directory"))
|
||||
.map((entry) => ({
|
||||
id: entry.id,
|
||||
plugin: entry.plugin,
|
||||
coverage: directoryPresenceOnlyIds.has(entry.id) ? "presence" : "lookups",
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user