22// Licensed under the MIT license.
33
44import { assert } from "chai" ;
5+ import { AbortController } from "@azure/abort-controller" ;
6+ import { CbsClient , defaultLock , TokenType } from "../src" ;
7+ import { createConnectionStub } from "./utils/createConnectionStub" ;
58import { Connection } from "rhea-promise" ;
69import { stub } from "sinon" ;
7- import { CbsClient , TokenType } from "../src" ;
810
911describe ( "CbsClient" , function ( ) {
1012 const TEST_FAILURE = "Test failure" ;
13+
14+ describe ( "init" , function ( ) {
15+ it ( "honors already aborted abortSignal" , async function ( ) {
16+ const cbsClient = new CbsClient ( new Connection ( ) , "lock" ) ;
17+
18+ // Create an abort signal that is already aborted.
19+ const controller = new AbortController ( ) ;
20+ controller . abort ( ) ;
21+ const signal = controller . signal ;
22+
23+ try {
24+ await cbsClient . init ( { abortSignal : signal } ) ;
25+ throw new Error ( TEST_FAILURE ) ;
26+ } catch ( err ) {
27+ assert . equal ( err . name , "AbortError" ) ;
28+ }
29+ } ) ;
30+
31+ it ( "honors abortSignal inside locking code" , async function ( ) {
32+ const lock = "lock" ;
33+ const cbsClient = new CbsClient ( new Connection ( ) , "lock" ) ;
34+
35+ // Create an abort signal that will be aborted on a future tick of the event loop.
36+ const controller = new AbortController ( ) ;
37+ const signal = controller . signal ;
38+
39+ // Make the existing `init` invocation wait until the abortSignal
40+ // is aborted before acquiring it's lock.
41+ await defaultLock . acquire ( lock , ( done ) => {
42+ setTimeout ( ( ) => {
43+ controller . abort ( ) ;
44+ done ( ) ;
45+ } , 0 ) ;
46+ } ) ;
47+
48+ try {
49+ await cbsClient . init ( { abortSignal : signal } ) ;
50+ throw new Error ( TEST_FAILURE ) ;
51+ } catch ( err ) {
52+ assert . equal ( err . name , "AbortError" ) ;
53+ }
54+ } ) ;
55+
56+ it ( "honors abortSignal" , async function ( ) {
57+ const connectionStub = new Connection ( ) ;
58+ // Stub 'open' because creating a real connection will fail.
59+ stub ( connectionStub , "open" ) . resolves ( { } as any ) ;
60+
61+ const cbsClient = new CbsClient ( connectionStub , "lock" ) ;
62+
63+ // Create an abort signal that will be aborted on a future tick of the event loop.
64+ const controller = new AbortController ( ) ;
65+ const signal = controller . signal ;
66+ setTimeout ( ( ) => controller . abort ( ) , 0 ) ;
67+
68+ try {
69+ await cbsClient . init ( { abortSignal : signal } ) ;
70+ throw new Error ( TEST_FAILURE ) ;
71+ } catch ( err ) {
72+ assert . equal ( err . name , "AbortError" ) ;
73+ }
74+ } ) ;
75+ } ) ;
76+
1177 describe ( "negotiateClaim" , function ( ) {
1278 it ( "throws an error if the cbs link doesn't exist." , async function ( ) {
13- const connectionStub = stub ( new Connection ( ) ) as any ;
14-
79+ const connectionStub = createConnectionStub ( ) ;
1580 const cbsClient = new CbsClient ( connectionStub , "lock" ) ;
81+
1682 try {
1783 await cbsClient . negotiateClaim ( "audience" , "token" , TokenType . CbsTokenTypeSas ) ;
1884 throw new Error ( TEST_FAILURE ) ;
@@ -23,5 +89,49 @@ describe("CbsClient", function() {
2389 ) ;
2490 }
2591 } ) ;
92+
93+ describe ( "cancellation" , function ( ) {
94+ it ( "honors already aborted abortSignal" , async function ( ) {
95+ const connectionStub = createConnectionStub ( ) ;
96+ const cbsClient = new CbsClient ( connectionStub , "lock" ) ;
97+
98+ // Create an abort signal that is already aborted.
99+ const controller = new AbortController ( ) ;
100+ controller . abort ( ) ;
101+ const signal = controller . signal ;
102+
103+ try {
104+ // Pass the already aborted abortSignal to make sure negotiateClaim will exit quickly.
105+ await cbsClient . negotiateClaim ( "audience" , "token" , TokenType . CbsTokenTypeSas , {
106+ abortSignal : signal
107+ } ) ;
108+ throw new Error ( TEST_FAILURE ) ;
109+ } catch ( err ) {
110+ assert . equal ( err . name , "AbortError" ) ;
111+ }
112+ } ) ;
113+
114+ it ( "honors abortSignal" , async function ( ) {
115+ const connectionStub = createConnectionStub ( ) ;
116+ const cbsClient = new CbsClient ( connectionStub , "lock" ) ;
117+
118+ // Call `init()` to ensure the CbsClient has a RequestResponseLink.
119+ await cbsClient . init ( ) ;
120+
121+ // Create an abort signal that will be aborted on a future tick of the event loop.
122+ const controller = new AbortController ( ) ;
123+ const signal = controller . signal ;
124+ setTimeout ( ( ) => controller . abort ( ) , 0 ) ;
125+
126+ try {
127+ await cbsClient . negotiateClaim ( "audience" , "token" , TokenType . CbsTokenTypeSas , {
128+ abortSignal : signal
129+ } ) ;
130+ throw new Error ( TEST_FAILURE ) ;
131+ } catch ( err ) {
132+ assert . equal ( err . name , "AbortError" ) ;
133+ }
134+ } ) ;
135+ } ) ;
26136 } ) ;
27137} ) ;
0 commit comments