mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 04:00:43 +00:00
172 lines
6.7 KiB
TypeScript
172 lines
6.7 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
|
import { readFileSync } from "node:fs";
|
|
import { describe, expect, it } from "vitest";
|
|
import { parse } from "yaml";
|
|
import { findLaneByName } from "../../scripts/lib/docker-e2e-plan.mjs";
|
|
import {
|
|
PLUGIN_PRERELEASE_REQUIRED_SURFACES,
|
|
assertPluginPrereleaseTestPlanComplete,
|
|
createPluginPrereleaseTestPlan,
|
|
} from "../../scripts/lib/plugin-prerelease-test-plan.mjs";
|
|
|
|
function readCiWorkflow() {
|
|
return parse(readFileSync(".github/workflows/ci.yml", "utf8"));
|
|
}
|
|
|
|
describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
|
|
it("covers every pre-release plugin skill surface in normal CI", () => {
|
|
const plan = assertPluginPrereleaseTestPlanComplete();
|
|
|
|
expect(plan.surfaces).toEqual(
|
|
[...PLUGIN_PRERELEASE_REQUIRED_SURFACES].toSorted((a, b) => a.localeCompare(b)),
|
|
);
|
|
});
|
|
|
|
it("runs the package and Docker product lanes through the existing scheduler", () => {
|
|
const plan = createPluginPrereleaseTestPlan();
|
|
|
|
expect(plan.dockerLanes).toEqual([
|
|
"npm-onboard-channel-agent",
|
|
"doctor-switch",
|
|
"update-channel-switch",
|
|
"bundled-channel-deps-compat",
|
|
"plugins-offline",
|
|
"plugins",
|
|
"kitchen-sink-plugin",
|
|
"plugin-update",
|
|
"config-reload",
|
|
"gateway-network",
|
|
"mcp-channels",
|
|
"cron-mcp-cleanup",
|
|
"bundled-plugin-install-uninstall-0",
|
|
"bundled-plugin-install-uninstall-1",
|
|
"bundled-plugin-install-uninstall-2",
|
|
"bundled-plugin-install-uninstall-3",
|
|
"bundled-plugin-install-uninstall-4",
|
|
"bundled-plugin-install-uninstall-5",
|
|
"bundled-plugin-install-uninstall-6",
|
|
"bundled-plugin-install-uninstall-7",
|
|
]);
|
|
|
|
for (const lane of plan.dockerLanes) {
|
|
expect(findLaneByName(lane), lane).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
it("keeps live-ish coverage credential-gated in PR CI", () => {
|
|
const plan = createPluginPrereleaseTestPlan();
|
|
|
|
expect(plan.dockerLanes).not.toContain("openai-web-search-minimal");
|
|
expect(plan.dockerLanes.some((lane) => lane.startsWith("live-"))).toBe(false);
|
|
expect(plan.staticChecks).toContainEqual({
|
|
check: "live-ish-availability",
|
|
checkName: "checks-plugin-prerelease-live-ish-availability",
|
|
command: "node scripts/plugin-prerelease-liveish-matrix.mjs",
|
|
surfaces: ["live-ish-availability"],
|
|
});
|
|
});
|
|
|
|
it("keeps SDK/package boundary checks inside the plugin prerelease suite", () => {
|
|
const plan = createPluginPrereleaseTestPlan();
|
|
|
|
expect(plan.staticChecks.map((check) => check.checkName)).toEqual([
|
|
"checks-plugin-prerelease-package-boundary-compile",
|
|
"checks-plugin-prerelease-package-boundary-canary",
|
|
"checks-plugin-prerelease-live-ish-availability",
|
|
]);
|
|
});
|
|
|
|
it("uses kitchen-sink npm and ClawHub scenarios as the registry install canary", () => {
|
|
const lane = findLaneByName("kitchen-sink-plugin");
|
|
const script = readFileSync("scripts/e2e/kitchen-sink-plugin-docker.sh", "utf8");
|
|
|
|
expect(lane).toEqual(
|
|
expect.objectContaining({
|
|
command: "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:kitchen-sink-plugin",
|
|
e2eImageKind: "functional",
|
|
name: "kitchen-sink-plugin",
|
|
resources: expect.arrayContaining(["npm"]),
|
|
stateScenario: "empty",
|
|
}),
|
|
);
|
|
expect(script).toContain("npm:@openclaw/kitchen-sink@latest");
|
|
expect(script).toContain("npm:@openclaw/kitchen-sink@beta");
|
|
expect(script).toContain("clawhub:openclaw-kitchen-sink@latest");
|
|
expect(script).toContain("clawhub:openclaw-kitchen-sink@beta");
|
|
expect(script).toContain('plugins install "$KITCHEN_SINK_SPEC"');
|
|
expect(script).toContain('plugins uninstall "$KITCHEN_SINK_SPEC" --force');
|
|
expect(script).toContain("run_failure_scenario");
|
|
expect(script).toContain("record.source !== source");
|
|
expect(script).toContain("record.clawhubPackage !== packageName");
|
|
expect(script).toContain("expectedErrorMessages");
|
|
expect(script).toContain("docker stats --no-stream");
|
|
expect(script).toContain("scan_logs_for_unexpected_errors");
|
|
});
|
|
|
|
it("wires the full plugin prerelease plan into the mega CI workflow", () => {
|
|
const workflow = readCiWorkflow();
|
|
const preflight = workflow.jobs.preflight;
|
|
const staticShard = workflow.jobs["plugin-prerelease-static-shard"];
|
|
const dockerSuite = workflow.jobs["plugin-prerelease-docker-suite"];
|
|
const suite = workflow.jobs["plugin-prerelease-suite"];
|
|
|
|
expect(preflight.outputs).toMatchObject({
|
|
plugin_prerelease_docker_lanes:
|
|
"${{ steps.manifest.outputs.plugin_prerelease_docker_lanes }}",
|
|
plugin_prerelease_ref: "${{ steps.manifest.outputs.plugin_prerelease_ref }}",
|
|
plugin_prerelease_static_matrix:
|
|
"${{ steps.manifest.outputs.plugin_prerelease_static_matrix }}",
|
|
run_plugin_prerelease_suite: "${{ steps.manifest.outputs.run_plugin_prerelease_suite }}",
|
|
});
|
|
expect(staticShard).toMatchObject({
|
|
name: "${{ matrix.check_name }}",
|
|
"runs-on": "blacksmith-8vcpu-ubuntu-2404",
|
|
});
|
|
expect(staticShard.strategy.matrix).toBe(
|
|
"${{ fromJson(needs.preflight.outputs.plugin_prerelease_static_matrix) }}",
|
|
);
|
|
expect(
|
|
staticShard.steps.find((step) => step.name === "Run plugin prerelease static shard").run,
|
|
).toContain('bash -c "$PLUGIN_PRERELEASE_COMMAND"');
|
|
expect(dockerSuite).toMatchObject({
|
|
if: "needs.preflight.outputs.run_plugin_prerelease_suite == 'true'",
|
|
needs: ["preflight"],
|
|
uses: "./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml",
|
|
with: {
|
|
docker_lanes: "${{ needs.preflight.outputs.plugin_prerelease_docker_lanes }}",
|
|
include_live_suites: false,
|
|
include_openwebui: false,
|
|
include_release_path_suites: false,
|
|
include_repo_e2e: false,
|
|
live_models_only: false,
|
|
ref: "${{ needs.preflight.outputs.plugin_prerelease_ref }}",
|
|
},
|
|
});
|
|
expect(dockerSuite.secrets).toBeUndefined();
|
|
expect(suite.needs).toEqual([
|
|
"preflight",
|
|
"plugin-prerelease-static-shard",
|
|
"plugin-prerelease-docker-suite",
|
|
]);
|
|
});
|
|
|
|
it("keeps the live-ish availability check redacted", () => {
|
|
const output = execFileSync(
|
|
process.execPath,
|
|
["scripts/plugin-prerelease-liveish-matrix.mjs"],
|
|
{
|
|
encoding: "utf8",
|
|
env: {
|
|
DISCORD_TOKEN: "discord-token-should-not-print",
|
|
OPENAI_API_KEY: "openai-token-should-not-print",
|
|
},
|
|
},
|
|
);
|
|
|
|
expect(output).toContain("provider-openai: present (OPENAI_API_KEY, OPENAI_BASE_URL)");
|
|
expect(output).toContain("channel-discord: present (DISCORD_TOKEN, OPENCLAW_DISCORD_TOKEN)");
|
|
expect(output).not.toContain("openai-token-should-not-print");
|
|
expect(output).not.toContain("discord-token-should-not-print");
|
|
});
|
|
});
|