@@ -34,6 +34,26 @@ function deferredPromises(count: number): Array<Deferred<void>> {
3434 return deferred ;
3535}
3636
37+ function assertOpCount < T > (
38+ pool : ClientPool < T > ,
39+ grpcClientOpCount : number ,
40+ restClientOpCount : number
41+ ) : void {
42+ let actualGrpcClientOpCount = 0 ;
43+ let actualRestClientOpCount = 0 ;
44+
45+ pool . _activeClients . forEach ( clientConfig => {
46+ if ( clientConfig . grpcEnabled ) {
47+ actualGrpcClientOpCount += clientConfig . activeRequestCount ;
48+ } else {
49+ actualRestClientOpCount += clientConfig . activeRequestCount ;
50+ }
51+ } ) ;
52+
53+ expect ( actualGrpcClientOpCount ) . to . equal ( grpcClientOpCount ) ;
54+ expect ( actualRestClientOpCount ) . to . equal ( restClientOpCount ) ;
55+ }
56+
3757describe ( 'Client pool' , ( ) => {
3858 it ( 'creates new instances as needed' , ( ) => {
3959 const clientPool = new ClientPool < { } > ( 3 , 0 , ( ) => {
@@ -133,6 +153,7 @@ describe('Client pool', () => {
133153 ( ) => operationPromises [ 1 ] . promise
134154 ) ;
135155 expect ( clientPool . size ) . to . equal ( 2 ) ;
156+ assertOpCount ( clientPool , 1 , 1 ) ;
136157
137158 operationPromises [ 0 ] . resolve ( ) ;
138159 operationPromises [ 1 ] . resolve ( ) ;
@@ -156,9 +177,166 @@ describe('Client pool', () => {
156177 ( ) => operationPromises [ 1 ] . promise
157178 ) ;
158179 expect ( clientPool . size ) . to . equal ( 1 ) ;
180+ assertOpCount ( clientPool , 2 , 0 ) ;
181+
182+ operationPromises [ 0 ] . resolve ( ) ;
183+ operationPromises [ 1 ] . resolve ( ) ;
184+ } ) ;
185+
186+ it ( 'does not re-use rest instance after beginning the transition to grpc' , async ( ) => {
187+ const clientPool = new ClientPool < { } > ( 10 , 1 , ( ) => {
188+ return { } ;
189+ } ) ;
190+
191+ const operationPromises = deferredPromises ( 3 ) ;
192+
193+ void clientPool . run (
194+ REQUEST_TAG ,
195+ USE_REST ,
196+ ( ) => operationPromises [ 0 ] . promise
197+ ) ;
198+ void clientPool . run (
199+ REQUEST_TAG ,
200+ USE_GRPC ,
201+ ( ) => operationPromises [ 1 ] . promise
202+ ) ;
203+ void clientPool . run (
204+ REQUEST_TAG ,
205+ USE_REST ,
206+ ( ) => operationPromises [ 2 ] . promise
207+ ) ;
208+
209+ expect ( clientPool . size ) . to . equal ( 2 ) ;
210+ assertOpCount ( clientPool , 2 , 1 ) ;
159211
160212 operationPromises [ 0 ] . resolve ( ) ;
161213 operationPromises [ 1 ] . resolve ( ) ;
214+ operationPromises [ 2 ] . resolve ( ) ;
215+ } ) ;
216+
217+ it ( 'does not re-use rest instance after beginning the transition to grpc - rest operation resolved' , async ( ) => {
218+ const clientPool = new ClientPool < { } > ( 10 , 1 , ( ) => {
219+ return { } ;
220+ } ) ;
221+
222+ const operationPromises = deferredPromises ( 3 ) ;
223+
224+ const restOperation = clientPool . run (
225+ REQUEST_TAG ,
226+ USE_REST ,
227+ ( ) => operationPromises [ 0 ] . promise
228+ ) ;
229+ void clientPool . run (
230+ REQUEST_TAG ,
231+ USE_GRPC ,
232+ ( ) => operationPromises [ 1 ] . promise
233+ ) ;
234+
235+ // resolve rest operation
236+ operationPromises [ 0 ] . resolve ( ) ;
237+ await restOperation ;
238+ expect ( clientPool . opCount ) . to . equal ( 1 ) ;
239+
240+ // Run new rest operation
241+ void clientPool . run (
242+ REQUEST_TAG ,
243+ USE_REST ,
244+ ( ) => operationPromises [ 2 ] . promise
245+ ) ;
246+
247+ // Assert client pool status
248+ expect ( clientPool . size ) . to . equal ( 1 ) ;
249+ assertOpCount ( clientPool , 2 , 0 ) ;
250+
251+ operationPromises [ 1 ] . resolve ( ) ;
252+ operationPromises [ 2 ] . resolve ( ) ;
253+ } ) ;
254+
255+ it ( 'does not re-use rest instance after beginning the transition to grpc - grpc client full' , async ( ) => {
256+ const operationLimit = 10 ;
257+ const clientPool = new ClientPool < { } > ( operationLimit , 1 , ( ) => {
258+ return { } ;
259+ } ) ;
260+
261+ const restPromises = deferredPromises ( operationLimit ) ;
262+ const grpcPromises = deferredPromises ( 1 ) ;
263+
264+ // First operation use GRPC
265+ void clientPool . run ( REQUEST_TAG , USE_GRPC , ( ) => grpcPromises [ 0 ] . promise ) ;
266+
267+ // Next X operations can use rest, this will fill the first
268+ // client and create a new client.
269+ // The new client should use GRPC since we have transitioned.
270+ restPromises . forEach ( restPromise => {
271+ void clientPool . run ( REQUEST_TAG , USE_REST , ( ) => restPromise . promise ) ;
272+ } ) ;
273+ expect ( clientPool . opCount ) . to . equal ( 11 ) ;
274+ expect ( clientPool . size ) . to . equal ( 2 ) ;
275+ assertOpCount ( clientPool , 11 , 0 ) ;
276+
277+ grpcPromises . forEach ( grpcPromise => grpcPromise . resolve ( ) ) ;
278+ restPromises . forEach ( restPromise => restPromise . resolve ( ) ) ;
279+ } ) ;
280+
281+ it ( 'does not re-use rest instance after beginning the transition to grpc - multiple rest clients' , async ( ) => {
282+ const operationLimit = 10 ;
283+ const clientPool = new ClientPool < { } > ( operationLimit , 1 , ( ) => {
284+ return { } ;
285+ } ) ;
286+
287+ const restPromises = deferredPromises ( 15 ) ;
288+ const grpcPromises = deferredPromises ( 5 ) ;
289+
290+ // First 15 operations can use rest, this will fill the first
291+ // client and create a new client.
292+ restPromises . forEach ( restPromise => {
293+ void clientPool . run ( REQUEST_TAG , USE_REST , ( ) => restPromise . promise ) ;
294+ } ) ;
295+ expect ( clientPool . opCount ) . to . equal ( 15 ) ;
296+ expect ( clientPool . size ) . to . equal ( 2 ) ;
297+ assertOpCount ( clientPool , 0 , 15 ) ;
298+
299+ // Next 5 operations alternate between gRPC and REST, this will create a new client using gRPC
300+ let transport = USE_GRPC ;
301+ grpcPromises . forEach ( grpcPromise => {
302+ void clientPool . run ( REQUEST_TAG , transport , ( ) => grpcPromise . promise ) ;
303+ transport = ! transport ;
304+ } ) ;
305+ expect ( clientPool . opCount ) . to . equal ( 20 ) ;
306+ expect ( clientPool . size ) . to . equal ( 3 ) ;
307+ assertOpCount ( clientPool , 5 , 15 ) ;
308+
309+ grpcPromises . forEach ( grpcPromise => grpcPromise . resolve ( ) ) ;
310+ restPromises . forEach ( restPromise => restPromise . resolve ( ) ) ;
311+ } ) ;
312+
313+ it ( 'does not re-use rest instance after beginning the transition to grpc - grpc client RST_STREAM' , async ( ) => {
314+ const clientPool = new ClientPool < { } > ( 10 , 1 , ( ) => {
315+ return { } ;
316+ } ) ;
317+
318+ const operationPromises = deferredPromises ( 1 ) ;
319+
320+ const grpcOperation = clientPool . run ( REQUEST_TAG , USE_GRPC , ( ) =>
321+ Promise . reject (
322+ new GoogleError ( '13 INTERNAL: Received RST_STREAM with code 2' )
323+ )
324+ ) ;
325+
326+ await grpcOperation . catch ( e => e ) ;
327+
328+ // Run new rest operation
329+ void clientPool . run (
330+ REQUEST_TAG ,
331+ USE_REST ,
332+ ( ) => operationPromises [ 0 ] . promise
333+ ) ;
334+
335+ // Assert client pool status
336+ expect ( clientPool . size ) . to . equal ( 1 ) ;
337+ assertOpCount ( clientPool , 1 , 0 ) ;
338+
339+ operationPromises [ 0 ] . resolve ( ) ;
162340 } ) ;
163341
164342 it ( 'bin packs operations' , async ( ) => {
0 commit comments