mirror of https://github.com/grpc/grpc-node.git
359 lines
14 KiB
JavaScript
359 lines
14 KiB
JavaScript
/*
|
|
*
|
|
* Copyright 2019 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.
|
|
*
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const interopServer = require('../interop/interop_server.js');
|
|
const anyGrpc = require('../any_grpc');
|
|
const grpc = anyGrpc.client;
|
|
var protoLoader = require('../../packages/proto-loader');
|
|
|
|
const protoPackage = protoLoader.loadSync(
|
|
'src/proto/grpc/testing/test.proto',
|
|
{keepCase: true,
|
|
defaults: true,
|
|
enums: String,
|
|
includeDirs: [__dirname + '/../proto/']});
|
|
const testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing;
|
|
|
|
function multiDone(done, count) {
|
|
return function() {
|
|
count -= 1;
|
|
if (count <= 0) {
|
|
done();
|
|
}
|
|
};
|
|
}
|
|
|
|
function echoMetadataGenerator(options, callback) {
|
|
const metadata = new grpc.Metadata();
|
|
metadata.set('x-grpc-test-echo-initial', 'test_initial_metadata_value');
|
|
callback(null, metadata);
|
|
}
|
|
|
|
const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator);
|
|
|
|
describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() {
|
|
describe('Interop-adjacent tests', function() {
|
|
let server;
|
|
let client;
|
|
let port;
|
|
before(function(done) {
|
|
/* To make testing max message size enforcement easier, the we explicitly
|
|
* remove the limit on the size of messages the server can receive, and
|
|
* we expect that the size of messages it can send is unlimited by
|
|
* default. On the other side, we explicitly limit the size of messages
|
|
* the client can send to 4 MB, and we expect that the size of messages
|
|
* it can receive is limited to 4 MB by default */
|
|
interopServer.getServer(0, true, (err, serverObj) => {
|
|
if (err) {
|
|
done(err);
|
|
} else {
|
|
server = serverObj.server;
|
|
port = serverObj.port;
|
|
server.start();
|
|
const ca_path = path.join(__dirname, '../data/ca.pem');
|
|
const ca_data = fs.readFileSync(ca_path);
|
|
const creds = grpc.credentials.createSsl(ca_data);
|
|
const options = {
|
|
'grpc.ssl_target_name_override': 'foo.test.google.fr',
|
|
'grpc.default_authority': 'foo.test.google.fr',
|
|
'grpc.max_send_message_length': 4*1024*1024,
|
|
'grpc.max_metadata_size': 4*1024*1024
|
|
};
|
|
client = new testProto.TestService(`localhost:${port}`, creds, options);
|
|
done();
|
|
}
|
|
}, {
|
|
'grpc.max_receive_message_length': -1,
|
|
'grpc.max_metadata_size': 4*1024*1024
|
|
});
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('Should be able to start many concurrent calls', function(done) {
|
|
const callCount = 100;
|
|
done = multiDone(done, callCount);
|
|
for (let i = 0; i < callCount; i++) {
|
|
client.unaryCall({}, (error, result) => {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
}
|
|
});
|
|
it('Should echo metadata from call credentials', function(done) {
|
|
done = multiDone(done, 2);
|
|
const call = client.unaryCall({}, {credentials}, (error, result) => {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
call.on('metadata', (metadata) => {
|
|
assert.deepEqual(metadata.get('x-grpc-test-echo-initial'),
|
|
['test_initial_metadata_value']);
|
|
done();
|
|
});
|
|
});
|
|
it('Should be able to send the same metadata on two calls with call creds', function(done) {
|
|
done = multiDone(done, 5);
|
|
const metadata = new grpc.Metadata();
|
|
metadata.set('x-grpc-test-echo-trailing-bin', Buffer.from('ababab', 'hex'));
|
|
const call1 = client.unaryCall({}, metadata, {credentials}, (error, result) => {
|
|
assert.ifError(error);
|
|
const call2 = client.unaryCall({}, metadata, {credentials}, (error, result) => {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
call2.on('metadata', (metadata) => {
|
|
assert.deepEqual(metadata.get('x-grpc-test-echo-initial'),
|
|
['test_initial_metadata_value']);
|
|
done();
|
|
});
|
|
call2.on('status', function(status) {
|
|
var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin');
|
|
assert(echo_trailer.length === 1);
|
|
assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab');
|
|
done();
|
|
});
|
|
});
|
|
call1.on('metadata', (metadata) => {
|
|
assert.deepEqual(metadata.get('x-grpc-test-echo-initial'),
|
|
['test_initial_metadata_value']);
|
|
done();
|
|
});
|
|
call1.on('status', function(status) {
|
|
var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin');
|
|
assert(echo_trailer.length === 1);
|
|
assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab');
|
|
done();
|
|
});
|
|
});
|
|
it('should receive all messages in a long stream', function(done) {
|
|
// the test is slow under aarch64 emulator
|
|
this.timeout(80000);
|
|
var arg = {
|
|
response_type: 'COMPRESSABLE',
|
|
response_parameters: [
|
|
]
|
|
};
|
|
for (let i = 0; i < 100000; i++) {
|
|
arg.response_parameters.push({size: 0});
|
|
}
|
|
var call = client.streamingOutputCall(arg);
|
|
let responseCount = 0;
|
|
call.on('data', (value) => {
|
|
responseCount++;
|
|
});
|
|
call.on('status', (status) => {
|
|
assert.strictEqual(status.code, grpc.status.OK);
|
|
assert.strictEqual(responseCount, arg.response_parameters.length);
|
|
done();
|
|
});
|
|
call.on('error', (error) => {
|
|
assert.ifError(error);
|
|
});
|
|
});
|
|
/* The test against the JS server does not work because of
|
|
* https://github.com/nodejs/node/issues/35218. The test against the native
|
|
* server fails because of an unidentified timeout issue. */
|
|
it.skip('should be able to send very large headers and trailers', function(done) {
|
|
done = multiDone(done, 3);
|
|
const header = 'X'.repeat(64 * 1024);
|
|
const trailer = Buffer.from('Y'.repeat(64 * 1024));
|
|
const metadata = new grpc.Metadata();
|
|
metadata.set('x-grpc-test-echo-initial', header);
|
|
metadata.set('x-grpc-test-echo-trailing-bin', trailer);
|
|
const call = client.unaryCall({}, metadata, (error, result) => {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
call.on('metadata', (metadata) => {
|
|
assert.deepStrictEqual(metadata.get('x-grpc-test-echo-initial'),
|
|
[header]);
|
|
done();
|
|
});
|
|
call.on('status', (status) => {
|
|
var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin');
|
|
assert(echo_trailer.length === 1);
|
|
assert.strictEqual(echo_trailer[0].toString('ascii'), 'Y'.repeat(64 * 1024));
|
|
done();
|
|
});
|
|
});
|
|
describe('max message size', function() {
|
|
// with the default timeout the test times out under aarch64 emulator
|
|
this.timeout(6000);
|
|
// A size that is larger than the default limit
|
|
const largeMessageSize = 8 * 1024 * 1024;
|
|
const largeMessage = Buffer.alloc(largeMessageSize);
|
|
it('should get an error when sending a large message', function(done) {
|
|
done = multiDone(done, 2);
|
|
const unaryMessage = {payload: {body: largeMessage}};
|
|
client.unaryCall(unaryMessage, (error, result) => {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
const stream = client.fullDuplexCall();
|
|
stream.write({payload: {body: largeMessage}});
|
|
stream.end();
|
|
stream.on('data', () => {});
|
|
stream.on('status', (status) => {
|
|
assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
stream.on('error', (error) => {
|
|
});
|
|
});
|
|
it('should get an error when receiving a large message', function(done) {
|
|
done = multiDone(done, 2);
|
|
client.unaryCall({response_size: largeMessageSize}, (error, result) => {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
const stream = client.fullDuplexCall();
|
|
stream.write({response_parameters: [{size: largeMessageSize}]});
|
|
stream.end();
|
|
stream.on('data', () => {});
|
|
stream.on('status', (status) => {
|
|
assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
stream.on('error', (error) => {
|
|
});
|
|
});
|
|
describe('with a client with no message size limits', function() {
|
|
// with the default timeout the test times out under aarch64 emulator
|
|
this.timeout(6000);
|
|
let unrestrictedClient;
|
|
before(function() {
|
|
const ca_path = path.join(__dirname, '../data/ca.pem');
|
|
const ca_data = fs.readFileSync(ca_path);
|
|
const creds = grpc.credentials.createSsl(ca_data);
|
|
const options = {
|
|
'grpc.ssl_target_name_override': 'foo.test.google.fr',
|
|
'grpc.default_authority': 'foo.test.google.fr',
|
|
'grpc.max_send_message_length': -1,
|
|
'grpc.max_receive_message_length': -1
|
|
};
|
|
unrestrictedClient = new testProto.TestService(`localhost:${port}`, creds, options);
|
|
});
|
|
it('should not get an error when sending or receiving a large message', function(done) {
|
|
done = multiDone(done, 2);
|
|
const unaryRequestMessage = {
|
|
response_size: largeMessageSize,
|
|
payload: {
|
|
body: largeMessage
|
|
}
|
|
};
|
|
unrestrictedClient.unaryCall(unaryRequestMessage, (error, result) => {
|
|
assert.ifError(error);
|
|
assert.strictEqual(result.payload.body.length, largeMessageSize);
|
|
done();
|
|
});
|
|
const streamingRequestMessage = {
|
|
response_parameters: [{size: largeMessageSize}],
|
|
payload: {body: largeMessage}
|
|
};
|
|
const stream = unrestrictedClient.fullDuplexCall();
|
|
stream.write(streamingRequestMessage);
|
|
stream.end();
|
|
stream.on('data', (result) => {
|
|
assert.strictEqual(result.payload.body.length, largeMessageSize);
|
|
});
|
|
stream.on('status', () => {
|
|
done();
|
|
});
|
|
stream.on('error', (error) => {
|
|
assert.ifError(error);
|
|
});
|
|
});
|
|
});
|
|
describe('with a server with message size limits and a client without limits', function() {
|
|
// with the default timeout the test times out under aarch64 emulator
|
|
this.timeout(6000);
|
|
let restrictedServer;
|
|
let restrictedServerClient;
|
|
let restrictedServerClient2;
|
|
let restrictedServerClient3;
|
|
let restrictedServerClient4;
|
|
before(function(done) {
|
|
interopServer.getServer(0, true, (err, serverObj) => {
|
|
if (err) {
|
|
done(err);
|
|
} else {
|
|
restrictedServer = serverObj.server;
|
|
restrictedServer.start();
|
|
const ca_path = path.join(__dirname, '../data/ca.pem');
|
|
const ca_data = fs.readFileSync(ca_path);
|
|
const creds = grpc.credentials.createSsl(ca_data);
|
|
const options = {
|
|
'grpc.ssl_target_name_override': 'foo.test.google.fr',
|
|
'grpc.default_authority': 'foo.test.google.fr',
|
|
'grpc.max_receive_message_length': -1
|
|
};
|
|
restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options);
|
|
restrictedServerClient2 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 1});
|
|
restrictedServerClient3 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 2});
|
|
restrictedServerClient4 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 3});
|
|
done();
|
|
}
|
|
}, {'grpc.max_send_message_length': 4 * 1024 * 1024});
|
|
});
|
|
after(function() {
|
|
restrictedServer.forceShutdown();
|
|
});
|
|
it('should get an error when sending a large message', function(done) {
|
|
restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
const stream = restrictedServerClient2.fullDuplexCall();
|
|
stream.write({payload: {body: largeMessage}});
|
|
stream.end();
|
|
stream.on('data', () => {});
|
|
stream.on('status', (status) => {
|
|
assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
stream.on('error', (error) => {
|
|
});
|
|
});
|
|
});
|
|
it('should get an error when requesting a large message', function(done) {
|
|
restrictedServerClient3.unaryCall({response_size: largeMessageSize}, (error, result) => {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
const stream = restrictedServerClient4.fullDuplexCall();
|
|
stream.write({response_parameters: [{size: largeMessageSize}]});
|
|
stream.end();
|
|
stream.on('data', () => {});
|
|
stream.on('status', (status) => {
|
|
assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED);
|
|
done();
|
|
});
|
|
stream.on('error', (error) => {
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}); |