From a5eb8e08addf07cd1cb6da65f06139577b2c90ab Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 3 Apr 2026 11:17:54 +0100 Subject: [PATCH] test: reroute telegram fetch network policy suite --- scripts/test-planner/catalog.mjs | 4 +- test/fixtures/test-memory-hotspots.unit.json | 4 -- test/fixtures/test-timings.extensions.json | 6 ++- test/fixtures/test-timings.unit.json | 4 -- test/scripts/test-parallel.test.ts | 12 +++++ test/vitest-scoped-config.test.ts | 15 ++++++ vitest.channel-paths.mjs | 52 +++++++++++++++++++- vitest.channels.config.ts | 4 +- vitest.extensions.config.ts | 14 ++---- 9 files changed, 92 insertions(+), 23 deletions(-) diff --git a/scripts/test-planner/catalog.mjs b/scripts/test-planner/catalog.mjs index b5a5a8643a1..ea4dc6b9c3a 100644 --- a/scripts/test-planner/catalog.mjs +++ b/scripts/test-planner/catalog.mjs @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import { channelTestPrefixes } from "../../vitest.channel-paths.mjs"; +import { channelTestPrefixes, isChannelSurfaceTestFile } from "../../vitest.channel-paths.mjs"; import { isBoundaryTestFile, isBundledPluginDependentUnitTestFile, @@ -127,7 +127,7 @@ export function loadTestCatalog() { surface = "live"; } else if (normalizedFile.endsWith(".e2e.test.ts")) { surface = "e2e"; - } else if (channelTestPrefixes.some((prefix) => normalizedFile.startsWith(prefix))) { + } else if (isChannelSurfaceTestFile(normalizedFile)) { surface = "channels"; } else if (normalizedFile.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) { surface = "extensions"; diff --git a/test/fixtures/test-memory-hotspots.unit.json b/test/fixtures/test-memory-hotspots.unit.json index 3c316fa4567..20a96993c6a 100644 --- a/test/fixtures/test-memory-hotspots.unit.json +++ b/test/fixtures/test-memory-hotspots.unit.json @@ -8,10 +8,6 @@ "deltaKb": 1111491, "sources": ["openclaw-test-memory-trace:unit-heavy-2"] }, - "src/media/fetch.telegram-network.test.ts": { - "deltaKb": 1101005, - "sources": ["openclaw-test-memory-trace:unit-heavy-1"] - }, "src/cron/isolated-agent/run.skill-filter.test.ts": { "deltaKb": 1069548, "sources": ["openclaw-test-memory-trace:unit-run.skill-filter-memory-isolated"] diff --git a/test/fixtures/test-timings.extensions.json b/test/fixtures/test-timings.extensions.json index 44e5132501b..53dfd509266 100644 --- a/test/fixtures/test-timings.extensions.json +++ b/test/fixtures/test-timings.extensions.json @@ -1,6 +1,6 @@ { "config": "vitest.extensions.config.ts", - "generatedAt": "2026-03-31T06:24:09.128Z", + "generatedAt": "2026-04-03T10:15:21.663Z", "defaultDurationMs": 1000, "files": { "extensions/bluebubbles/src/monitor.webhook-auth.test.ts": { @@ -1046,6 +1046,10 @@ "extensions/mattermost/src/mattermost/probe.test.ts": { "durationMs": 2.155517578125, "testCount": 5 + }, + "extensions/telegram/src/fetch.network-policy.test.ts": { + "durationMs": 3260, + "testCount": 5 } } } diff --git a/test/fixtures/test-timings.unit.json b/test/fixtures/test-timings.unit.json index 1fb884600ab..1ed80ae49f0 100644 --- a/test/fixtures/test-timings.unit.json +++ b/test/fixtures/test-timings.unit.json @@ -3,10 +3,6 @@ "generatedAt": "2026-03-23T05:11:36.071Z", "defaultDurationMs": 250, "files": { - "src/media/fetch.telegram-network.test.ts": { - "durationMs": 6483.10009765625, - "testCount": 5 - }, "src/cron/service.issue-regressions.test.ts": { "durationMs": 4524.16552734375, "testCount": 39 diff --git a/test/scripts/test-parallel.test.ts b/test/scripts/test-parallel.test.ts index 23f9527c828..ce4ddd980e7 100644 --- a/test/scripts/test-parallel.test.ts +++ b/test/scripts/test-parallel.test.ts @@ -447,6 +447,18 @@ describe("scripts/test-parallel lane planning", () => { expect(output).not.toContain("vitest.unit.config.ts"); }); + it("routes telegram fetch network policy through the extensions config", () => { + const output = runPlannerPlan([ + "--explain", + bundledPluginFile("telegram", "src/fetch.network-policy.test.ts"), + ]); + + expect(output).toContain("surface=extensions"); + expect(output).toContain("reasons=extensions-surface"); + expect(output).toContain("vitest.extensions.config.ts"); + expect(output).not.toContain("vitest.channels.config.ts"); + }); + it("prints the planner-backed CI manifest as JSON", () => { const output = runPlannerPlan(["--ci-manifest"], { GITHUB_EVENT_NAME: "pull_request", diff --git a/test/vitest-scoped-config.test.ts b/test/vitest-scoped-config.test.ts index 11bc9816a99..5e475e35902 100644 --- a/test/vitest-scoped-config.test.ts +++ b/test/vitest-scoped-config.test.ts @@ -97,6 +97,21 @@ describe("scoped vitest configs", () => { expect(defaultExtensionsConfig.test?.include).toEqual(["**/*.test.ts"]); }); + it("keeps telegram fetch network policy in extensions while excluding other telegram channel suites", () => { + const extensionExcludes = defaultExtensionsConfig.test?.exclude ?? []; + expect( + extensionExcludes.some((pattern) => path.matchesGlob("telegram/src/fetch.test.ts", pattern)), + ).toBe(true); + expect( + extensionExcludes.some((pattern) => + path.matchesGlob("telegram/src/fetch.network-policy.test.ts", pattern), + ), + ).toBe(false); + expect(defaultChannelsConfig.test?.exclude).toContain( + bundledPluginFile("telegram", "src/fetch.network-policy.test.ts"), + ); + }); + it("normalizes gateway include patterns relative to the scoped dir", () => { expect(defaultGatewayConfig.test?.dir).toBe("src/gateway"); expect(defaultGatewayConfig.test?.include).toEqual(["**/*.test.ts"]); diff --git a/vitest.channel-paths.mjs b/vitest.channel-paths.mjs index 4c80c799170..a41ffe5e603 100644 --- a/vitest.channel-paths.mjs +++ b/vitest.channel-paths.mjs @@ -1,4 +1,17 @@ -import { bundledPluginRoot } from "./scripts/lib/bundled-plugin-paths.mjs"; +import path from "node:path"; +import { + BUNDLED_PLUGIN_PATH_PREFIX, + bundledPluginFile, + bundledPluginRoot, +} from "./scripts/lib/bundled-plugin-paths.mjs"; + +const normalizeRepoPath = (value) => value.split(path.sep).join("/"); + +export const extensionRoutedChannelTestFiles = [ + bundledPluginFile("telegram", "src/fetch.network-policy.test.ts"), +]; + +const extensionRoutedChannelTestFileSet = new Set(extensionRoutedChannelTestFiles); export const channelTestRoots = [ bundledPluginRoot("telegram"), @@ -14,3 +27,40 @@ export const channelTestRoots = [ export const channelTestPrefixes = channelTestRoots.map((root) => `${root}/`); export const channelTestInclude = channelTestRoots.map((root) => `${root}/**/*.test.ts`); export const channelTestExclude = channelTestRoots.map((root) => `${root}/**`); + +const extensionChannelRootOverrideBasenames = new Map(); +for (const file of extensionRoutedChannelTestFiles) { + if (!file.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) { + continue; + } + const relativeFile = file.slice(BUNDLED_PLUGIN_PATH_PREFIX.length); + const separator = relativeFile.indexOf("/"); + if (separator === -1) { + continue; + } + const root = relativeFile.slice(0, separator); + const baseName = path.basename(relativeFile, ".test.ts"); + const current = extensionChannelRootOverrideBasenames.get(root) ?? []; + current.push(baseName); + extensionChannelRootOverrideBasenames.set(root, current); +} + +export const extensionExcludedChannelTestGlobs = channelTestRoots + .filter((root) => root.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) + .map((root) => root.slice(BUNDLED_PLUGIN_PATH_PREFIX.length)) + .map((relativeRoot) => { + const allowedBasenames = extensionChannelRootOverrideBasenames.get(relativeRoot) ?? []; + if (allowedBasenames.length === 0) { + return `${relativeRoot}/**`; + } + const alternation = allowedBasenames.join("|"); + return `${relativeRoot}/**/!(${alternation}).test.ts`; + }); + +export function isChannelSurfaceTestFile(filePath) { + const normalizedFile = normalizeRepoPath(filePath); + return ( + channelTestPrefixes.some((prefix) => normalizedFile.startsWith(prefix)) && + !extensionRoutedChannelTestFileSet.has(normalizedFile) + ); +} diff --git a/vitest.channels.config.ts b/vitest.channels.config.ts index 29cb6270fea..c287a28a58f 100644 --- a/vitest.channels.config.ts +++ b/vitest.channels.config.ts @@ -1,4 +1,4 @@ -import { channelTestInclude } from "./vitest.channel-paths.mjs"; +import { channelTestInclude, extensionRoutedChannelTestFiles } from "./vitest.channel-paths.mjs"; import { loadPatternListFromEnv } from "./vitest.pattern-file.ts"; import { createScopedVitestConfig } from "./vitest.scoped-config.ts"; @@ -11,7 +11,7 @@ export function loadIncludePatternsFromEnv( export function createChannelsVitestConfig(env?: Record) { return createScopedVitestConfig(loadIncludePatternsFromEnv(env) ?? channelTestInclude, { env, - exclude: ["src/gateway/**"], + exclude: ["src/gateway/**", ...extensionRoutedChannelTestFiles], passWithNoTests: true, }); } diff --git a/vitest.extensions.config.ts b/vitest.extensions.config.ts index c5ec6238887..a952a881e96 100644 --- a/vitest.extensions.config.ts +++ b/vitest.extensions.config.ts @@ -1,8 +1,5 @@ -import { - BUNDLED_PLUGIN_PATH_PREFIX, - BUNDLED_PLUGIN_TEST_GLOB, -} from "./scripts/lib/bundled-plugin-paths.mjs"; -import { channelTestExclude } from "./vitest.channel-paths.mjs"; +import { BUNDLED_PLUGIN_TEST_GLOB } from "./scripts/lib/bundled-plugin-paths.mjs"; +import { extensionExcludedChannelTestGlobs } from "./vitest.channel-paths.mjs"; import { loadPatternListFromEnv } from "./vitest.pattern-file.ts"; import { createScopedVitestConfig } from "./vitest.scoped-config.ts"; @@ -19,10 +16,9 @@ export function createExtensionsVitestConfig( dir: "extensions", env, passWithNoTests: true, - // Channel implementations live under the bundled plugin tree but are tested by - // vitest.channels.config.ts (pnpm test:channels) which provides - // the heavier mock scaffolding they need. - exclude: channelTestExclude.filter((pattern) => pattern.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)), + // Most channel implementations stay on the channel surface, but a few + // transport-only suites live better in the general extensions lane. + exclude: extensionExcludedChannelTestGlobs, }); }