Files
openclaw/test/scripts/check-deprecated-api-usage.test.ts
Peter Steinberger c7e7ac2728 refactor: remove expired plugin compatibility surfaces (#111451)
* docs(secrets): remove retired web credential paths

* refactor(web): remove retired provider compatibility paths

* refactor(providers): delete retired compatibility routes

* refactor(secrets): remove retired credential aliases

* refactor(plugin-sdk): delete retired compatibility surfaces

* docs(plugin-sdk): remove retired migration guidance

* chore(plugin-sdk): refresh rebased surface budgets

* chore(plugin-sdk): refresh API removal baseline

* refactor(compat): migrate retired internal callers

* chore(plugin-sdk): refresh current-main baselines

* test(config): migrate plugin-owned secret assertions

* test(gateway): narrow plugin secret refs

* fix(plugin-sdk): preserve private boundary type identity

* chore(compat): remove stale sweep references

* chore(lint): lower max-lines budget

* refactor(secrets): remove unused web helper

* build(plugin-sdk): drop removed compat entries

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): use Linux API baseline hash

* fix(plugin-sdk): preserve private bundled build entries

* fix(plugin-sdk): package private runtime facades

* fix(plugins): preserve external credential contracts
2026-07-19 11:04:48 -07:00

122 lines
4.7 KiB
TypeScript

// Check Deprecated Api Usage tests cover check deprecated api usage script behavior.
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import {
BANNED_INTERNAL_PLUGIN_SDK_FACADE_MODULES,
buildDeprecatedPluginSdkModuleSpecifiers,
} from "../../scripts/lib/deprecated-plugin-sdk-usage.mjs";
import deprecatedPublicPluginSdkSubpaths from "../../scripts/lib/plugin-sdk-deprecated-public-subpaths.json" with { type: "json" };
const GUARD_SCRIPT_PATH = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../scripts/check-deprecated-api-usage.mjs",
);
function runFacadeImportRule(sourceByRepoPath: Record<string, string>) {
// realpath first: macOS os.tmpdir() is a /var -> /private/var symlink and the
// script reports repo-relative paths from its resolved cwd.
const fixtureRoot = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "deprecated-guard-")));
try {
for (const [repoPath, source] of Object.entries(sourceByRepoPath)) {
const filePath = path.join(fixtureRoot, repoPath);
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, source);
}
return spawnSync(process.execPath, [GUARD_SCRIPT_PATH, "--rule=facade-internal-imports"], {
cwd: fixtureRoot,
encoding: "utf8",
});
} finally {
fs.rmSync(fixtureRoot, { recursive: true, force: true });
}
}
describe("scripts/check-deprecated-api-usage", () => {
it("bans every curated deprecated public plugin SDK subpath", () => {
const specifiers = new Set(buildDeprecatedPluginSdkModuleSpecifiers());
for (const subpath of deprecatedPublicPluginSdkSubpaths) {
expect(specifiers.has(`openclaw/plugin-sdk/${subpath}`), subpath).toBe(true);
}
});
it("keeps removed root and private compatibility aliases out of the inventory", () => {
const specifiers = buildDeprecatedPluginSdkModuleSpecifiers();
for (const removedSpecifier of [
"openclaw/plugin-sdk",
"openclaw/plugin-sdk/agent-dir-compat",
"openclaw/plugin-sdk/test-utils",
]) {
expect(specifiers).not.toContain(removedSpecifier);
}
});
it("bans the scoped @openclaw/plugin-sdk spelling of every deprecated specifier", () => {
const specifiers = new Set(buildDeprecatedPluginSdkModuleSpecifiers());
for (const specifier of specifiers) {
if (!specifier.startsWith("@")) {
expect(specifiers.has(`@${specifier}`), specifier).toBe(true);
}
}
});
it("bans internal imports of every deprecated reply facade", () => {
const modulePaths = new Set(
BANNED_INTERNAL_PLUGIN_SDK_FACADE_MODULES.map((ban) => ban.modulePath),
);
for (const facade of [
"src/plugin-sdk/channel-message",
"src/plugin-sdk/channel-reply-pipeline",
"src/plugin-sdk/inbound-reply-dispatch",
"src/channels/message/inbound-reply-dispatch",
]) {
expect(modulePaths.has(facade), facade).toBe(true);
}
});
it("limits facade import allowlists to the plugin-sdk compat re-export chain", () => {
for (const ban of BANNED_INTERNAL_PLUGIN_SDK_FACADE_MODULES) {
for (const importer of ban.allowedImporters ?? []) {
expect(importer.startsWith("src/plugin-sdk/"), `${ban.modulePath} -> ${importer}`).toBe(
true,
);
}
}
});
it("flags internal facade imports across static, relative, scoped, and dynamic forms", () => {
const result = runFacadeImportRule({
"src/channels/probe.ts": [
'import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";',
'export { runInboundReplyTurn } from "./message/inbound-reply-dispatch.js";',
'const facade = await import ("../plugin-sdk/channel-message.js", { with: {} });',
].join("\n"),
});
expect(result.status).toBe(1);
expect(result.stderr).toContain(
"src/channels/probe.ts:1: openclaw/plugin-sdk/channel-reply-pipeline",
);
expect(result.stderr).toContain("src/channels/probe.ts:2: ./message/inbound-reply-dispatch.js");
expect(result.stderr).toContain("src/channels/probe.ts:3: ../plugin-sdk/channel-message.js");
});
it("allows canonical compat re-exports and test files", () => {
const result = runFacadeImportRule({
"src/plugin-sdk/channel-inbound.ts":
'export { runChannelInboundEvent } from "../channels/message/inbound-reply-dispatch.js";',
"src/plugin-sdk/channel-message.test.ts":
'const mod = await import("openclaw/plugin-sdk/channel-message");',
});
expect(result.stderr).toBe("");
expect(result.status).toBe(0);
});
});