/* * Copyright 2023 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import * as assert from 'assert'; import * as path from 'path'; import * as grpc from '../src'; import { sendUnaryData, Server, ServerCredentials, ServerUnaryCall, ServiceClientConstructor, ServiceError, } from '../src'; import { loadProtoFile } from './common'; const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); const echoService = loadProtoFile(protoFile) .EchoService as ServiceClientConstructor; describe('Global subchannel pool', () => { let server: Server; let serverPort: number; let client1: InstanceType; let client2: InstanceType; let promises: Promise[]; before(done => { server = new Server(); server.addService(echoService.service, { echo(call: ServerUnaryCall, callback: sendUnaryData) { callback(null, call.request); }, }); server.bindAsync( 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { assert.ifError(err); serverPort = port; server.start(); done(); } ); }); beforeEach(() => { promises = []; }); after(done => { server.tryShutdown(done); }); function callService(client: InstanceType) { return new Promise(resolve => { const request = { value: 'test value', value2: 3 }; client.echo(request, (error: ServiceError, response: any) => { assert.ifError(error); assert.deepStrictEqual(response, request); resolve(); }); }); } function connect() { const grpcOptions = { 'grpc.use_local_subchannel_pool': 0, }; client1 = new echoService( `127.0.0.1:${serverPort}`, grpc.credentials.createInsecure(), grpcOptions ); client2 = new echoService( `127.0.0.1:${serverPort}`, grpc.credentials.createInsecure(), grpcOptions ); } /* This is a regression test for a bug where client1.close in the * waitForReady callback would cause the subchannel to transition to IDLE * even though client2 is also using it. */ it('Should handle client.close calls in waitForReady', done => { connect(); promises.push( new Promise(resolve => { client1.waitForReady(Date.now() + 50, error => { assert.ifError(error); client1.close(); resolve(); }); }) ); promises.push( new Promise(resolve => { client2.waitForReady(Date.now() + 50, error => { assert.ifError(error); resolve(); }); }) ); Promise.all(promises).then(() => { done(); }); }); it('Call the service', done => { promises.push(callService(client2)); Promise.all(promises).then(() => { done(); }); }); it('Should complete the client lifecycle without error', done => { setTimeout(() => { client1.close(); client2.close(); done(); }, 500); }); });