mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:10:44 +00:00
test(plugins): cover kitchen sink clawhub cutover
This commit is contained in:
@@ -14,8 +14,9 @@ npm-latest-full|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|
|
||||
npm-latest-conformance|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|npm|success|conformance|conformance
|
||||
npm-latest-adversarial|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|npm|success|adversarial|adversarial
|
||||
npm-beta|npm:@openclaw/kitchen-sink@beta|openclaw-kitchen-sink-fixture|npm|failure|none
|
||||
clawhub-latest|clawhub:openclaw-kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic
|
||||
clawhub-beta|clawhub:openclaw-kitchen-sink@beta|openclaw-kitchen-sink-fixture|clawhub|failure|none
|
||||
clawhub-latest|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic
|
||||
clawhub-beta|clawhub:@openclaw/kitchen-sink@beta|openclaw-kitchen-sink-fixture|clawhub|failure|none
|
||||
npm-to-clawhub|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic||npm:@openclaw/kitchen-sink@latest
|
||||
SCENARIOS
|
||||
)"
|
||||
KITCHEN_SINK_SCENARIOS="${OPENCLAW_KITCHEN_SINK_PLUGIN_SCENARIOS:-$DEFAULT_KITCHEN_SINK_SCENARIOS}"
|
||||
|
||||
@@ -8,7 +8,7 @@ const profile = process.argv[2];
|
||||
const portFile = process.argv[3];
|
||||
const requireFromApp = createRequire(path.join(process.cwd(), "package.json"));
|
||||
const JSZip = requireFromApp("jszip");
|
||||
const packageName = "openclaw-kitchen-sink";
|
||||
const packageName = "@openclaw/kitchen-sink";
|
||||
const pluginId = "openclaw-kitchen-sink-fixture";
|
||||
|
||||
const profiles = {
|
||||
|
||||
@@ -213,6 +213,39 @@ function assertClawHubExternalInstallContract(installPath) {
|
||||
}
|
||||
}
|
||||
|
||||
function inferInstallSource(spec) {
|
||||
if (spec?.startsWith("npm:")) {
|
||||
return "npm";
|
||||
}
|
||||
if (spec?.startsWith("clawhub:")) {
|
||||
return "clawhub";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function assertCutoverPreinstalled() {
|
||||
const pluginId = process.env.KITCHEN_SINK_ID;
|
||||
const preinstallSpec = process.env.KITCHEN_SINK_PREINSTALL_SPEC;
|
||||
const source = inferInstallSource(preinstallSpec);
|
||||
if (!pluginId || !preinstallSpec || !source) {
|
||||
throw new Error(`invalid kitchen-sink cutover preinstall spec: ${preinstallSpec}`);
|
||||
}
|
||||
|
||||
const indexPath = path.join(process.env.HOME, ".openclaw", "plugins", "installs.json");
|
||||
const index = readJson(indexPath);
|
||||
const record = (index.installRecords ?? index.records ?? {})[pluginId];
|
||||
if (!record) {
|
||||
throw new Error(`missing kitchen-sink cutover preinstall record for ${pluginId}`);
|
||||
}
|
||||
if (record.source !== source) {
|
||||
throw new Error(`expected kitchen-sink preinstall source=${source}, got ${record.source}`);
|
||||
}
|
||||
const expectedSpec = source === "npm" ? preinstallSpec.replace(/^npm:/u, "") : preinstallSpec;
|
||||
if (record.spec !== expectedSpec) {
|
||||
throw new Error(`expected kitchen-sink preinstall spec ${expectedSpec}, got ${record.spec}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertInstalled() {
|
||||
const pluginId = process.env.KITCHEN_SINK_ID;
|
||||
const spec = process.env.KITCHEN_SINK_SPEC;
|
||||
@@ -412,6 +445,7 @@ const commands = {
|
||||
"scan-logs": scanLogs,
|
||||
"configure-runtime": configureRuntime,
|
||||
"remove-channel-config": removeChannelConfig,
|
||||
"assert-cutover-preinstalled": assertCutoverPreinstalled,
|
||||
"assert-installed": assertInstalled,
|
||||
"assert-removed": assertRemoved,
|
||||
};
|
||||
|
||||
@@ -75,9 +75,19 @@ assert_kitchen_sink_removed() {
|
||||
node scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs assert-removed
|
||||
}
|
||||
|
||||
assert_kitchen_sink_cutover_preinstalled() {
|
||||
node scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs assert-cutover-preinstalled
|
||||
}
|
||||
|
||||
run_success_scenario() {
|
||||
echo "Testing ${KITCHEN_SINK_LABEL} install from ${KITCHEN_SINK_SPEC}..."
|
||||
run_logged_print "kitchen-sink-install-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "$KITCHEN_SINK_SPEC"
|
||||
local install_args=("$KITCHEN_SINK_SPEC")
|
||||
if [ -n "${KITCHEN_SINK_PREINSTALL_SPEC:-}" ]; then
|
||||
run_logged_print "kitchen-sink-preinstall-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "$KITCHEN_SINK_PREINSTALL_SPEC"
|
||||
assert_kitchen_sink_cutover_preinstalled
|
||||
install_args+=("--force")
|
||||
fi
|
||||
run_logged_print "kitchen-sink-install-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "${install_args[@]}"
|
||||
configure_kitchen_sink_runtime
|
||||
run_logged_print "kitchen-sink-enable-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins enable "$KITCHEN_SINK_ID"
|
||||
node "$OPENCLAW_ENTRY" plugins list --json >"/tmp/kitchen-sink-${KITCHEN_SINK_LABEL}-plugins.json"
|
||||
@@ -110,7 +120,7 @@ if [[ "$KITCHEN_SINK_SCENARIOS" == *"clawhub:"* ]] &&
|
||||
fi
|
||||
|
||||
scenario_count=0
|
||||
while IFS='|' read -r label spec plugin_id source expectation surface_mode personality; do
|
||||
while IFS='|' read -r label spec plugin_id source expectation surface_mode personality preinstall_spec; do
|
||||
if [ -z "${label:-}" ] || [[ "$label" == \#* ]]; then
|
||||
continue
|
||||
fi
|
||||
@@ -122,6 +132,7 @@ while IFS='|' read -r label spec plugin_id source expectation surface_mode perso
|
||||
export KITCHEN_SINK_SURFACE_MODE="$surface_mode"
|
||||
export KITCHEN_SINK_PERSONALITY="${personality:-}"
|
||||
export OPENCLAW_KITCHEN_SINK_PERSONALITY="${personality:-}"
|
||||
export KITCHEN_SINK_PREINSTALL_SPEC="${preinstall_spec:-}"
|
||||
case "$expectation" in
|
||||
success)
|
||||
run_success_scenario
|
||||
|
||||
@@ -3,7 +3,7 @@ run_plugins_clawhub_scenario() {
|
||||
echo "Skipping ClawHub plugin install and uninstall (OPENCLAW_PLUGINS_E2E_CLAWHUB=0)."
|
||||
else
|
||||
echo "Testing ClawHub kitchen-sink plugin install and uninstall..."
|
||||
CLAWHUB_PLUGIN_SPEC="${OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC:-clawhub:openclaw-kitchen-sink}"
|
||||
CLAWHUB_PLUGIN_SPEC="${OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC:-clawhub:@openclaw/kitchen-sink}"
|
||||
CLAWHUB_PLUGIN_ID="${OPENCLAW_PLUGINS_E2E_CLAWHUB_ID:-openclaw-kitchen-sink-fixture}"
|
||||
export CLAWHUB_PLUGIN_SPEC CLAWHUB_PLUGIN_ID
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { mkdirSync, writeFileSync } from "node:fs";
|
||||
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
@@ -11,7 +11,10 @@ import {
|
||||
resolveSelectedClawHubPublishablePluginPackages,
|
||||
type PublishablePluginPackage,
|
||||
} from "../scripts/lib/plugin-clawhub-release.ts";
|
||||
import { OPENCLAW_PLUGIN_NPM_REPOSITORY_URL } from "../scripts/lib/plugin-npm-release.ts";
|
||||
import {
|
||||
collectPublishablePluginPackages,
|
||||
OPENCLAW_PLUGIN_NPM_REPOSITORY_URL,
|
||||
} from "../scripts/lib/plugin-npm-release.ts";
|
||||
import { cleanupTempDirs, makeTempRepoRoot } from "./helpers/temp-repo.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
@@ -101,6 +104,60 @@ describe("collectClawHubPublishablePluginPackages", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("OpenClaw ClawHub-preferred plugin metadata", () => {
|
||||
const clawHubPreferredPlugins = [
|
||||
{
|
||||
extensionId: "diagnostics-otel",
|
||||
packageName: "@openclaw/diagnostics-otel",
|
||||
},
|
||||
{
|
||||
extensionId: "diagnostics-prometheus",
|
||||
packageName: "@openclaw/diagnostics-prometheus",
|
||||
},
|
||||
] as const;
|
||||
|
||||
it("keeps diagnostics plugins selectable through both ClawHub and npm release paths", () => {
|
||||
const packageNames = clawHubPreferredPlugins.map((plugin) => plugin.packageName);
|
||||
const clawHubPublishable = collectClawHubPublishablePluginPackages(undefined, {
|
||||
packageNames,
|
||||
});
|
||||
const npmPublishable = collectPublishablePluginPackages(undefined, {
|
||||
packageNames,
|
||||
});
|
||||
|
||||
expect(clawHubPublishable.map((plugin) => plugin.packageName)).toEqual(packageNames);
|
||||
expect(npmPublishable.map((plugin) => plugin.packageName)).toEqual(packageNames);
|
||||
|
||||
for (const plugin of clawHubPreferredPlugins) {
|
||||
const packageJson = JSON.parse(
|
||||
readFileSync(`extensions/${plugin.extensionId}/package.json`, "utf8"),
|
||||
) as {
|
||||
openclaw?: {
|
||||
install?: {
|
||||
clawhubSpec?: string;
|
||||
defaultChoice?: string;
|
||||
npmSpec?: string;
|
||||
};
|
||||
release?: {
|
||||
publishToClawHub?: boolean;
|
||||
publishToNpm?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
expect(packageJson.openclaw?.install).toMatchObject({
|
||||
clawhubSpec: `clawhub:${plugin.packageName}`,
|
||||
defaultChoice: "clawhub",
|
||||
npmSpec: plugin.packageName,
|
||||
});
|
||||
expect(packageJson.openclaw?.release).toMatchObject({
|
||||
publishToClawHub: true,
|
||||
publishToNpm: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("collectClawHubVersionGateErrors", () => {
|
||||
it("requires a version bump when a publishable plugin changes", () => {
|
||||
const repoDir = createTempPluginRepo();
|
||||
|
||||
@@ -305,6 +305,7 @@ describe("docker build helper", () => {
|
||||
|
||||
expect(clawhub).toContain('plugins install "$CLAWHUB_PLUGIN_SPEC"');
|
||||
expect(clawhub).toContain('plugins update "$CLAWHUB_PLUGIN_ID"');
|
||||
expect(clawhub).toContain("clawhub:@openclaw/kitchen-sink");
|
||||
expect(assertions).toContain("clawhub-updated");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -102,10 +102,16 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
|
||||
expect(script).toContain("npm-latest-conformance");
|
||||
expect(script).toContain("npm-latest-adversarial");
|
||||
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("clawhub:@openclaw/kitchen-sink@latest");
|
||||
expect(script).toContain("clawhub:@openclaw/kitchen-sink@beta");
|
||||
expect(script).toContain(
|
||||
"npm-to-clawhub|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic||npm:@openclaw/kitchen-sink@latest",
|
||||
);
|
||||
expect(script).toContain("scripts/e2e/lib/kitchen-sink-plugin/sweep.sh");
|
||||
expect(sweepScript).toContain('plugins install "$KITCHEN_SINK_SPEC"');
|
||||
expect(sweepScript).toContain('plugins install "$KITCHEN_SINK_PREINSTALL_SPEC"');
|
||||
expect(sweepScript).toContain("assert-cutover-preinstalled");
|
||||
expect(sweepScript).toContain('install_args+=("--force")');
|
||||
expect(sweepScript).toContain("KITCHEN_SINK_PERSONALITY");
|
||||
expect(sweepScript).toContain("OPENCLAW_KITCHEN_SINK_PERSONALITY");
|
||||
expect(sweepScript).toContain('plugins uninstall "$KITCHEN_SINK_SPEC" --force');
|
||||
@@ -113,7 +119,7 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
|
||||
sweepScript.indexOf("run_success_scenario()"),
|
||||
sweepScript.indexOf("run_failure_scenario()"),
|
||||
);
|
||||
expect(successScenario.indexOf('plugins install "$KITCHEN_SINK_SPEC"')).toBeLessThan(
|
||||
expect(successScenario.indexOf('plugins install "${install_args[@]}"')).toBeLessThan(
|
||||
successScenario.indexOf("configure_kitchen_sink_runtime"),
|
||||
);
|
||||
expect(successScenario.indexOf("configure_kitchen_sink_runtime")).toBeLessThan(
|
||||
@@ -122,6 +128,7 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
|
||||
expect(successScenario).toContain('plugins inspect "$KITCHEN_SINK_ID" --runtime --json');
|
||||
expect(successScenario).toContain("plugins inspect --all --runtime --json");
|
||||
expect(sweepScript).toContain("run_failure_scenario");
|
||||
expect(assertionsScript).toContain("assertCutoverPreinstalled");
|
||||
expect(assertionsScript).toContain("record.source !== source");
|
||||
expect(assertionsScript).toContain("record.clawhubPackage !== packageName");
|
||||
expect(assertionsScript).toContain("assertClawHubExternalInstallContract");
|
||||
|
||||
Reference in New Issue
Block a user