mirror of https://github.com/grpc/grpc-node.git
Merge pull request #209 from murgatroid99/multi_impl_interop_tests
Make interop tests use new proto loader, run them with pure js client
This commit is contained in:
commit
0e1054016e
|
|
@ -99,7 +99,7 @@ gulp.task('clean.all', 'Delete all files created by tasks',
|
|||
'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']);
|
||||
|
||||
gulp.task('native.test.only', 'Run tests of native code without rebuilding anything',
|
||||
['native.core.test', 'internal.test.test', 'health-check.test']);
|
||||
['native.core.test', 'health-check.test']);
|
||||
|
||||
gulp.task('native.test', 'Run tests of native code', (callback) => {
|
||||
runSequence('build', 'native.test.only', callback);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export interface ChannelOptions {
|
|||
'grpc.ssl_target_name_override': string;
|
||||
'grpc.primary_user_agent': string;
|
||||
'grpc.secondary_user_agent': string;
|
||||
'grpc.default_authority': string;
|
||||
[key: string]: string | number;
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +159,7 @@ export class Http2Channel extends EventEmitter implements Channel {
|
|||
connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate): Error | undefined => {
|
||||
return checkServerIdentity(sslTargetNameOverride, cert);
|
||||
}
|
||||
connectionOptions.servername = sslTargetNameOverride;
|
||||
}
|
||||
subChannel = http2.connect(this.authority, connectionOptions);
|
||||
}
|
||||
|
|
@ -224,7 +226,14 @@ export class Http2Channel extends EventEmitter implements Channel {
|
|||
Promise.all([finalMetadata, this.connect()])
|
||||
.then(([metadataValue]) => {
|
||||
let headers = metadataValue.toHttp2Headers();
|
||||
headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname;
|
||||
let host: string;
|
||||
// TODO(murgatroid99): Add more centralized handling of channel options
|
||||
if (this.options['grpc.default_authority']) {
|
||||
host = this.options['grpc.default_authority'] as string;
|
||||
} else {
|
||||
host = this.authority.hostname;
|
||||
}
|
||||
headers[HTTP2_HEADER_AUTHORITY] = host;
|
||||
headers[HTTP2_HEADER_USER_AGENT] = this.userAgent;
|
||||
headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc';
|
||||
headers[HTTP2_HEADER_METHOD] = 'POST';
|
||||
|
|
@ -234,6 +243,7 @@ export class Http2Channel extends EventEmitter implements Channel {
|
|||
if (this.connectivityState === ConnectivityState.READY) {
|
||||
const session: http2.ClientHttp2Session = this.subChannel!;
|
||||
// Prevent the HTTP/2 session from keeping the process alive.
|
||||
// Note: this function is only available in Node 9
|
||||
session.unref();
|
||||
stream.attachHttp2Stream(session.request(headers));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export function loadPackageDefinition(packageDef: PackageDefinition) {
|
|||
const nameComponents = serviceFqn.split('.');
|
||||
const serviceName = nameComponents[nameComponents.length-1];
|
||||
let current = result;
|
||||
for (const packageName in nameComponents.slice(0, -1)) {
|
||||
for (const packageName of nameComponents.slice(0, -1)) {
|
||||
if (!current[packageName]) {
|
||||
current[packageName] = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) {
|
|||
const nameComponents = serviceFqn.split('.');
|
||||
const serviceName = nameComponents[nameComponents.length-1];
|
||||
let current = result;
|
||||
for (const packageName in nameComponents.slice(0, -1)) {
|
||||
for (const packageName of nameComponents.slice(0, -1)) {
|
||||
if (!current[packageName]) {
|
||||
current[packageName] = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,11 @@
|
|||
"build/src/*.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.104",
|
||||
"@types/node": "^9.4.6",
|
||||
"clang-format": "^1.2.2",
|
||||
"gts": "^0.5.3",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash": "^4.17.5",
|
||||
"protobufjs": "^6.8.5",
|
||||
"typescript": "~2.7.2"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
import * as Protobuf from 'protobufjs';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export interface Serialize<T> {
|
||||
(value: T): Buffer;
|
||||
|
|
@ -35,6 +36,7 @@ export interface MethodDefinition<RequestType, ResponseType> {
|
|||
responseSerialize: Serialize<ResponseType>;
|
||||
requestDeserialize: Deserialize<RequestType>;
|
||||
responseDeserialize: Deserialize<ResponseType>;
|
||||
originalName?: string;
|
||||
}
|
||||
|
||||
export interface ServiceDefinition {
|
||||
|
|
@ -88,12 +90,14 @@ function createSerializer(cls: Protobuf.Type): Serialize<object> {
|
|||
function createMethodDefinition(method: Protobuf.Method, serviceName: string, options: Options): MethodDefinition<object, object> {
|
||||
return {
|
||||
path: '/' + serviceName + '/' + method.name,
|
||||
requestStream: !!method.requestStream,
|
||||
responseStream: !!method.responseStream,
|
||||
requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type),
|
||||
requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options),
|
||||
responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type),
|
||||
responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options)
|
||||
requestStream: !!method.requestStream,
|
||||
responseStream: !!method.responseStream,
|
||||
requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type),
|
||||
requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options),
|
||||
responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type),
|
||||
responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options),
|
||||
// TODO(murgatroid99): Find a better way to handle this
|
||||
originalName: _.camelCase(method.name)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +117,21 @@ function createPackageDefinition(root: Protobuf.Root, options: Options): Package
|
|||
return def;
|
||||
}
|
||||
|
||||
function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) {
|
||||
root.resolvePath = (origin: string, target: string) => {
|
||||
for (const directory of includePaths) {
|
||||
const fullPath: string = path.join(directory, target);
|
||||
try {
|
||||
fs.accessSync(fullPath, fs.constants.R_OK);
|
||||
return fullPath;
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a .proto file with the specified options.
|
||||
* @param filename The file path to load. Can be an absolute path or relative to
|
||||
|
|
@ -143,21 +162,23 @@ export function load(filename: string, options: Options): Promise<PackageDefinit
|
|||
if (!(options.include instanceof Array)) {
|
||||
return Promise.reject(new Error('The include option must be an array'));
|
||||
}
|
||||
root.resolvePath = (origin: string, target: string) => {
|
||||
for (const directory of options.include as string[]) {
|
||||
const fullPath: string = path.join(directory, target);
|
||||
try {
|
||||
fs.accessSync(fullPath, fs.constants.R_OK);
|
||||
return fullPath;
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
addIncludePathResolver(root, options.include as string[]);
|
||||
}
|
||||
return root.load(filename, options).then((loadedRoot) => {
|
||||
loadedRoot.resolveAll();
|
||||
return createPackageDefinition(root, options);
|
||||
});
|
||||
}
|
||||
|
||||
export function loadSync(filename: string, options: Options): PackageDefinition {
|
||||
const root: Protobuf.Root = new Protobuf.Root();
|
||||
if (!!options.include) {
|
||||
if (!(options.include instanceof Array)) {
|
||||
throw new Error('The include option must be an array');
|
||||
}
|
||||
addIncludePathResolver(root, options.include as string[]);
|
||||
}
|
||||
const loadedRoot = root.loadSync(filename, options);
|
||||
loadedRoot.resolveAll();
|
||||
return createPackageDefinition(root, options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,29 +11,15 @@ function getImplementation(globalField) {
|
|||
'If running from the command line, please --require a fixture first.'
|
||||
].join(' '));
|
||||
}
|
||||
console.error(globalField, global[globalField]);
|
||||
const impl = global[globalField];
|
||||
return {
|
||||
surface: require(`../packages/grpc-${impl}`),
|
||||
pjson: require(`../packages/grpc-${impl}/package.json`),
|
||||
core: require(`../packages/grpc-${impl}-core`),
|
||||
corePjson: require(`../packages/grpc-${impl}-core/package.json`)
|
||||
};
|
||||
return require(`../packages/grpc-${impl}-core`);
|
||||
}
|
||||
|
||||
const clientImpl = getImplementation('_client_implementation');
|
||||
const serverImpl = getImplementation('_server_implementation');
|
||||
|
||||
// We export a "merged" gRPC API by merging client and server specified
|
||||
// APIs together. Any function that is unspecific to client/server defaults
|
||||
// to client-side implementation.
|
||||
// This object also has a test-only field from which details about the
|
||||
// modules may be read.
|
||||
module.exports = Object.assign({
|
||||
'$implementationInfo': {
|
||||
client: clientImpl,
|
||||
server: serverImpl
|
||||
}
|
||||
}, clientImpl.surface, _.pick(serverImpl.surface, [
|
||||
'Server',
|
||||
'ServerCredentials'
|
||||
]));
|
||||
module.exports = {
|
||||
client: clientImpl,
|
||||
server: serverImpl
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
require('../../../test/fixtures/native_native.js');
|
||||
var interop_server = require('../../../test/interop/interop_server.js');
|
||||
var interop_client = require('../../../test/interop/interop_client.js');
|
||||
var interop_server = require('../interop/interop_server.js');
|
||||
var interop_client = require('../interop/interop_client.js');
|
||||
|
||||
var server;
|
||||
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
global._server_implementation = 'js';
|
||||
global._client_implementation = 'native';
|
||||
global._server_implementation = 'native';
|
||||
global._client_implementation = 'js';
|
||||
|
|
|
|||
|
|
@ -35,4 +35,29 @@ gulp.task('install', 'Install test dependencies', () => {
|
|||
|
||||
gulp.task('clean.all', 'Delete all files created by tasks', () => {});
|
||||
|
||||
gulp.task('test', 'Run API-level tests', () => {});
|
||||
gulp.task('test', 'Run API-level tests', () => {
|
||||
// run mocha tests matching a glob with a pre-required fixture,
|
||||
// returning the associated gulp stream
|
||||
const apiTestGlob = `${apiTestDir}/*.js`;
|
||||
const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => {
|
||||
const fixture = `${server}_${client}`;
|
||||
console.log(`Running ${apiTestGlob} with ${server} server + ${client} client`);
|
||||
gulp.src(apiTestGlob)
|
||||
.pipe(mocha({
|
||||
reporter: 'mocha-jenkins-reporter',
|
||||
require: `${testDir}/fixtures/${fixture}.js`
|
||||
}))
|
||||
.resume() // put the stream in flowing mode
|
||||
.on('end', resolve)
|
||||
.on('error', reject);
|
||||
});
|
||||
const runTestsArgPairs = [
|
||||
['native', 'native'],
|
||||
['native', 'js'],
|
||||
// ['js', 'native'],
|
||||
// ['js', 'js']
|
||||
];
|
||||
return runTestsArgPairs.reduce((previousPromise, argPair) => {
|
||||
return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1]));
|
||||
}, Promise.resolve());
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,12 +20,18 @@
|
|||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var grpc = require('../any_grpc')['$implementationInfo'].client.surface;
|
||||
var testProto = grpc.load({
|
||||
root: __dirname + '/../../packages/grpc-native-core/deps/grpc',
|
||||
file: 'src/proto/grpc/testing/test.proto'}).grpc.testing;
|
||||
var grpc = require('../any_grpc').client;
|
||||
var protoLoader = require('../../packages/grpc-protobufjs');
|
||||
var GoogleAuth = require('google-auth-library');
|
||||
|
||||
var protoPackage = protoLoader.loadSync(
|
||||
'src/proto/grpc/testing/test.proto',
|
||||
{keepCase: true,
|
||||
defaults: true,
|
||||
enums: String,
|
||||
include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']});
|
||||
var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing;
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var SERVICE_ACCOUNT_EMAIL;
|
||||
|
|
|
|||
|
|
@ -22,10 +22,16 @@ var fs = require('fs');
|
|||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var AsyncDelayQueue = require('./async_delay_queue');
|
||||
var grpc = require('../any_grpc')['$implementationInfo'].server.surface;
|
||||
var testProto = grpc.load({
|
||||
root: __dirname + '/../../packages/grpc-native-core/deps/grpc',
|
||||
file: 'src/proto/grpc/testing/test.proto'}).grpc.testing;
|
||||
var grpc = require('../any_grpc').server;
|
||||
// TODO(murgatroid99): do this import more cleanly
|
||||
var protoLoader = require('../../packages/grpc-protobufjs');
|
||||
var protoPackage = protoLoader.loadSync(
|
||||
'src/proto/grpc/testing/test.proto',
|
||||
{keepCase: true,
|
||||
defaults: true,
|
||||
enums: String,
|
||||
include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']});
|
||||
var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing;
|
||||
|
||||
var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
|
||||
var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
|
||||
|
|
|
|||
Loading…
Reference in New Issue