Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/JAVA/Openclaw/extensions/voice-call/src/webhook/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 5 kB image not shown  

Quelle  tailscale.test.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import { EventEmitter } from "node:events";
import { beforeEach, describe, expect, it, vi } from "vitest";

const { spawnMock } = vi.hoisted(() => ({
  spawnMock: vi.fn(),
}));

vi.mock("node:child_process", async () => {
  const { mockNodeBuiltinModule } = await import("../../../../test/helpers/node-builtin-mocks.js");
  return mockNodeBuiltinModule(
    () => vi.importActual<typeof import("node:child_process")>("node:child_process"),
    {
      spawn: spawnMock,
    },
  );
});

import {
  cleanupTailscaleExposure,
  cleanupTailscaleExposureRoute,
  getTailscaleDnsName,
  getTailscaleSelfInfo,
  setupTailscaleExposure,
  setupTailscaleExposureRoute,
} from "./tailscale.js";

function createProc(params?: { code?: number; stdout?: string }) {
  const proc = new EventEmitter() as EventEmitter & {
    stdout: EventEmitter;
    kill: ReturnType<typeof vi.fn>;
  };
  proc.stdout = new EventEmitter();
  proc.kill = vi.fn();
  setTimeout(() => {
    if (params?.stdout) {
      proc.stdout.emit("data", Buffer.from(params.stdout));
    }
    proc.emit("close", params?.code ?? 0);
  }, 0);
  return proc;
}

function createErrorProc() {
  const proc = new EventEmitter() as EventEmitter & {
    stdout: EventEmitter;
    kill: ReturnType<typeof vi.fn>;
  };
  proc.stdout = new EventEmitter();
  proc.kill = vi.fn();
  setTimeout(() => {
    proc.emit("error", Object.assign(new Error("spawn tailscale ENOENT"), { code: "ENOENT" }));
  }, 0);
  return proc;
}

describe("voice-call tailscale helpers", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("reads dns and node id from tailscale status json", async () => {
    spawnMock
      .mockReturnValueOnce(
        createProc({
          stdout: JSON.stringify({
            Self: {
              DNSName: "bot.example.ts.net.",
              ID: "node-123",
            },
          }),
        }),
      )
      .mockReturnValueOnce(
        createProc({
          stdout: JSON.stringify({
            Self: {
              DNSName: "bot.example.ts.net.",
              ID: "node-123",
            },
          }),
        }),
      );

    await expect(getTailscaleSelfInfo()).resolves.toEqual({
      dnsName: "bot.example.ts.net",
      nodeId: "node-123",
    });
    await expect(getTailscaleDnsName()).resolves.toBe("bot.example.ts.net");
  });

  it("returns null for failing or invalid status responses", async () => {
    spawnMock.mockReturnValueOnce(createProc({ code: 1, stdout: "bad" }));
    await expect(getTailscaleSelfInfo()).resolves.toBeNull();

    spawnMock.mockReturnValueOnce(createProc({ stdout: "{not-json" }));
    await expect(getTailscaleSelfInfo()).resolves.toBeNull();
  });

  it("treats missing tailscale binary as unavailable instead of leaking spawn errors", async () => {
    spawnMock.mockReturnValueOnce(createErrorProc());

    await expect(getTailscaleSelfInfo()).resolves.toBeNull();
  });

  it("sets up and cleans up exposure routes with the selected mode", async () => {
    spawnMock
      .mockReturnValueOnce(
        createProc({
          stdout: JSON.stringify({ Self: { DNSName: "bot.example.ts.net." } }),
        }),
      )
      .mockReturnValueOnce(createProc({ code: 0 }))
      .mockReturnValueOnce(createProc({ code: 0 }));

    await expect(
      setupTailscaleExposureRoute({
        mode: "serve",
        path: "/voice",
        localUrl: "http://127.0.0.1:8787/webhook",
      }),
    ).resolves.toBe("https://bot.example.ts.net/voice");

    await cleanupTailscaleExposureRoute({ mode: "serve", path: "/voice" });

    expect(spawnMock).toHaveBeenNthCalledWith(
      1,
      "tailscale",
      ["status", "--json"],
      expect.objectContaining({ stdio: ["ignore", "pipe", "pipe"] }),
    );
    expect(spawnMock).toHaveBeenNthCalledWith(
      2,
      "tailscale",
      ["serve", "--bg", "--yes", "--set-path", "/voice", "http://127.0.0.1:8787/webhook"],
      expect.any(Object),
    );
    expect(spawnMock).toHaveBeenNthCalledWith(
      3,
      "tailscale",
      ["serve", "off", "/voice"],
      expect.any(Object),
    );
  });

  it("returns null when setup cannot resolve dns or route activation fails", async () => {
    spawnMock
      .mockReturnValueOnce(createProc({ code: 1 }))
      .mockReturnValueOnce(
        createProc({
          stdout: JSON.stringify({ Self: { DNSName: "bot.example.ts.net." } }),
        }),
      )
      .mockReturnValueOnce(createProc({ code: 1 }));

    await expect(
      setupTailscaleExposureRoute({
        mode: "funnel",
        path: "/voice",
        localUrl: "http://127.0.0.1:8787/webhook",
      }),
    ).resolves.toBeNull();

    await expect(
      setupTailscaleExposureRoute({
        mode: "funnel",
        path: "/voice",
        localUrl: "http://127.0.0.1:8787/webhook",
      }),
    ).resolves.toBeNull();
  });

  it("maps config modes to serve or funnel and skips off", async () => {
    spawnMock
      .mockReturnValueOnce(
        createProc({
          stdout: JSON.stringify({ Self: { DNSName: "bot.example.ts.net." } }),
        }),
      )
      .mockReturnValueOnce(createProc({ code: 0 }))
      .mockReturnValueOnce(createProc({ code: 0 }));

    await expect(
      setupTailscaleExposure({
        tailscale: { mode: "off", path: "/voice" },
        serve: { port: 8787, path: "/webhook" },
      } as never),
    ).resolves.toBeNull();

    await expect(
      setupTailscaleExposure({
        tailscale: { mode: "funnel", path: "/voice" },
        serve: { port: 8787, path: "/webhook" },
      } as never),
    ).resolves.toBe("https://bot.example.ts.net/voice");

    await cleanupTailscaleExposure({
      tailscale: { mode: "serve", path: "/voice" },
      serve: { port: 8787, path: "/webhook" },
    } as never);

    expect(spawnMock).toHaveBeenNthCalledWith(
      2,
      "tailscale",
      ["funnel", "--bg", "--yes", "--set-path", "/voice", "http://127.0.0.1:8787/webhook"],
      expect.any(Object),
    );
    expect(spawnMock).toHaveBeenNthCalledWith(
      3,
      "tailscale",
      ["serve", "off", "/voice"],
      expect.any(Object),
    );
  });
});

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.