
























@@ -2,6 +2,7 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
2233const listDevicePairingMock = vi.fn();
44const loadApnsRegistrationMock = vi.fn();
5+const loadApnsRegistrationsMock = vi.fn();
56const resolveApnsAuthConfigFromEnvMock = vi.fn();
67const resolveApnsRelayConfigFromEnvMock = vi.fn();
78const sendApnsExecApprovalAlertMock = vi.fn();
@@ -68,6 +69,7 @@ vi.mock("../infra/device-pairing.js", async () => {
68696970vi.mock("../infra/push-apns.js", () => ({
7071loadApnsRegistration: loadApnsRegistrationMock,
72+loadApnsRegistrations: loadApnsRegistrationsMock,
7173resolveApnsAuthConfigFromEnv: resolveApnsAuthConfigFromEnvMock,
7274resolveApnsRelayConfigFromEnv: resolveApnsRelayConfigFromEnvMock,
7375sendApnsExecApprovalAlert: sendApnsExecApprovalAlertMock,
@@ -92,6 +94,16 @@ describe("createExecApprovalIosPushDelivery", () => {
9294environment: "sandbox",
9395updatedAtMs: 1,
9496});
97+loadApnsRegistrationsMock.mockImplementation(async (nodeIds: readonly string[]) => {
98+const registrations = [];
99+for (const nodeId of nodeIds) {
100+const registration = await loadApnsRegistrationMock(nodeId);
101+if (registration) {
102+registrations.push({ nodeId, registration });
103+}
104+}
105+return registrations;
106+});
95107resolveApnsAuthConfigFromEnvMock.mockResolvedValue({
96108ok: true,
97109value: { teamId: "team", keyId: "key", privateKey: "private-key" },
@@ -150,7 +162,7 @@ describe("createExecApprovalIosPushDelivery", () => {
150162});
151163152164expect(accepted).toBe(false);
153-expect(loadApnsRegistrationMock).not.toHaveBeenCalled();
165+expect(loadApnsRegistrationsMock).not.toHaveBeenCalled();
154166expect(sendApnsExecApprovalAlertMock).not.toHaveBeenCalled();
155167});
156168@@ -167,10 +179,64 @@ describe("createExecApprovalIosPushDelivery", () => {
167179});
168180169181expect(accepted).toBe(true);
170-expect(loadApnsRegistrationMock).toHaveBeenCalledWith("ios-device-1");
182+expect(loadApnsRegistrationsMock).toHaveBeenCalledWith(["ios-device-1"]);
171183expect(sendApnsExecApprovalAlertMock).toHaveBeenCalledTimes(1);
172184});
173185186+it("loads APNs registrations in one bulk read for all visible iOS operators", async () => {
187+listDevicePairingMock.mockResolvedValue({
188+pending: [],
189+paired: [
190+{
191+deviceId: "ios-device-1",
192+publicKey: "pub-1",
193+platform: "iOS 18",
194+role: "operator",
195+roles: ["operator"],
196+createdAtMs: 1,
197+approvedAtMs: 1,
198+tokens: {
199+operator: {
200+token: "operator-token-1",
201+role: "operator",
202+scopes: ["operator.approvals"],
203+createdAtMs: 1,
204+},
205+},
206+},
207+{
208+deviceId: "ios-device-2",
209+publicKey: "pub-2",
210+platform: "iPadOS 18",
211+role: "operator",
212+roles: ["operator"],
213+createdAtMs: 1,
214+approvedAtMs: 2,
215+tokens: {
216+operator: {
217+token: "operator-token-2",
218+role: "operator",
219+scopes: ["operator.approvals"],
220+createdAtMs: 1,
221+},
222+},
223+},
224+],
225+});
226+227+const delivery = createExecApprovalIosPushDelivery({ log: {} });
228+229+await delivery.handleRequested({
230+id: "approval-bulk-load",
231+request: { command: "echo ok", host: "gateway", allowedDecisions: ["allow-once"] },
232+createdAtMs: 1,
233+expiresAtMs: 2,
234+});
235+236+expect(loadApnsRegistrationsMock).toHaveBeenCalledTimes(1);
237+expect(loadApnsRegistrationsMock).toHaveBeenCalledWith(["ios-device-1", "ios-device-2"]);
238+});
239+174240it("does not target iOS devices rejected by the approval visibility filter", async () => {
175241mockPairedIosOperator(["operator.approvals", "operator.read"]);
176242const isTargetVisible = vi.fn(() => false);
@@ -192,7 +258,7 @@ describe("createExecApprovalIosPushDelivery", () => {
192258deviceId: "ios-device-1",
193259scopes: ["operator.approvals", "operator.read"],
194260});
195-expect(loadApnsRegistrationMock).not.toHaveBeenCalled();
261+expect(loadApnsRegistrationsMock).not.toHaveBeenCalled();
196262expect(sendApnsExecApprovalAlertMock).not.toHaveBeenCalled();
197263});
198264@@ -285,7 +351,7 @@ describe("createExecApprovalIosPushDelivery", () => {
285351"exec approvals: iOS cleanup push skipped approvalId=approval-missing-targets reason=missing-targets",
286352);
287353expect(listDevicePairingMock).not.toHaveBeenCalled();
288-expect(loadApnsRegistrationMock).not.toHaveBeenCalled();
354+expect(loadApnsRegistrationsMock).not.toHaveBeenCalled();
289355expect(sendApnsExecApprovalResolvedWakeMock).not.toHaveBeenCalled();
290356});
291357@@ -321,7 +387,7 @@ describe("createExecApprovalIosPushDelivery", () => {
321387});
322388323389expect(listDevicePairingMock).not.toHaveBeenCalled();
324-expect(loadApnsRegistrationMock).toHaveBeenCalledWith("ios-device-1");
390+expect(loadApnsRegistrationsMock).toHaveBeenCalledWith(["ios-device-1"]);
325391expect(sendApnsExecApprovalResolvedWakeMock).toHaveBeenCalledTimes(1);
326392});
327393});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。