
























@@ -389,11 +389,11 @@ describe("createLazyChannelApprovalNativeRuntimeAdapter", () => {
389389const request = makeExecApprovalRequest("exec:in-flight");
390390391391const inflight = approvalRuntime.handleRequested(request);
392-// microtasks 흘려 deliverPending 완료 + bindPending await 진입.
392+// Flush microtasks so deliverPending resolves and bindPending parks at the gate.
393393await new Promise((r) => setTimeout(r, 0));
394394await new Promise((r) => setTimeout(r, 0));
395395396-// stop() — onStopped 가 stopped flag set. bindPending 은 park.
396+// stop() flips the stopped flag while bindPending is parked.
397397await approvalRuntime.stop();
398398bindGate.resolve();
399399await inflight;
@@ -406,4 +406,96 @@ describe("createLazyChannelApprovalNativeRuntimeAdapter", () => {
406406expect(unbind?.binding).toEqual({ bindingId: "bound-in-flight" });
407407expect(unbind?.request).toBe(request);
408408});
409+410+it("invokes cancelDelivered when stop() fires between deliverPending and bindPending", async () => {
411+const deliverGate = { resolve: () => {}, promise: Promise.resolve() };
412+const deliverPromise = new Promise<void>((resolve) => {
413+deliverGate.resolve = resolve;
414+});
415+deliverGate.promise = deliverPromise;
416+const deliveredEntry = { messageId: "pre-bind" };
417+const deliverPending = vi.fn(async () => {
418+await deliverPromise;
419+return deliveredEntry;
420+});
421+const bindPending = vi.fn().mockResolvedValue({ bindingId: "should-not-bind" });
422+const unbindPending = vi.fn();
423+const cancelDelivered = vi.fn();
424+425+const runtime = await createTestApprovalHandler(
426+makeNativeApprovalCapability({
427+ deliverPending,
428+ bindPending,
429+ unbindPending,
430+ cancelDelivered,
431+}),
432+);
433+const approvalRuntime = expectApprovalRuntime(runtime);
434+const request = makeExecApprovalRequest("exec:pre-bind");
435+436+const inflight = approvalRuntime.handleRequested(request);
437+// Flush microtasks so deliverPending is awaited and parked at the gate.
438+await new Promise((r) => setTimeout(r, 0));
439+await new Promise((r) => setTimeout(r, 0));
440+441+// stop() flips the stopped flag while deliverPending is still pending.
442+await approvalRuntime.stop();
443+deliverGate.resolve();
444+await inflight;
445+446+expect(bindPending).not.toHaveBeenCalled();
447+expect(unbindPending).not.toHaveBeenCalled();
448+expect(cancelDelivered).toHaveBeenCalledTimes(1);
449+const cancel = firstCallArg(cancelDelivered) as
450+| { entry?: unknown; request?: unknown; approvalKind?: string }
451+| undefined;
452+expect(cancel?.entry).toBe(deliveredEntry);
453+expect(cancel?.request).toBe(request);
454+expect(cancel?.approvalKind).toBe("exec");
455+});
456+457+it("invokes cancelDelivered when stop() fires after bindPending returned null", async () => {
458+const bindGate = { resolve: () => {}, promise: Promise.resolve() };
459+const bindPromise = new Promise<void>((resolve) => {
460+bindGate.resolve = resolve;
461+});
462+bindGate.promise = bindPromise;
463+const deliveredEntry = { messageId: "post-bind-null" };
464+const deliverPending = vi.fn().mockResolvedValue(deliveredEntry);
465+const bindPending = vi.fn(async () => {
466+await bindPromise;
467+return null;
468+});
469+const unbindPending = vi.fn();
470+const cancelDelivered = vi.fn();
471+472+const runtime = await createTestApprovalHandler(
473+makeNativeApprovalCapability({
474+ deliverPending,
475+ bindPending,
476+ unbindPending,
477+ cancelDelivered,
478+}),
479+);
480+const approvalRuntime = expectApprovalRuntime(runtime);
481+const request = makeExecApprovalRequest("exec:post-bind-null");
482+483+const inflight = approvalRuntime.handleRequested(request);
484+// Flush microtasks so deliverPending resolves and bindPending awaits the gate.
485+await new Promise((r) => setTimeout(r, 0));
486+await new Promise((r) => setTimeout(r, 0));
487+488+// stop() flips the stopped flag while bindPending is parked; it then resolves to null.
489+await approvalRuntime.stop();
490+bindGate.resolve();
491+await inflight;
492+493+expect(unbindPending).not.toHaveBeenCalled();
494+expect(cancelDelivered).toHaveBeenCalledTimes(1);
495+const cancel = firstCallArg(cancelDelivered) as
496+| { entry?: unknown; request?: unknown }
497+| undefined;
498+expect(cancel?.entry).toBe(deliveredEntry);
499+expect(cancel?.request).toBe(request);
500+});
409501});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。