mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
fix(environments): address sandbox probe review notes
This commit is contained in:
1 parent
6aed879611
commit
21040bad77
4 files changed
+83
-2
No files matched your search
@@ -459,6 +459,43 @@ describeEmbeddedPostgres("environmentCustomImageService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not rewrite generic missing image setup failures as template conflicts", async () => {
|
||||
const { environmentId } = await seed();
|
||||
const workerManager = createWorkerManager();
|
||||
workerManager.call.mockImplementation(async (_pluginId, method) => {
|
||||
if (method === "environmentStartInteractiveSetup") {
|
||||
throw new Error("Base image not found in registry");
|
||||
}
|
||||
throw new Error(`Unexpected plugin call: ${method}`);
|
||||
});
|
||||
const service = environmentCustomImageService(db, { pluginWorkerManager: workerManager });
|
||||
const [template] = await db.insert(environmentCustomImageTemplates).values({
|
||||
environmentId,
|
||||
provider: "fake-plugin",
|
||||
templateKind: "snapshot",
|
||||
templateRef: "snapshot-valid",
|
||||
status: "active",
|
||||
}).returning();
|
||||
|
||||
await expect(service.startSetupSession({
|
||||
environmentId,
|
||||
templateId: template!.id,
|
||||
actor: { userId: "user-1" },
|
||||
})).rejects.toThrow("Base image not found in registry");
|
||||
|
||||
const [session] = await db
|
||||
.select({
|
||||
status: environmentCustomImageSetupSessions.status,
|
||||
failureReason: environmentCustomImageSetupSessions.failureReason,
|
||||
})
|
||||
.from(environmentCustomImageSetupSessions)
|
||||
.where(eq(environmentCustomImageSetupSessions.templateId, template!.id));
|
||||
expect(session).toEqual({
|
||||
status: "failed",
|
||||
failureReason: "Base image not found in registry",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies the active template regardless of base-config changes and falls back when none exists", async () => {
|
||||
const { companyId, environmentId } = await seed();
|
||||
const environment = await db.select().from(environments).where(eq(environments.id, environmentId)).then((rows) => rows[0]!);
|
||||
|
||||
@@ -192,7 +192,7 @@ function providerErrorMessage(error: unknown): string {
|
||||
function isProviderMissingTemplateError(error: unknown): boolean {
|
||||
const message = providerErrorMessage(error).toLowerCase();
|
||||
return (
|
||||
(message.includes("snapshot") || message.includes("template") || message.includes("image"))
|
||||
(message.includes("snapshot") || message.includes("template"))
|
||||
&& (message.includes("not found") || message.includes("missing"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -531,6 +531,50 @@ describe("CompanyEnvironments — test provider button", () => {
|
||||
expect(container.textContent).toContain("Test probes clean up the validation sandbox after the check");
|
||||
});
|
||||
|
||||
it("does not show sandbox lifecycle success copy for failed sandbox provider tests", async () => {
|
||||
root = createRoot(container);
|
||||
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
mockEnvironmentsApi.list.mockResolvedValue([
|
||||
{ id: "env-1", name: "Daytona", driver: "sandbox", description: null, config: { provider: "daytona" } },
|
||||
]);
|
||||
mockEnvironmentsApi.capabilities.mockResolvedValue(supportedDaytonaCapabilities());
|
||||
mockEnvironmentsApi.probe.mockResolvedValue({
|
||||
ok: false,
|
||||
driver: "sandbox",
|
||||
summary: "Daytona sandbox probe failed.",
|
||||
details: {
|
||||
provider: "daytona",
|
||||
error: "Sandbox image was not found.",
|
||||
metadata: {
|
||||
provider: "daytona",
|
||||
sandboxId: "473167E9",
|
||||
sandboxName: "paperclip-probe",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
<CompanyEnvironments />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
await flushReact();
|
||||
|
||||
await act(async () => {
|
||||
testProviderButtons(container)[0].dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flushReact();
|
||||
|
||||
expect(container.textContent).toContain("Daytona sandbox probe failed.");
|
||||
expect(container.textContent).toContain("Sandbox image was not found.");
|
||||
expect(container.textContent).not.toContain("Verified temporary daytona sandbox");
|
||||
expect(container.textContent).not.toContain("Test probes clean up the validation sandbox after the check");
|
||||
});
|
||||
|
||||
it("keeps the second environment's testing state when an earlier probe settles", async () => {
|
||||
root = createRoot(container);
|
||||
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
|
||||
@@ -215,7 +215,7 @@ function readStringValue(value: unknown): string | null {
|
||||
}
|
||||
|
||||
function sandboxProbeLifecycleNote(probe: EnvironmentProbeResult): string | null {
|
||||
if (probe.driver !== "sandbox") return null;
|
||||
if (probe.driver !== "sandbox" || !probe.ok) return null;
|
||||
const metadata = readProbeMetadata(probe);
|
||||
const provider = readStringValue(metadata.provider) ?? readStringValue(readRecord(probe.details)?.provider) ?? "sandbox";
|
||||
const sandboxName = readStringValue(metadata.sandboxName);
|
||||
|
||||
Reference in new issue
Block a user