























@@ -64,11 +64,16 @@ function mockCiaoService(params?: {
6464serviceState?: string;
6565stateRef?: { value: string };
6666on?: ReturnType<typeof vi.fn>;
67+listenerMap?: Map<string, (value: unknown) => void>;
6768responder?: Record<string, unknown>;
6869}) {
6970const advertise = params?.advertise ?? vi.fn().mockResolvedValue(undefined);
7071const destroy = params?.destroy ?? vi.fn().mockResolvedValue(undefined);
71-const on = params?.on ?? vi.fn();
72+const on =
73+params?.on ??
74+vi.fn((event: string, listener: (value: unknown) => void) => {
75+params?.listenerMap?.set(event, listener);
76+});
7277createService.mockImplementation((options: Record<string, unknown>) => {
7378const service = {
7479 advertise,
@@ -695,18 +700,8 @@ describe("gateway bonjour advertiser", () => {
695700vi.useFakeTimers();
696701697702const stateRef = { value: "probing" };
698-let advertiseCount = 0;
699703const destroy = vi.fn().mockResolvedValue(undefined);
700-const advertise = vi.fn().mockImplementation(() => {
701-advertiseCount += 1;
702-if (advertiseCount === 2) {
703-stateRef.value = "announcing";
704-}
705-if (advertiseCount >= 3) {
706-stateRef.value = "announced";
707-}
708-return Promise.resolve();
709-});
704+const advertise = vi.fn().mockResolvedValue(undefined);
710705mockCiaoService({ advertise, destroy, stateRef });
711706712707const started = await startAdvertiser({
@@ -717,18 +712,87 @@ describe("gateway bonjour advertiser", () => {
717712expect(createService).toHaveBeenCalledTimes(1);
718713expect(advertise).toHaveBeenCalledTimes(1);
719714715+setTimeout(() => {
716+stateRef.value = "announcing";
717+}, 10_000);
718+720719await vi.advanceTimersByTimeAsync(25_000);
721720722721expectWarnContaining("service stuck in announcing");
723722expect(createService).toHaveBeenCalledTimes(2);
724-expect(advertise).toHaveBeenCalledTimes(3);
723+expect(advertise).toHaveBeenCalledTimes(2);
725724expect(destroy).toHaveBeenCalledTimes(1);
726725expect(shutdown).not.toHaveBeenCalled();
727726728727await started.stop();
729728expect(shutdown).toHaveBeenCalledTimes(1);
730729});
731730731+it("does not re-advertise while ciao is still probing", async () => {
732+enableAdvertiserUnitMode();
733+vi.useFakeTimers();
734+735+const stateRef = { value: "probing" };
736+const destroy = vi.fn().mockResolvedValue(undefined);
737+const advertise = vi.fn().mockResolvedValue(undefined);
738+mockCiaoService({ advertise, destroy, stateRef });
739+740+const started = await startAdvertiser({
741+gatewayPort: 18789,
742+sshPort: 2222,
743+});
744+745+expect(advertise).toHaveBeenCalledTimes(1);
746+747+await vi.advanceTimersByTimeAsync(15_000);
748+749+expect(advertise).toHaveBeenCalledTimes(1);
750+expect(createService).toHaveBeenCalledTimes(1);
751+expect(logger.warn).not.toHaveBeenCalledWith(
752+expect.stringContaining("watchdog detected non-announced service; attempting re-advertise"),
753+);
754+755+await vi.advanceTimersByTimeAsync(10_000);
756+757+expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining("service stuck in probing"));
758+expect(createService).toHaveBeenCalledTimes(2);
759+760+await started.stop();
761+});
762+763+it("defers probing recovery while a name conflict is still settling", async () => {
764+enableAdvertiserUnitMode();
765+vi.useFakeTimers();
766+767+const stateRef = { value: "probing" };
768+const destroy = vi.fn().mockResolvedValue(undefined);
769+const advertise = vi.fn().mockResolvedValue(undefined);
770+const listenerMap = new Map<string, (value: unknown) => void>();
771+mockCiaoService({ advertise, destroy, stateRef, listenerMap });
772+773+const started = await startAdvertiser({
774+gatewayPort: 18789,
775+sshPort: 2222,
776+});
777+778+await vi.advanceTimersByTimeAsync(10_000);
779+listenerMap.get("name-change")?.("test-host (OpenClaw) (2)");
780+781+await vi.advanceTimersByTimeAsync(15_000);
782+783+expect(createService).toHaveBeenCalledTimes(1);
784+expect(logger.warn).toHaveBeenCalledWith(
785+expect.stringContaining('name conflict resolved; newName="test-host (OpenClaw) (2)"'),
786+);
787+788+await vi.advanceTimersByTimeAsync(20_000);
789+790+expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining("service stuck in probing"));
791+expect(createService).toHaveBeenCalledTimes(2);
792+793+await started.stop();
794+});
795+732796it("disables bonjour for the process after repeated stuck advertiser restarts", async () => {
733797enableAdvertiserUnitMode();
734798vi.useFakeTimers();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。