ostool-server 0.7.2

Server for managing development boards, serial sessions, and TFTP artifacts
import "@testing-library/jest-dom/vitest";
import { act, cleanup, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { afterEach, expect, it, vi } from "vitest";
import BoardEditor from "./BoardEditor";
import { admin } from "@/api/events";
import { api } from "@/api/client";
import type { BoardConfig, LoaderDeviceSummary } from "@/types/api";
vi.stubGlobal(
  "ResizeObserver",
  class {
    observe() {}
    unobserve() {}
    disconnect() {}
  },
);
afterEach(() => {
  cleanup();
  vi.restoreAllMocks();
  sessionStorage.clear();
});
function mount(board?: BoardConfig) {
  admin.apply({
    epoch: crypto.randomUUID(),
    revision: 1,
    kind: "snapshot",
    data: {
      boards: board ? [board] : [],
      serial: [],
      loaders: [],
      dtbs: [],
      power_actions: [],
      virtual: { enabled: false, devices: [] },
    },
  });
  render(
    <MemoryRouter
      initialEntries={[
        board ? `/boards/${board.id}` : "/boards/new?mac=02:00:00:00:00:21",
      ]}
    >
      <Routes>
        <Route path="/boards/new" element={<BoardEditor />} />
        <Route path="/boards/:boardId" element={<BoardEditor />} />
      </Routes>
    </MemoryRouter>,
  );
}
it("only prefills the MAC and does not require board identity for a power command", async () => {
  const power = vi.spyOn(api, "powerAction").mockResolvedValue({
    id: "one",
    action: "on",
    state: "succeeded",
    message: "ok",
  });
  mount();
  const user = userEvent.setup();
  expect(screen.getByLabelText("MAC 地址")).toHaveValue("02:00:00:00:00:21");
  expect(screen.getByLabelText("板型")).toHaveValue("");
  expect(screen.getByRole("checkbox", { name: "启用串口" })).not.toBeChecked();
  await user.type(screen.getByLabelText("上电命令"), "true");
  await user.click(screen.getByRole("button", { name: "上电" }));
  expect(power).toHaveBeenCalledOnce();
  expect(power.mock.calls[0][0]).toMatchObject({
    action: "on",
    power_management: { kind: "custom", power_on_cmd: "true" },
  });
  expect(power.mock.calls[0][0]).not.toHaveProperty("board_id");
});
it("preserves typed MAC and input identity while devices arrive", async () => {
  mount();
  const input = screen.getByLabelText("MAC 地址");
  const user = userEvent.setup();
  await user.clear(input);
  await user.type(input, "02:00:00:00:00:");
  act(() =>
    admin.apply({
      epoch: "device-arrived",
      revision: 1,
      kind: "snapshot",
      data: {
        loaders: [
          {
            mac_address: "02:00:00:00:00:22",
            online: true,
            conflict: false,
            bound_board_id: null,
            hardware: {},
            ip_address: "10.0.0.2",
            arch: "x86_64",
          } as LoaderDeviceSummary,
        ],
      },
    }),
  );
  expect(screen.getByLabelText("MAC 地址")).toBe(input);
  expect(input).toHaveValue("02:00:00:00:00:");
  expect(input).toHaveFocus();
  expect(screen.getByRole("button", { name: "发现 1 台设备" })).toBeVisible();
});
it("does not overwrite a local draft when another client edits the board", async () => {
  const board: BoardConfig = {
    id: "one",
    board_type: "arm",
    tags: [],
    notes: null,
    disabled: false,
    serial: null,
    network_identity: null,
    power_management: {
      kind: "custom",
      power_on_cmd: "true",
      power_off_cmd: "true",
    },
    boot: { kind: "pxe", notes: null },
  };
  mount(board);
  const user = userEvent.setup();
  await user.type(screen.getByLabelText("备注"), "draft");
  act(() =>
    admin.apply({
      epoch: "peer",
      revision: 1,
      kind: "snapshot",
      data: { boards: [{ ...board, notes: "remote" }] },
    }),
  );
  expect(screen.getByLabelText("备注")).toHaveValue("draft");
  expect(screen.getByRole("button", { name: "保存开发板" })).toBeDisabled();
  await user.click(screen.getByRole("button", { name: "载入服务器版本" }));
  expect(screen.getByLabelText("备注")).toHaveValue("remote");
});

it("switches to U-Boot without requiring or submitting a stale MAC", async () => {
  const create = vi
    .spyOn(api, "createBoard")
    .mockResolvedValue({} as BoardConfig);
  mount();
  const user = userEvent.setup();
  await user.clear(screen.getByLabelText("MAC 地址"));
  await user.type(screen.getByLabelText("MAC 地址"), "unfinished");
  await user.selectOptions(screen.getByLabelText("启动方式"), "uboot");
  expect(screen.queryByLabelText("MAC 地址")).not.toBeInTheDocument();
  await user.type(screen.getByLabelText("板型"), "arm");
  await user.type(screen.getByLabelText("上电命令"), "true");
  await user.type(screen.getByLabelText("下电命令"), "true");
  await user.click(screen.getByRole("button", { name: "保存开发板" }));
  expect(create).toHaveBeenCalledWith(
    expect.objectContaining({
      boot: expect.objectContaining({ kind: "uboot" }),
      network_identity: null,
    }),
  );
});