// Shared fixtures for the fleet service suites (service.runtime.test.ts and // service-upgrade.runtime.test.ts), which exercise the same createFleetService // seam from opposite ends: cell lifecycle and upgrade/restore. import path from "node:path"; import { vi } from "vitest"; import { cellOwnerId } from "./cell-profile.js"; import type { FleetContainerInspectResult, FleetContainerRuntime } from "./containers.runtime.js"; import { createFleetService as createFleetServiceRuntime } from "./service.runtime.js"; type FleetServiceOptions = NonNullable[0]>; export const TEST_ATTEMPT_ID = "22222222222222222222222222222222"; export const NEXT_ATTEMPT_ID = "44444444444444444444444444444444"; // Each suite sets its per-test root in beforeEach before deriving ownership labels. let suiteRoot = ""; export function setFleetSuiteRoot(root: string): void { suiteRoot = root; } export function createFleetService(options: FleetServiceOptions = {}) { return createFleetServiceRuntime({ probePort: async () => true, ...options }); } export function fleetLabels(tenant = "acme", attemptId = TEST_ATTEMPT_ID): Record { return { "openclaw.fleet.tenant": tenant, "openclaw.fleet.owner": cellOwnerId(path.join(suiteRoot, "fleet", "cells", tenant)), "openclaw.fleet.attempt": attemptId, "openclaw.fleet.env-keys": "FEATURE", }; } export function runningInspection( overrides: Partial> = {}, ): Extract { return { kind: "ok", containerId: "container-id", state: "running", running: true, labels: fleetLabels(), environment: { HOME: "/home/node", OPENCLAW_GATEWAY_TOKEN: "old-token", FEATURE: "enabled", NODE_VERSION: "old-image-default", }, imageId: "sha256:old-image-id", memory: "2147483648", cpus: "2", pidsLimit: 512, storageOpt: {}, capDrop: ["ALL"], effectiveCaps: undefined, securityOpt: ["no-new-privileges"], init: true, restartPolicy: "unless-stopped", portBindings: [{ containerPort: "18789/tcp", hostIp: "127.0.0.1", hostPort: "19100" }], ...overrides, }; } export function createContainerMock( initialInspection: FleetContainerInspectResult = { kind: "missing", state: "missing", }, ) { const assertLocal = vi.fn(async () => undefined); const inspections = new Map(); const removedContainers = new Set(); const inspect = vi.fn(async (_runtime, name) => removedContainers.has(name) ? { kind: "missing", state: "missing" } : (inspections.get(name) ?? initialInspection), ); const networks = new Map< string, Extract>, { kind: "ok" }> >(); const inspectNetwork = vi.fn( async (_runtime, name) => networks.get(name) ?? { kind: "missing" }, ); const isDockerRootless = vi.fn(async () => false); const run = vi.fn(async (profile, start) => { removedContainers.delete(profile.containerName); inspections.set( profile.containerName, runningInspection({ state: start ? "running" : "created", running: start, labels: { ...fleetLabels(profile.tenantId, profile.attemptId), "openclaw.fleet.env-keys": profile.userEnvironmentKeys.toSorted().join(","), }, environment: { ...profile.environment }, containerId: `container-${profile.attemptId}`, imageId: `sha256:${profile.attemptId}`, memory: profile.memory, cpus: profile.cpus, pidsLimit: profile.pidsLimit, }), ); }); const pull = vi.fn(async () => undefined); const createNetwork = vi.fn( async (_runtime, name, labels, options) => { networks.set(name, { kind: "ok", labels: { ...labels }, attachedContainers: [], internal: options.internal, }); }, ); const removeNetwork = vi.fn(async (_runtime, name) => { networks.delete(name); }); const start = vi.fn(async (_runtime, name) => { const current = await inspect("docker", name); if (current.kind === "ok") { inspections.set(name, { ...current, state: "running", running: true }); } }); const stop = vi.fn(async () => undefined); const restart = vi.fn(async () => undefined); const logs = vi.fn(async () => undefined); const remove = vi.fn(async (_runtime, name) => { inspections.delete(name); removedContainers.add(name); inspect.mockResolvedValue({ kind: "missing", state: "missing" }); }); return { runtime: { assertLocal, inspect, inspectNetwork, isDockerRootless, run, pull, createNetwork, removeNetwork, start, stop, restart, logs, remove, }, assertLocal, inspect, inspectNetwork, isDockerRootless, run, pull, createNetwork, removeNetwork, start, stop, restart, logs, remove, }; }