diff options
author | Craig Tiller <craig.tiller@gmail.com> | 2015-07-20 22:47:21 -0700 |
---|---|---|
committer | Craig Tiller <craig.tiller@gmail.com> | 2015-07-20 22:47:21 -0700 |
commit | 4e9ce32870b3528032c8ce8beaa6efbdb0ee080f (patch) | |
tree | 2da7fb858628c2280ee64791e1afa6f9209cfc13 /src | |
parent | 9d25e946828592d1e2a8fc51daa685995c771dd2 (diff) | |
parent | 40d808ffdc00831fdb31f7ed11610a21854a18ee (diff) |
Merge github.com:grpc/grpc into sometimes-its-good-just-to-check-in-with-each-other
Conflicts:
include/grpc/grpc.h
Diffstat (limited to 'src')
21 files changed, 589 insertions, 321 deletions
diff --git a/src/cpp/client/channel_arguments.cc b/src/cpp/client/channel_arguments.cc index 92ac5ea6fd..4263e377a8 100644 --- a/src/cpp/client/channel_arguments.cc +++ b/src/cpp/client/channel_arguments.cc @@ -37,7 +37,7 @@ namespace grpc { -void ChannelArguments::_Experimental_SetCompressionAlgorithm( +void ChannelArguments::SetCompressionAlgorithm( grpc_compression_algorithm algorithm) { SetInt(GRPC_COMPRESSION_ALGORITHM_ARG, algorithm); } diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc index 69216d2030..14ab772e50 100644 --- a/src/cpp/client/client_context.cc +++ b/src/cpp/client/client_context.cc @@ -79,7 +79,7 @@ void ClientContext::set_call(grpc_call* call, } } -void ClientContext::_experimental_set_compression_algorithm( +void ClientContext::set_compression_algorithm( grpc_compression_algorithm algorithm) { char* algorithm_name = NULL; if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) { diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs index 8d5e543a21..7edf19ed67 100644 --- a/src/csharp/Grpc.Auth/GoogleCredential.cs +++ b/src/csharp/Grpc.Auth/GoogleCredential.cs @@ -35,8 +35,11 @@ using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; +using Google.Apis.Auth.OAuth2.Responses; using Newtonsoft.Json.Linq; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; @@ -100,6 +103,19 @@ namespace Grpc.Auth return new GoogleCredential(serviceCredential); } + public Task<bool> RequestAccessTokenAsync(CancellationToken taskCancellationToken) + { + return credential.RequestAccessTokenAsync(taskCancellationToken); + } + + public TokenResponse Token + { + get + { + return credential.Token; + } + } + internal ServiceCredential InternalCredential { get diff --git a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs index 320423b245..e03e20c4f7 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs @@ -51,7 +51,8 @@ namespace Grpc.Core.Internal.Tests [Test] public void CreateAndDestroy() { - var metadata = new Metadata { + var metadata = new Metadata + { new Metadata.Entry("host", "somehost"), new Metadata.Entry("header2", "header value"), }; diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index af4a75a034..d3c69ab9eb 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -32,21 +32,34 @@ <PlatformTarget>x86</PlatformTarget> </PropertyGroup> <ItemGroup> - <Reference Include="Google.Apis.Auth.PlatformServices"> + <Reference Include="Google.Apis.Auth, Version=1.9.1.12395, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath> + </Reference> + <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.1.12399, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Core"> + <Reference Include="Google.Apis.Core, Version=1.9.1.12394, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks"> + <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions"> + <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> + <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> </Reference> + <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> <Reference Include="nunit.framework"> <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> </Reference> @@ -63,16 +76,15 @@ </Reference> <Reference Include="System.Net" /> <Reference Include="System.Net.Http" /> - <Reference Include="System.Net.Http.Extensions"> + <Reference Include="System.Net.Http.Extensions, Version=2.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath> </Reference> - <Reference Include="System.Net.Http.Primitives"> + <Reference Include="System.Net.Http.Primitives, Version=4.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath> </Reference> <Reference Include="System.Net.Http.WebRequest" /> - <Reference Include="Newtonsoft.Json"> - <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath> - </Reference> </ItemGroup> <ItemGroup> <Compile Include="..\Grpc.Core\Version.cs"> diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 05e732dbd4..ea83aaf2c1 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -135,7 +135,7 @@ namespace Grpc.IntegrationTesting GrpcEnvironment.Shutdown(); } - private void RunTestCase(string testCase, TestService.ITestServiceClient client) + private void RunTestCase(string testCase, TestService.TestServiceClient client) { switch (testCase) { @@ -163,6 +163,12 @@ namespace Grpc.IntegrationTesting case "compute_engine_creds": RunComputeEngineCreds(client); break; + case "oauth2_auth_token": + RunOAuth2AuthToken(client); + break; + case "per_rpc_creds": + RunPerRpcCreds(client); + break; case "cancel_after_begin": RunCancelAfterBegin(client); break; @@ -355,6 +361,51 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } + public static void RunOAuth2AuthToken(TestService.TestServiceClient client) + { + Console.WriteLine("running oauth2_auth_token"); + var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope }); + Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); + string oauth2Token = credential.Token.AccessToken; + + // Intercept calls with an OAuth2 token obtained out-of-band. + client.HeaderInterceptor = new MetadataInterceptorDelegate((metadata) => + { + metadata.Add(new Metadata.Entry("Authorization", "Bearer " + oauth2Token)); + }); + + var request = SimpleRequest.CreateBuilder() + .SetFillUsername(true) + .SetFillOauthScope(true) + .Build(); + + var response = client.UnaryCall(request); + + Assert.AreEqual(AuthScopeResponse, response.OauthScope); + Assert.AreEqual(ServiceAccountUser, response.Username); + Console.WriteLine("Passed!"); + } + + public static void RunPerRpcCreds(TestService.TestServiceClient client) + { + Console.WriteLine("running per_rpc_creds"); + + var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope }); + Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); + string oauth2Token = credential.Token.AccessToken; + + var request = SimpleRequest.CreateBuilder() + .SetFillUsername(true) + .SetFillOauthScope(true) + .Build(); + + var response = client.UnaryCall(request, headers: new Metadata { new Metadata.Entry("Authorization", "Bearer " + oauth2Token) } ); + + Assert.AreEqual(AuthScopeResponse, response.OauthScope); + Assert.AreEqual(ServiceAccountUser, response.Username); + Console.WriteLine("Passed!"); + } + public static void RunCancelAfterBegin(TestService.ITestServiceClient client) { Task.Run(async () => diff --git a/src/node/README.md b/src/node/README.md index 2f4c49096d..78781dab14 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -54,10 +54,10 @@ function loadObject(reflectionObject) Returns the same structure that `load` returns, but takes a reflection object from `ProtoBuf.js` instead of a file name. ```javascript -function buildServer(serviceArray) +function Server([serverOpions]) ``` -Takes an array of service objects and returns a constructor for a server that handles requests to all of those services. +Constructs a server to which service/implementation pairs can be added. ```javascript diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js index 0a86e7eaff..b1f8a6323f 100644 --- a/src/node/examples/math_server.js +++ b/src/node/examples/math_server.js @@ -36,8 +36,6 @@ var grpc = require('..'); var math = grpc.load(__dirname + '/math.proto').math; -var Server = grpc.buildServer([math.Math.service]); - /** * Server function for division. Provides the /Math/DivMany and /Math/Div * functions (Div is just DivMany with only one stream element). For each @@ -108,19 +106,17 @@ function mathDivMany(stream) { stream.end(); }); } - -var server = new Server({ - 'math.Math' : { - div: mathDiv, - fib: mathFib, - sum: mathSum, - divMany: mathDivMany - } +var server = new grpc.Server(); +server.addProtoService(math.Math.service, { + div: mathDiv, + fib: mathFib, + sum: mathSum, + divMany: mathDivMany }); if (require.main === module) { server.bind('0.0.0.0:50051'); - server.listen(); + server.start(); } /** diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js index c777eab7bc..70044a322c 100644 --- a/src/node/examples/route_guide_server.js +++ b/src/node/examples/route_guide_server.js @@ -40,8 +40,6 @@ var _ = require('lodash'); var grpc = require('..'); var examples = grpc.load(__dirname + '/route_guide.proto').examples; -var Server = grpc.buildServer([examples.RouteGuide.service]); - var COORD_FACTOR = 1e7; /** @@ -228,14 +226,14 @@ function routeChat(call) { * @return {Server} The new server object */ function getServer() { - return new Server({ - 'examples.RouteGuide' : { - getFeature: getFeature, - listFeatures: listFeatures, - recordRoute: recordRoute, - routeChat: routeChat - } + var server = new grpc.Server(); + server.addProtoService(examples.RouteGuide.service, { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat }); + return server; } if (require.main === module) { diff --git a/src/node/examples/stock_server.js b/src/node/examples/stock_server.js index caaf9f99ba..f2eb6ad4ab 100644 --- a/src/node/examples/stock_server.js +++ b/src/node/examples/stock_server.js @@ -37,8 +37,6 @@ var _ = require('lodash'); var grpc = require('..'); var examples = grpc.load(__dirname + '/stock.proto').examples; -var StockServer = grpc.buildServer([examples.Stock.service]); - function getLastTradePrice(call, callback) { callback(null, {symbol: call.request.symbol, price: 88}); } @@ -73,13 +71,12 @@ function getLastTradePriceMultiple(call) { }); } -var stockServer = new StockServer({ - 'examples.Stock' : { - getLastTradePrice: getLastTradePrice, - getLastTradePriceMultiple: getLastTradePriceMultiple, - watchFutureTrades: watchFutureTrades, - getHighestTradePrice: getHighestTradePrice - } +var stockServer = new grpc.Server(); +stockServer.addProtoService(examples.Stock.service, { + getLastTradePrice: getLastTradePrice, + getLastTradePriceMultiple: getLastTradePriceMultiple, + watchFutureTrades: watchFutureTrades, + getHighestTradePrice: getHighestTradePrice }); if (require.main === module) { diff --git a/src/node/index.js b/src/node/index.js index b6a4e2d0ee..d81e780443 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -133,9 +133,9 @@ exports.loadObject = loadObject; exports.load = load; /** - * See docs for server.makeServerConstructor + * See docs for Server */ -exports.buildServer = server.makeProtobufServerConstructor; +exports.Server = server.Server; /** * Status name to code number mapping @@ -159,5 +159,3 @@ exports.ServerCredentials = grpc.ServerCredentials; exports.getGoogleAuthDelegate = getGoogleAuthDelegate; exports.makeGenericClientConstructor = client.makeClientConstructor; - -exports.makeGenericServerConstructor = server.makeServerConstructor; diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js index 0baa78a094..505c6bb537 100644 --- a/src/node/interop/interop_server.js +++ b/src/node/interop/interop_server.js @@ -38,7 +38,6 @@ var path = require('path'); var _ = require('lodash'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; -var Server = grpc.buildServer([testProto.TestService.service]); /** * Create a buffer filled with size zeroes @@ -173,16 +172,15 @@ function getServer(port, tls) { key_data, pem_data); } - var server = new Server({ - 'grpc.testing.TestService' : { - emptyCall: handleEmpty, - unaryCall: handleUnary, - streamingOutputCall: handleStreamingOutput, - streamingInputCall: handleStreamingInput, - fullDuplexCall: handleFullDuplex, - halfDuplexCall: handleHalfDuplex - } - }, null, options); + var server = new grpc.Server(options); + server.addProtoService(testProto.TestService.service, { + emptyCall: handleEmpty, + unaryCall: handleUnary, + streamingOutputCall: handleStreamingOutput, + streamingInputCall: handleStreamingInput, + fullDuplexCall: handleFullDuplex, + halfDuplexCall: handleHalfDuplex + }); var port_num = server.bind('0.0.0.0:' + port, server_creds); return {server: server, port: port_num}; } diff --git a/src/node/src/server.js b/src/node/src/server.js index 00be400e61..0a3a0031bd 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -72,6 +72,9 @@ function handleError(call, error) { status.metadata = error.metadata; } var error_batch = {}; + if (!call.metadataSent) { + error_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + } error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; call.startBatch(error_batch, function(){}); } @@ -115,6 +118,10 @@ function sendUnaryResponse(call, value, serialize, metadata) { if (metadata) { status.metadata = metadata; } + if (!call.metadataSent) { + end_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + call.metadataSent = true; + } end_batch[grpc.opType.SEND_MESSAGE] = serialize(value); end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; call.startBatch(end_batch, function (){}); @@ -136,6 +143,10 @@ function setUpWritable(stream, serialize) { stream.serialize = common.wrapIgnoreNull(serialize); function sendStatus() { var batch = {}; + if (!stream.call.metadataSent) { + stream.call.metadataSent = true; + batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + } batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status; stream.call.startBatch(batch, function(){}); } @@ -239,6 +250,10 @@ function ServerWritableStream(call, serialize) { function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; + if (!this.call.metadataSent) { + batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + this.call.metadataSent = true; + } batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk); this.call.startBatch(batch, function(err, value) { if (err) { @@ -251,6 +266,23 @@ function _write(chunk, encoding, callback) { ServerWritableStream.prototype._write = _write; +function sendMetadata(responseMetadata) { + /* jshint validthis: true */ + if (!this.call.metadataSent) { + this.call.metadataSent = true; + var batch = []; + batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata; + this.call.startBatch(batch, function(err) { + if (err) { + this.emit('error', err); + return; + } + }); + } +} + +ServerWritableStream.prototype.sendMetadata = sendMetadata; + util.inherits(ServerReadableStream, Readable); /** @@ -339,6 +371,7 @@ function ServerDuplexStream(call, serialize, deserialize) { ServerDuplexStream.prototype._read = _read; ServerDuplexStream.prototype._write = _write; +ServerDuplexStream.prototype.sendMetadata = sendMetadata; /** * Fully handle a unary call @@ -348,12 +381,20 @@ ServerDuplexStream.prototype._write = _write; */ function handleUnary(call, handler, metadata) { var emitter = new EventEmitter(); + emitter.sendMetadata = function(responseMetadata) { + if (!call.metadataSent) { + call.metadataSent = true; + var batch = {}; + batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata; + call.startBatch(batch, function() {}); + } + }; emitter.on('error', function(error) { handleError(call, error); }); + emitter.metadata = metadata; waitForCancel(call, emitter); var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { if (err) { @@ -392,8 +433,8 @@ function handleUnary(call, handler, metadata) { function handleServerStreaming(call, handler, metadata) { var stream = new ServerWritableStream(call, handler.serialize); waitForCancel(call, stream); + stream.metadata = metadata; var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { if (err) { @@ -419,13 +460,19 @@ function handleServerStreaming(call, handler, metadata) { */ function handleClientStreaming(call, handler, metadata) { var stream = new ServerReadableStream(call, handler.deserialize); + stream.sendMetadata = function(responseMetadata) { + if (!call.metadataSent) { + call.metadataSent = true; + var batch = {}; + batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata; + call.startBatch(batch, function() {}); + } + }; stream.on('error', function(error) { handleError(call, error); }); waitForCancel(call, stream); - var metadata_batch = {}; - metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; - call.startBatch(metadata_batch, function() {}); + stream.metadata = metadata; handler.func(stream, function(err, value, trailer) { stream.terminate(); if (err) { @@ -449,9 +496,7 @@ function handleBidiStreaming(call, handler, metadata) { var stream = new ServerDuplexStream(call, handler.serialize, handler.deserialize); waitForCancel(call, stream); - var metadata_batch = {}; - metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; - call.startBatch(metadata_batch, function() {}); + stream.metadata = metadata; handler.func(stream); } @@ -466,29 +511,28 @@ var streamHandlers = { * Constructs a server object that stores request handlers and delegates * incoming requests to those handlers * @constructor - * @param {function(string, Object<string, Array<Buffer>>): - Object<string, Array<Buffer|string>>=} getMetadata Callback that gets - * metatada for a given method * @param {Object=} options Options that should be passed to the internal server * implementation */ -function Server(getMetadata, options) { +function Server(options) { this.handlers = {}; var handlers = this.handlers; var server = new grpc.Server(options); this._server = server; + this.started = false; /** * Start the server and begin handling requests * @this Server */ - this.listen = function() { + this.start = function() { + if (this.started) { + throw new Error('Server is already running'); + } + this.started = true; console.log('Server starting'); _.each(handlers, function(handler, handler_name) { console.log('Serving', handler_name); }); - if (this.started) { - throw 'Server is already running'; - } server.start(); /** * Handles the SERVER_RPC_NEW event. If there is a handler associated with @@ -523,11 +567,7 @@ function Server(getMetadata, options) { call.startBatch(batch, function() {}); return; } - var response_metadata = {}; - if (getMetadata) { - response_metadata = getMetadata(method, metadata); - } - streamHandlers[handler.type](call, handler, response_metadata); + streamHandlers[handler.type](call, handler, metadata); } server.requestCall(handleNewCall); }; @@ -565,6 +605,47 @@ Server.prototype.register = function(name, handler, serialize, deserialize, return true; }; +Server.prototype.addService = function(service, implementation) { + if (this.started) { + throw new Error('Can\'t add a service to a started server.'); + } + var self = this; + _.each(service, function(attrs, name) { + var method_type; + if (attrs.requestStream) { + if (attrs.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (attrs.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + if (implementation[name] === undefined) { + throw new Error('Method handler for ' + attrs.path + + ' not provided.'); + } + var serialize = attrs.responseSerialize; + var deserialize = attrs.requestDeserialize; + var register_success = self.register(attrs.path, + _.bind(implementation[name], + implementation), + serialize, deserialize, method_type); + if (!register_success) { + throw new Error('Method handler for ' + attrs.path + + ' already provided.'); + } + }); +}; + +Server.prototype.addProtoService = function(service, implementation) { + this.addService(common.getProtobufServiceAttrs(service), implementation); +}; + /** * Binds the server to the given port, with SSL enabled if creds is given * @param {string} port The port that the server should bind on, in the format @@ -573,6 +654,9 @@ Server.prototype.register = function(name, handler, serialize, deserialize, * nothing for an insecure port */ Server.prototype.bind = function(port, creds) { + if (this.started) { + throw new Error('Can\'t bind an already running server to an address'); + } if (creds) { return this._server.addSecureHttp2Port(port, creds); } else { @@ -581,131 +665,6 @@ Server.prototype.bind = function(port, creds) { }; /** - * Create a constructor for servers with services defined by service_attr_map. - * That is an object that maps (namespaced) service names to objects that in - * turn map method names to objects with the following keys: - * path: The path on the server for accessing the method. For example, for - * protocol buffers, we use "/service_name/method_name" - * requestStream: bool indicating whether the client sends a stream - * resonseStream: bool indicating whether the server sends a stream - * requestDeserialize: function to deserialize request objects - * responseSerialize: function to serialize response objects - * @param {Object} service_attr_map An object mapping service names to method - * attribute map objects - * @return {function(Object, function, Object=)} New server constructor - */ -function makeServerConstructor(service_attr_map) { - /** - * Create a server with the given handlers for all of the methods. - * @constructor - * @param {Object} service_handlers Map from service names to map from method - * names to handlers - * @param {function(string, Object<string, Array<Buffer>>): - Object<string, Array<Buffer|string>>=} getMetadata Callback that - * gets metatada for a given method - * @param {Object=} options Options to pass to the underlying server - */ - function SurfaceServer(service_handlers, getMetadata, options) { - var server = new Server(getMetadata, options); - this.inner_server = server; - _.each(service_attr_map, function(service_attrs, service_name) { - if (service_handlers[service_name] === undefined) { - throw new Error('Handlers for service ' + - service_name + ' not provided.'); - } - _.each(service_attrs, function(attrs, name) { - var method_type; - if (attrs.requestStream) { - if (attrs.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (attrs.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - if (service_handlers[service_name][name] === undefined) { - throw new Error('Method handler for ' + attrs.path + - ' not provided.'); - } - var serialize = attrs.responseSerialize; - var deserialize = attrs.requestDeserialize; - server.register(attrs.path, _.bind(service_handlers[service_name][name], - service_handlers[service_name]), - serialize, deserialize, method_type); - }); - }, this); - } - - /** - * Binds the server to the given port, with SSL enabled if creds is supplied - * @param {string} port The port that the server should bind on, in the format - * "address:port" - * @param {boolean=} creds Credentials to use for SSL - * @return {SurfaceServer} this - */ - SurfaceServer.prototype.bind = function(port, creds) { - return this.inner_server.bind(port, creds); - }; - - /** - * Starts the server listening on any bound ports - * @return {SurfaceServer} this - */ - SurfaceServer.prototype.listen = function() { - this.inner_server.listen(); - return this; - }; - - /** - * Shuts the server down; tells it to stop listening for new requests and to - * kill old requests. - */ - SurfaceServer.prototype.shutdown = function() { - this.inner_server.shutdown(); - }; - - return SurfaceServer; -} - -/** - * Create a constructor for servers that serve the given services. - * @param {Array<ProtoBuf.Reflect.Service>} services The services that the - * servers will serve - * @return {function(Object, function, Object=)} New server constructor - */ -function makeProtobufServerConstructor(services) { - var qual_names = []; - var service_attr_map = {}; - _.each(services, function(service) { - var service_name = common.fullyQualifiedName(service); - _.each(service.children, function(method) { - var name = common.fullyQualifiedName(method); - if (_.indexOf(qual_names, name) !== -1) { - throw new Error('Method ' + name + ' exposed by more than one service'); - } - qual_names.push(name); - }); - var method_attrs = common.getProtobufServiceAttrs(service); - if (!service_attr_map.hasOwnProperty(service_name)) { - service_attr_map[service_name] = {}; - } - service_attr_map[service_name] = _.extend(service_attr_map[service_name], - method_attrs); - }); - return makeServerConstructor(service_attr_map); -} - -/** - * See documentation for makeServerConstructor - */ -exports.makeServerConstructor = makeServerConstructor; - -/** - * See documentation for makeProtobufServerConstructor + * See documentation for Server */ -exports.makeProtobufServerConstructor = makeProtobufServerConstructor; +exports.Server = Server; diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js index 4d1a5082e0..bb700cc46c 100644 --- a/src/node/test/health_test.js +++ b/src/node/test/health_test.js @@ -49,14 +49,13 @@ describe('Health Checking', function() { 'grpc.test.TestService': 'SERVING' } }; - var HealthServer = grpc.buildServer([health.service]); - var healthServer = new HealthServer({ - 'grpc.health.v1alpha.Health': new health.Implementation(statusMap) - }); + var healthServer = new grpc.Server(); + healthServer.addProtoService(health.service, + new health.Implementation(statusMap)); var healthClient; before(function() { var port_num = healthServer.bind('0.0.0.0:0'); - healthServer.listen(); + healthServer.start(); healthClient = new health.Client('localhost:' + port_num); }); after(function() { diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index fcd8eb6403..0a5eb29c0c 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -46,7 +46,7 @@ describe('Interop tests', function() { before(function(done) { var server_obj = interop_server.getServer(0, true); server = server_obj.server; - server.listen(); + server.start(); port = 'localhost:' + server_obj.port; done(); }); diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js index 3461922e66..f2751857ff 100644 --- a/src/node/test/math_client_test.js +++ b/src/node/test/math_client_test.js @@ -52,7 +52,7 @@ var server = require('../examples/math_server.js'); describe('Math client', function() { before(function(done) { var port_num = server.bind('0.0.0.0:0'); - server.listen(); + server.start(); math_client = new math.Math('localhost:' + port_num); done(); }); diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 125957277f..18178e49e4 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -69,34 +69,45 @@ describe('File loader', function() { }); }); }); -describe('Surface server constructor', function() { - it('Should fail with conflicting method names', function() { - assert.throws(function() { - grpc.buildServer([mathService, mathService]); - }); +describe('Server.prototype.addProtoService', function() { + var server; + var dummyImpls = { + 'div': function() {}, + 'divMany': function() {}, + 'fib': function() {}, + 'sum': function() {} + }; + beforeEach(function() { + server = new grpc.Server(); + }); + afterEach(function() { + server.shutdown(); }); it('Should succeed with a single service', function() { assert.doesNotThrow(function() { - grpc.buildServer([mathService]); + server.addProtoService(mathService, dummyImpls); + }); + }); + it('Should fail with conflicting method names', function() { + server.addProtoService(mathService, dummyImpls); + assert.throws(function() { + server.addProtoService(mathService, dummyImpls); }); }); it('Should fail with missing handlers', function() { - var Server = grpc.buildServer([mathService]); assert.throws(function() { - new Server({ - 'math.Math': { - 'div': function() {}, - 'divMany': function() {}, - 'fib': function() {} - } + server.addProtoService(mathService, { + 'div': function() {}, + 'divMany': function() {}, + 'fib': function() {} }); }, /math.Math.Sum/); }); - it('Should fail with no handlers for the service', function() { - var Server = grpc.buildServer([mathService]); + it('Should fail if the server has been started', function() { + server.start(); assert.throws(function() { - new Server({}); - }, /math.Math/); + server.addProtoService(mathService, dummyImpls); + }); }); }); describe('Echo service', function() { @@ -105,18 +116,16 @@ describe('Echo service', function() { before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto'); var echo_service = test_proto.lookup('EchoService'); - var Server = grpc.buildServer([echo_service]); - server = new Server({ - 'EchoService': { - echo: function(call, callback) { - callback(null, call.request); - } + server = new grpc.Server(); + server.addProtoService(echo_service, { + echo: function(call, callback) { + callback(null, call.request); } }); var port = server.bind('localhost:0'); var Client = surface_client.makeProtobufClientConstructor(echo_service); client = new Client('localhost:' + port); - server.listen(); + server.start(); }); after(function() { server.shutdown(); @@ -151,18 +160,14 @@ describe('Generic client and server', function() { var client; var server; before(function() { - var Server = grpc.makeGenericServerConstructor({ - string: string_service_attrs - }); - server = new Server({ - string: { - capitalize: function(call, callback) { - callback(null, _.capitalize(call.request)); - } + server = new grpc.Server(); + server.addService(string_service_attrs, { + capitalize: function(call, callback) { + callback(null, _.capitalize(call.request)); } }); var port = server.bind('localhost:0'); - server.listen(); + server.start(); var Client = grpc.makeGenericClientConstructor(string_service_attrs); client = new Client('localhost:' + port); }); @@ -178,6 +183,82 @@ describe('Generic client and server', function() { }); }); }); +describe('Echo metadata', function() { + var client; + var server; + before(function() { + var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto'); + var test_service = test_proto.lookup('TestService'); + server = new grpc.Server(); + server.addProtoService(test_service, { + unary: function(call, cb) { + call.sendMetadata(call.metadata); + cb(null, {}); + }, + clientStream: function(stream, cb){ + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.sendMetadata(stream.metadata); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + stream.end(); + }); + } + }); + var port = server.bind('localhost:0'); + var Client = surface_client.makeProtobufClientConstructor(test_service); + client = new Client('localhost:' + port); + server.start(); + }); + after(function() { + server.shutdown(); + }); + it('with unary call', function(done) { + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }, {key: ['value']}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.key, ['value']); + done(); + }); + }); + it('with client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + }, {key: ['value']}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.key, ['value']); + done(); + }); + call.end(); + }); + it('with server stream call', function(done) { + var call = client.serverStream({}, {key: ['value']}); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.key, ['value']); + done(); + }); + }); + it('with bidi stream call', function(done) { + var call = client.bidiStream({key: ['value']}); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.key, ['value']); + done(); + }); + call.end(); + }); +}); describe('Other conditions', function() { var client; var server; @@ -185,72 +266,70 @@ describe('Other conditions', function() { before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto'); var test_service = test_proto.lookup('TestService'); - var Server = grpc.buildServer([test_service]); - server = new Server({ - TestService: { - unary: function(call, cb) { - var req = call.request; - if (req.error) { - cb(new Error('Requested error'), null, {metadata: ['yes']}); + server = new grpc.Server(); + server.addProtoService(test_service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + cb(new Error('Requested error'), null, {trailer_present: ['yes']}); + } else { + cb(null, {count: 1}, {trailer_present: ['yes']}); + } + }, + clientStream: function(stream, cb){ + var count = 0; + var errored; + stream.on('data', function(data) { + if (data.error) { + errored = true; + cb(new Error('Requested error'), null, {trailer_present: ['yes']}); } else { - cb(null, {count: 1}, {metadata: ['yes']}); + count += 1; } - }, - clientStream: function(stream, cb){ - var count = 0; - var errored; - stream.on('data', function(data) { - if (data.error) { - errored = true; - cb(new Error('Requested error'), null, {metadata: ['yes']}); - } else { - count += 1; - } - }); - stream.on('end', function() { - if (!errored) { - cb(null, {count: count}, {metadata: ['yes']}); - } - }); - }, - serverStream: function(stream) { - var req = stream.request; - if (req.error) { + }); + stream.on('end', function() { + if (!errored) { + cb(null, {count: count}, {trailer_present: ['yes']}); + } + }); + }, + serverStream: function(stream) { + var req = stream.request; + if (req.error) { + var err = new Error('Requested error'); + err.metadata = {trailer_present: ['yes']}; + stream.emit('error', err); + } else { + for (var i = 0; i < 5; i++) { + stream.write({count: i}); + } + stream.end({trailer_present: ['yes']}); + } + }, + bidiStream: function(stream) { + var count = 0; + stream.on('data', function(data) { + if (data.error) { var err = new Error('Requested error'); - err.metadata = {metadata: ['yes']}; + err.metadata = { + trailer_present: ['yes'], + count: ['' + count] + }; stream.emit('error', err); } else { - for (var i = 0; i < 5; i++) { - stream.write({count: i}); - } - stream.end({metadata: ['yes']}); + stream.write({count: count}); + count += 1; } - }, - bidiStream: function(stream) { - var count = 0; - stream.on('data', function(data) { - if (data.error) { - var err = new Error('Requested error'); - err.metadata = { - metadata: ['yes'], - count: ['' + count] - }; - stream.emit('error', err); - } else { - stream.write({count: count}); - count += 1; - } - }); - stream.on('end', function() { - stream.end({metadata: ['yes']}); - }); - } + }); + stream.on('end', function() { + stream.end({trailer_present: ['yes']}); + }); } }); port = server.bind('localhost:0'); var Client = surface_client.makeProtobufClientConstructor(test_service); client = new Client('localhost:' + port); - server.listen(); + server.start(); }); after(function() { server.shutdown(); @@ -340,7 +419,7 @@ describe('Other conditions', function() { assert.ifError(err); }); call.on('status', function(status) { - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -349,7 +428,7 @@ describe('Other conditions', function() { assert(err); }); call.on('status', function(status) { - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -361,7 +440,7 @@ describe('Other conditions', function() { call.write({error: false}); call.end(); call.on('status', function(status) { - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -373,7 +452,7 @@ describe('Other conditions', function() { call.write({error: true}); call.end(); call.on('status', function(status) { - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -382,7 +461,7 @@ describe('Other conditions', function() { call.on('data', function(){}); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -390,7 +469,7 @@ describe('Other conditions', function() { var call = client.serverStream({error: true}); call.on('data', function(){}); call.on('error', function(error) { - assert.deepEqual(error.metadata.metadata, ['yes']); + assert.deepEqual(error.metadata.trailer_present, ['yes']); done(); }); }); @@ -402,7 +481,7 @@ describe('Other conditions', function() { call.on('data', function(){}); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.metadata, ['yes']); + assert.deepEqual(status.metadata.trailer_present, ['yes']); done(); }); }); @@ -413,7 +492,7 @@ describe('Other conditions', function() { call.end(); call.on('data', function(){}); call.on('error', function(error) { - assert.deepEqual(error.metadata.metadata, ['yes']); + assert.deepEqual(error.metadata.trailer_present, ['yes']); done(); }); }); @@ -465,18 +544,17 @@ describe('Cancelling surface client', function() { var client; var server; before(function() { - var Server = grpc.buildServer([mathService]); - server = new Server({ - 'math.Math': { - 'div': function(stream) {}, - 'divMany': function(stream) {}, - 'fib': function(stream) {}, - 'sum': function(stream) {} - } + server = new grpc.Server(); + server.addProtoService(mathService, { + 'div': function(stream) {}, + 'divMany': function(stream) {}, + 'fib': function(stream) {}, + 'sum': function(stream) {} }); var port = server.bind('localhost:0'); var Client = surface_client.makeProtobufClientConstructor(mathService); client = new Client('localhost:' + port); + server.start(); }); after(function() { server.shutdown(); diff --git a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec b/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec index dd0dab352d..7cc9a040fe 100644 --- a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec +++ b/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec @@ -7,7 +7,13 @@ Pod::Spec.new do |s| s.osx.deployment_target = "10.8" # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. - s.prepare_command = "protoc --objc_out=. --objcgrpc_out=. *.proto" + s.prepare_command = <<-CMD + cd ../../../.. + # TODO(jcanizales): Make only Objective-C plugin. + make plugins + cd - + protoc --plugin=protoc-gen-grpc=../../../../bins/opt/grpc_objective_c_plugin --objc_out=. --grpc_out=. *.proto + CMD s.subspec "Messages" do |ms| ms.source_files = "*.pbobjc.{h,m}" diff --git a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec index e26e62f5bb..0e8dacd1c4 100644 --- a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec +++ b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec @@ -7,7 +7,13 @@ Pod::Spec.new do |s| s.osx.deployment_target = "10.8" # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. - s.prepare_command = "protoc --objc_out=. --objcgrpc_out=. *.proto" + s.prepare_command = <<-CMD + cd ../../../.. + # TODO(jcanizales): Make only Objective-C plugin. + make plugins + cd - + protoc --plugin=protoc-gen-grpc=../../../../bins/opt/grpc_objective_c_plugin --objc_out=. --grpc_out=. *.proto + CMD s.subspec "Messages" do |ms| ms.source_files = "*.pbobjc.{h,m}" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme new file mode 100644 index 0000000000..3a6e2c3591 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0630" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "NO" + buildForArchiving = "NO" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "63423F431B150A5F006CF63C" + BuildableName = "AllTests.xctest" + BlueprintName = "AllTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Debug"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "63423F431B150A5F006CF63C" + BuildableName = "AllTests.xctest" + BlueprintName = "AllTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + <SkippedTests> + <Test + Identifier = "LocalClearTextTests"> + </Test> + <Test + Identifier = "LocalClearTextTests/testConnectionToLocalServer"> + </Test> + </SkippedTests> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "63423F431B150A5F006CF63C" + BuildableName = "AllTests.xctest" + BlueprintName = "AllTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Debug" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "63423F431B150A5F006CF63C" + BuildableName = "AllTests.xctest" + BlueprintName = "AllTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "63423F431B150A5F006CF63C" + BuildableName = "AllTests.xctest" + BlueprintName = "AllTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh new file mode 100755 index 0000000000..37fced3a62 --- /dev/null +++ b/src/objective-c/tests/run_tests.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -e + +cd $(dirname $0) + +# TODO(jcanizales): Remove when Cocoapods issue #3823 is resolved. +export COCOAPODS_DISABLE_DETERMINISTIC_UUIDS=YES +pod install + +# xcodebuild is very verbose. We filter its output and tell Bash to fail if any +# element of the pipe fails. +# TODO(jcanizales): Use xctool instead? Issue #2540. +set -o pipefail +XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)' +xcodebuild \ + -workspace Tests.xcworkspace \ + -scheme AllTests \ + -destination name="iPhone 6" \ + test \ + | egrep "$XCODEBUILD_FILTER" - |