Skip to content

Commit 33eebc2

Browse files
committed
test(plugins): cover kitchen sink clawhub cutover
1 parent 4eedc47 commit 33eebc2

8 files changed

Lines changed: 122 additions & 11 deletions

File tree

scripts/e2e/kitchen-sink-plugin-docker.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ npm-latest-full|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|
1414
npm-latest-conformance|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|npm|success|conformance|conformance
1515
npm-latest-adversarial|npm:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|npm|success|adversarial|adversarial
1616
npm-beta|npm:@openclaw/kitchen-sink@beta|openclaw-kitchen-sink-fixture|npm|failure|none
17-
clawhub-latest|clawhub:openclaw-kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic
18-
clawhub-beta|clawhub:openclaw-kitchen-sink@beta|openclaw-kitchen-sink-fixture|clawhub|failure|none
17+
clawhub-latest|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic
18+
clawhub-beta|clawhub:@openclaw/kitchen-sink@beta|openclaw-kitchen-sink-fixture|clawhub|failure|none
19+
npm-to-clawhub|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic||npm:@openclaw/kitchen-sink@latest
1920
SCENARIOS
2021
)"
2122
KITCHEN_SINK_SCENARIOS="${OPENCLAW_KITCHEN_SINK_PLUGIN_SCENARIOS:-$DEFAULT_KITCHEN_SINK_SCENARIOS}"

scripts/e2e/lib/clawhub-fixture-server.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const profile = process.argv[2];
88
const portFile = process.argv[3];
99
const requireFromApp = createRequire(path.join(process.cwd(), "package.json"));
1010
const JSZip = requireFromApp("jszip");
11-
const packageName = "openclaw-kitchen-sink";
11+
const packageName = "@openclaw/kitchen-sink";
1212
const pluginId = "openclaw-kitchen-sink-fixture";
1313

1414
const profiles = {

scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,39 @@ function assertClawHubExternalInstallContract(installPath) {
213213
}
214214
}
215215

216+
function inferInstallSource(spec) {
217+
if (spec?.startsWith("npm:")) {
218+
return "npm";
219+
}
220+
if (spec?.startsWith("clawhub:")) {
221+
return "clawhub";
222+
}
223+
return null;
224+
}
225+
226+
function assertCutoverPreinstalled() {
227+
const pluginId = process.env.KITCHEN_SINK_ID;
228+
const preinstallSpec = process.env.KITCHEN_SINK_PREINSTALL_SPEC;
229+
const source = inferInstallSource(preinstallSpec);
230+
if (!pluginId || !preinstallSpec || !source) {
231+
throw new Error(`invalid kitchen-sink cutover preinstall spec: ${preinstallSpec}`);
232+
}
233+
234+
const indexPath = path.join(process.env.HOME, ".openclaw", "plugins", "installs.json");
235+
const index = readJson(indexPath);
236+
const record = (index.installRecords ?? index.records ?? {})[pluginId];
237+
if (!record) {
238+
throw new Error(`missing kitchen-sink cutover preinstall record for ${pluginId}`);
239+
}
240+
if (record.source !== source) {
241+
throw new Error(`expected kitchen-sink preinstall source=${source}, got ${record.source}`);
242+
}
243+
const expectedSpec = source === "npm" ? preinstallSpec.replace(/^npm:/u, "") : preinstallSpec;
244+
if (record.spec !== expectedSpec) {
245+
throw new Error(`expected kitchen-sink preinstall spec ${expectedSpec}, got ${record.spec}`);
246+
}
247+
}
248+
216249
function assertInstalled() {
217250
const pluginId = process.env.KITCHEN_SINK_ID;
218251
const spec = process.env.KITCHEN_SINK_SPEC;
@@ -412,6 +445,7 @@ const commands = {
412445
"scan-logs": scanLogs,
413446
"configure-runtime": configureRuntime,
414447
"remove-channel-config": removeChannelConfig,
448+
"assert-cutover-preinstalled": assertCutoverPreinstalled,
415449
"assert-installed": assertInstalled,
416450
"assert-removed": assertRemoved,
417451
};

scripts/e2e/lib/kitchen-sink-plugin/sweep.sh

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,19 @@ assert_kitchen_sink_removed() {
7575
node scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs assert-removed
7676
}
7777

78+
assert_kitchen_sink_cutover_preinstalled() {
79+
node scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs assert-cutover-preinstalled
80+
}
81+
7882
run_success_scenario() {
7983
echo "Testing ${KITCHEN_SINK_LABEL} install from ${KITCHEN_SINK_SPEC}..."
80-
run_logged_print "kitchen-sink-install-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "$KITCHEN_SINK_SPEC"
84+
local install_args=("$KITCHEN_SINK_SPEC")
85+
if [ -n "${KITCHEN_SINK_PREINSTALL_SPEC:-}" ]; then
86+
run_logged_print "kitchen-sink-preinstall-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "$KITCHEN_SINK_PREINSTALL_SPEC"
87+
assert_kitchen_sink_cutover_preinstalled
88+
install_args+=("--force")
89+
fi
90+
run_logged_print "kitchen-sink-install-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins install "${install_args[@]}"
8191
configure_kitchen_sink_runtime
8292
run_logged_print "kitchen-sink-enable-${KITCHEN_SINK_LABEL}" node "$OPENCLAW_ENTRY" plugins enable "$KITCHEN_SINK_ID"
8393
node "$OPENCLAW_ENTRY" plugins list --json >"/tmp/kitchen-sink-${KITCHEN_SINK_LABEL}-plugins.json"
@@ -110,7 +120,7 @@ if [[ "$KITCHEN_SINK_SCENARIOS" == *"clawhub:"* ]] &&
110120
fi
111121

112122
scenario_count=0
113-
while IFS='|' read -r label spec plugin_id source expectation surface_mode personality; do
123+
while IFS='|' read -r label spec plugin_id source expectation surface_mode personality preinstall_spec; do
114124
if [ -z "${label:-}" ] || [[ "$label" == \#* ]]; then
115125
continue
116126
fi
@@ -122,6 +132,7 @@ while IFS='|' read -r label spec plugin_id source expectation surface_mode perso
122132
export KITCHEN_SINK_SURFACE_MODE="$surface_mode"
123133
export KITCHEN_SINK_PERSONALITY="${personality:-}"
124134
export OPENCLAW_KITCHEN_SINK_PERSONALITY="${personality:-}"
135+
export KITCHEN_SINK_PREINSTALL_SPEC="${preinstall_spec:-}"
125136
case "$expectation" in
126137
success)
127138
run_success_scenario

scripts/e2e/lib/plugins/clawhub.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ run_plugins_clawhub_scenario() {
33
echo "Skipping ClawHub plugin install and uninstall (OPENCLAW_PLUGINS_E2E_CLAWHUB=0)."
44
else
55
echo "Testing ClawHub kitchen-sink plugin install and uninstall..."
6-
CLAWHUB_PLUGIN_SPEC="${OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC:-clawhub:openclaw-kitchen-sink}"
6+
CLAWHUB_PLUGIN_SPEC="${OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC:-clawhub:@openclaw/kitchen-sink}"
77
CLAWHUB_PLUGIN_ID="${OPENCLAW_PLUGINS_E2E_CLAWHUB_ID:-openclaw-kitchen-sink-fixture}"
88
export CLAWHUB_PLUGIN_SPEC CLAWHUB_PLUGIN_ID
99

test/plugin-clawhub-release.test.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { execFileSync } from "node:child_process";
2-
import { mkdirSync, writeFileSync } from "node:fs";
2+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
33
import { join } from "node:path";
44
import { afterEach, describe, expect, it } from "vitest";
55
import {
@@ -11,7 +11,10 @@ import {
1111
resolveSelectedClawHubPublishablePluginPackages,
1212
type PublishablePluginPackage,
1313
} from "../scripts/lib/plugin-clawhub-release.ts";
14-
import { OPENCLAW_PLUGIN_NPM_REPOSITORY_URL } from "../scripts/lib/plugin-npm-release.ts";
14+
import {
15+
collectPublishablePluginPackages,
16+
OPENCLAW_PLUGIN_NPM_REPOSITORY_URL,
17+
} from "../scripts/lib/plugin-npm-release.ts";
1518
import { cleanupTempDirs, makeTempRepoRoot } from "./helpers/temp-repo.js";
1619

1720
const tempDirs: string[] = [];
@@ -101,6 +104,60 @@ describe("collectClawHubPublishablePluginPackages", () => {
101104
});
102105
});
103106

107+
describe("OpenClaw ClawHub-preferred plugin metadata", () => {
108+
const clawHubPreferredPlugins = [
109+
{
110+
extensionId: "diagnostics-otel",
111+
packageName: "@openclaw/diagnostics-otel",
112+
},
113+
{
114+
extensionId: "diagnostics-prometheus",
115+
packageName: "@openclaw/diagnostics-prometheus",
116+
},
117+
] as const;
118+
119+
it("keeps diagnostics plugins selectable through both ClawHub and npm release paths", () => {
120+
const packageNames = clawHubPreferredPlugins.map((plugin) => plugin.packageName);
121+
const clawHubPublishable = collectClawHubPublishablePluginPackages(undefined, {
122+
packageNames,
123+
});
124+
const npmPublishable = collectPublishablePluginPackages(undefined, {
125+
packageNames,
126+
});
127+
128+
expect(clawHubPublishable.map((plugin) => plugin.packageName)).toEqual(packageNames);
129+
expect(npmPublishable.map((plugin) => plugin.packageName)).toEqual(packageNames);
130+
131+
for (const plugin of clawHubPreferredPlugins) {
132+
const packageJson = JSON.parse(
133+
readFileSync(`extensions/${plugin.extensionId}/package.json`, "utf8"),
134+
) as {
135+
openclaw?: {
136+
install?: {
137+
clawhubSpec?: string;
138+
defaultChoice?: string;
139+
npmSpec?: string;
140+
};
141+
release?: {
142+
publishToClawHub?: boolean;
143+
publishToNpm?: boolean;
144+
};
145+
};
146+
};
147+
148+
expect(packageJson.openclaw?.install).toMatchObject({
149+
clawhubSpec: `clawhub:${plugin.packageName}`,
150+
defaultChoice: "clawhub",
151+
npmSpec: plugin.packageName,
152+
});
153+
expect(packageJson.openclaw?.release).toMatchObject({
154+
publishToClawHub: true,
155+
publishToNpm: true,
156+
});
157+
}
158+
});
159+
});
160+
104161
describe("collectClawHubVersionGateErrors", () => {
105162
it("requires a version bump when a publishable plugin changes", () => {
106163
const repoDir = createTempPluginRepo();

test/scripts/docker-build-helper.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ describe("docker build helper", () => {
305305

306306
expect(clawhub).toContain('plugins install "$CLAWHUB_PLUGIN_SPEC"');
307307
expect(clawhub).toContain('plugins update "$CLAWHUB_PLUGIN_ID"');
308+
expect(clawhub).toContain("clawhub:@openclaw/kitchen-sink");
308309
expect(assertions).toContain("clawhub-updated");
309310
});
310311
});

test/scripts/plugin-prerelease-test-plan.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,24 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
102102
expect(script).toContain("npm-latest-conformance");
103103
expect(script).toContain("npm-latest-adversarial");
104104
expect(script).toContain("npm:@openclaw/kitchen-sink@beta");
105-
expect(script).toContain("clawhub:openclaw-kitchen-sink@latest");
106-
expect(script).toContain("clawhub:openclaw-kitchen-sink@beta");
105+
expect(script).toContain("clawhub:@openclaw/kitchen-sink@latest");
106+
expect(script).toContain("clawhub:@openclaw/kitchen-sink@beta");
107+
expect(script).toContain(
108+
"npm-to-clawhub|clawhub:@openclaw/kitchen-sink@latest|openclaw-kitchen-sink-fixture|clawhub|success|basic||npm:@openclaw/kitchen-sink@latest",
109+
);
107110
expect(script).toContain("scripts/e2e/lib/kitchen-sink-plugin/sweep.sh");
108111
expect(sweepScript).toContain('plugins install "$KITCHEN_SINK_SPEC"');
112+
expect(sweepScript).toContain('plugins install "$KITCHEN_SINK_PREINSTALL_SPEC"');
113+
expect(sweepScript).toContain("assert-cutover-preinstalled");
114+
expect(sweepScript).toContain('install_args+=("--force")');
109115
expect(sweepScript).toContain("KITCHEN_SINK_PERSONALITY");
110116
expect(sweepScript).toContain("OPENCLAW_KITCHEN_SINK_PERSONALITY");
111117
expect(sweepScript).toContain('plugins uninstall "$KITCHEN_SINK_SPEC" --force');
112118
const successScenario = sweepScript.slice(
113119
sweepScript.indexOf("run_success_scenario()"),
114120
sweepScript.indexOf("run_failure_scenario()"),
115121
);
116-
expect(successScenario.indexOf('plugins install "$KITCHEN_SINK_SPEC"')).toBeLessThan(
122+
expect(successScenario.indexOf('plugins install "${install_args[@]}"')).toBeLessThan(
117123
successScenario.indexOf("configure_kitchen_sink_runtime"),
118124
);
119125
expect(successScenario.indexOf("configure_kitchen_sink_runtime")).toBeLessThan(
@@ -122,6 +128,7 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
122128
expect(successScenario).toContain('plugins inspect "$KITCHEN_SINK_ID" --runtime --json');
123129
expect(successScenario).toContain("plugins inspect --all --runtime --json");
124130
expect(sweepScript).toContain("run_failure_scenario");
131+
expect(assertionsScript).toContain("assertCutoverPreinstalled");
125132
expect(assertionsScript).toContain("record.source !== source");
126133
expect(assertionsScript).toContain("record.clawhubPackage !== packageName");
127134
expect(assertionsScript).toContain("assertClawHubExternalInstallContract");

0 commit comments

Comments
 (0)