Some checks failed
CI/CD / lint (pull_request) Failing after 13s
CI/CD / test (pull_request) Failing after 10s
CI/CD / typecheck (pull_request) Failing after 36s
CI/CD / build (pull_request) Has been skipped
CI/CD / publish-rpm (pull_request) Has been skipped
CI/CD / publish-deb (pull_request) Has been skipped
Kickstart installs on real hardware failed silently — no error reporting, only 3 progress callbacks, zero log streaming. This overhaul makes every install fully observable. Kickstart improvements: - Error trapping in %pre and %post (trap ERR sends failure details to bastion) - 12+ granular progress stages (was 3): SSH, hostname, k3s prep, EFI boot, metadata - Background log streamer: tails %post output and batch-sends to /api/log - bastion_log() function for explicit log lines from kickstart scripts Bastion API: - POST /api/log — receives raw log lines from kickstart (single or batch) - InstallLogBuffer — per-MAC ring buffer (2000 lines) + file persistence - GET /api/logs/:mac — now returns log_lines + log_total alongside stages - SSE /api/logs/:mac/follow — uses named events (event: stage vs event: log) - Progress events forwarded to labd via bastion-progress WebSocket message - Post-provision k3s logs routed through progressBus (was console-only) dnsmasq fixes found during VM testing: - HTTP Boot filename: ipxe-real.efi → ipxe.efi (leftover from old 2-stage approach) - pxe-service directives: only in proxy mode (breaks OVMF PXE in full mode) - PXEClient vendor class echo for UEFI firmware compatibility Integration tests: - PXE boot test: blank UEFI VM → dnsmasq → HTTP Boot → iPXE → bastion → install - ISO boot test: blank VM boots from bastion-generated ISO → same flow - Shared helpers: pxe-network (no DHCP, nftables fix), pxe-vm (UEFI + ISO boot) - test-provision.sh: runs both PXE + ISO tests with prerequisite checks - 250GB sparse QCOW2 disk (LVM layout needs ~204GB) 201 unit tests passing (11 new). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
// Tests for LabdApiError.
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { LabdApiError, isLabdApiError } from "../src/api/errors.js";
|
|
|
|
describe("LabdApiError", () => {
|
|
it("constructs with status code and message", () => {
|
|
const err = new LabdApiError(404, "Not found");
|
|
expect(err.statusCode).toBe(404);
|
|
expect(err.message).toBe("Not found");
|
|
expect(err.errorCode).toBe("NOT_FOUND");
|
|
});
|
|
|
|
it("fromResponse parses error body", () => {
|
|
const err = LabdApiError.fromResponse(400, {
|
|
error: "Invalid input",
|
|
detail: "hostname required",
|
|
});
|
|
expect(err.statusCode).toBe(400);
|
|
expect(err.message).toBe("Invalid input");
|
|
expect(err.detail).toBe("hostname required");
|
|
});
|
|
|
|
it("fromResponse handles non-object body", () => {
|
|
const err = LabdApiError.fromResponse(500, "plain text");
|
|
expect(err.statusCode).toBe(500);
|
|
expect(err.message).toBe("HTTP 500");
|
|
});
|
|
|
|
it("notConnected creates connection error", () => {
|
|
const err = LabdApiError.notConnected("https://localhost:8443");
|
|
expect(err.statusCode).toBe(0);
|
|
expect(err.errorCode).toBe("CONNECTION_ERROR");
|
|
expect(err.message).toContain("localhost:8443");
|
|
});
|
|
|
|
it("timeout creates timeout error", () => {
|
|
const err = LabdApiError.timeout(30000);
|
|
expect(err.message).toContain("30000ms");
|
|
});
|
|
});
|
|
|
|
describe("isLabdApiError", () => {
|
|
it("returns true for LabdApiError", () => {
|
|
expect(isLabdApiError(new LabdApiError(500, "err"))).toBe(true);
|
|
});
|
|
|
|
it("returns false for regular Error", () => {
|
|
expect(isLabdApiError(new Error("nope"))).toBe(false);
|
|
});
|
|
|
|
it("returns false for non-errors", () => {
|
|
expect(isLabdApiError(null)).toBe(false);
|
|
expect(isLabdApiError("string")).toBe(false);
|
|
});
|
|
});
|