Merge github.com:google/grpc into async-api

pull/357/head
Craig Tiller 10 years ago
commit b05561fa1a
  1. 62
      src/node/examples/stock.proto
  2. 43
      src/node/examples/stock_client.js
  3. 83
      src/node/examples/stock_server.js
  4. 22
      src/node/ext/byte_buffer.cc
  5. 4
      src/node/ext/byte_buffer.h
  6. 3
      src/node/ext/event.cc
  7. 17
      src/node/src/server.js
  8. 8
      src/node/test/client_server_test.js
  9. 6
      src/php/lib/Grpc/ActiveCall.php
  10. 34
      src/php/lib/Grpc/BaseStub.php
  11. 9
      src/php/tests/interop/empty.php
  12. 13
      src/php/tests/interop/interop_client.php
  13. 213
      src/php/tests/interop/messages.php
  14. 34
      src/php/tests/interop/test.php
  15. 67
      tools/run_tests/jobset.py
  16. 95
      tools/run_tests/run_tests.py

@ -0,0 +1,62 @@
// 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.
syntax = "proto3";
package examples;
// Protocol type definitions
message StockRequest {
optional string symbol = 1;
optional int32 num_trades_to_watch = 2 [default=0];
};
message StockReply {
optional float price = 1;
optional string symbol = 2;
};
// Interface exported by the server
service Stock {
// Simple blocking RPC
rpc GetLastTradePrice(StockRequest) returns (StockReply) {
};
// Bidirectional streaming RPC
rpc GetLastTradePriceMultiple(stream StockRequest) returns
(stream StockReply) {
};
// Unidirectional server-to-client streaming RPC
rpc WatchFutureTrades(StockRequest) returns (stream StockReply) {
};
// Unidirectional client-to-server streaming RPC
rpc GetHighestTradePrice(stream StockRequest) returns (StockReply) {
};
};

@ -0,0 +1,43 @@
/*
*
* 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.
*
*/
var grpc = require('..');
var examples = grpc.load(__dirname + '/stock.proto').examples;
/**
* This exports a client constructor for the Stock service. The usage looks like
*
* var StockClient = require('stock_client.js');
* var stockClient = new StockClient(server_address);
*/
module.exports = examples.Stock;

@ -0,0 +1,83 @@
/*
*
* 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.
*
*/
var _ = require('underscore');
var grpc = require('..');
var examples = grpc.load(__dirname + '/stock.proto').examples;
var StockServer = grpc.makeServerConstructor([examples.Stock.service]);
function getLastTradePrice(call, callback) {
callback(null, {price: 88});
}
function watchFutureTrades(call) {
for (var i = 0; i < call.request.num_trades_to_watch; i++) {
call.write({price: 88.00 + i * 10.00});
}
call.end();
}
function getHighestTradePrice(call, callback) {
var trades = [];
call.on('data', function(data) {
trades.push({symbol: data.symbol, price: _.random(0, 100)});
});
call.on('end', function() {
if(_.isEmpty(trades)) {
callback(null, {});
} else {
callback(null, _.max(trades, function(trade){return trade.price;}));
}
});
}
function getLastTradePriceMultiple(call) {
call.on('data', function(data) {
call.write({price: 88});
});
call.on('end', function() {
call.end();
});
}
var stockServer = new StockServer({
'examples.Stock' : {
getLastTradePrice: getLastTradePrice,
getLastTradePriceMultiple: getLastTradePriceMultiple,
watchFutureTrades: watchFutureTrades,
getHighestTradePrice: getHighestTradePrice
}
});
exports.module = stockServer;

@ -39,13 +39,17 @@
#include "grpc/grpc.h"
#include "grpc/support/slice.h"
#include "byte_buffer.h"
namespace grpc {
namespace node {
#include "byte_buffer.h"
using ::node::Buffer;
using v8::Context;
using v8::Function;
using v8::Handle;
using v8::Object;
using v8::Number;
using v8::Value;
grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
@ -73,7 +77,19 @@ Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}
return NanEscapeScope(NanNewBufferHandle(result, length));
return NanEscapeScope(MakeFastBuffer(NanNewBufferHandle(result, length)));
}
Handle<Value> MakeFastBuffer(Handle<Value> slowBuffer) {
NanEscapableScope();
Handle<Object> globalObj = Context::GetCurrent()->Global();
Handle<Function> bufferConstructor = Handle<Function>::Cast(
globalObj->Get(NanNew("Buffer")));
Handle<Value> consArgs[3] = { slowBuffer,
NanNew<Number>(Buffer::Length(slowBuffer)),
NanNew<Number>(0) };
Handle<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
return NanEscapeScope(fastBuffer);
}
} // namespace node
} // namespace grpc

@ -50,6 +50,10 @@ grpc_byte_buffer *BufferToByteBuffer(v8::Handle<v8::Value> buffer);
/* Convert a grpc_byte_buffer to a Node.js Buffer */
v8::Handle<v8::Value> ByteBufferToBuffer(grpc_byte_buffer *buffer);
/* Convert a ::node::Buffer to a fast Buffer, as defined in the Node
Buffer documentation */
v8::Handle<v8::Value> MakeFastBuffer(v8::Handle<v8::Value> slowBuffer);
} // namespace node
} // namespace grpc

@ -80,7 +80,8 @@ Handle<Value> ParseMetadata(grpc_metadata *metadata_elements, size_t length) {
metadata_object->Set(key_string, array);
}
array->Set(index_map[elem->key],
NanNewBufferHandle(elem->value, elem->value_length));
MakeFastBuffer(
NanNewBufferHandle(elem->value, elem->value_length)));
index_map[elem->key] += 1;
}
return NanEscapeScope(metadata_object);

@ -243,15 +243,24 @@ function Server(getMetadata, options) {
var handler = undefined;
var deadline = data.absolute_deadline;
var cancelled = false;
if (handlers.hasOwnProperty(data.method)) {
handler = handlers[data.method];
}
call.serverAccept(function(event) {
if (event.data.code === grpc.status.CANCELLED) {
cancelled = true;
stream.emit('cancelled');
if (stream) {
stream.emit('cancelled');
}
}
}, 0);
if (handlers.hasOwnProperty(data.method)) {
handler = handlers[data.method];
} else {
call.serverEndInitialMetadata(0);
call.startWriteStatus(
grpc.status.UNIMPLEMENTED,
"This method is not available on this server.",
function() {});
return;
}
if (getMetadata) {
call.addMetadata(getMetadata(data.method, data.metadata));
}

@ -185,6 +185,14 @@ describe('echo client', function() {
done();
});
});
it('should get correct status for unimplemented method', function(done) {
var stream = client.makeRequest(channel, 'unimplemented_method');
stream.end();
stream.on('status', function(status) {
assert.equal(status.code, grpc.status.UNIMPLEMENTED);
done();
});
});
});
/* TODO(mlumish): explore options for reducing duplication between this test
* and the insecure echo client test */

@ -28,9 +28,9 @@ class ActiveCall {
$this->flags = $flags;
// Invoke the call.
$this->call->start_invoke($this->completion_queue,
CLIENT_METADATA_READ,
FINISHED, 0);
$this->call->invoke($this->completion_queue,
CLIENT_METADATA_READ,
FINISHED, 0);
$metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ,
Timeval::inf_future());
$this->metadata = $metadata_event->data;

@ -10,8 +10,8 @@ class BaseStub {
private $channel;
public function __construct($hostname) {
$this->channel = new Channel($hostname, []);
public function __construct($hostname, $opts) {
$this->channel = new Channel($hostname, $opts);
}
/**
@ -33,10 +33,10 @@ class BaseStub {
* @param array $metadata A metadata map to send to the server
* @return SimpleSurfaceActiveCall The active call object
*/
protected function _simpleRequest($method,
$argument,
callable $deserialize,
$metadata = array()) {
public function _simpleRequest($method,
$argument,
callable $deserialize,
$metadata = array()) {
return new SimpleSurfaceActiveCall($this->channel,
$method,
$deserialize,
@ -55,10 +55,10 @@ class BaseStub {
* @param array $metadata A metadata map to send to the server
* @return ClientStreamingSurfaceActiveCall The active call object
*/
protected function _clientStreamRequest($method,
$arguments,
callable $deserialize,
$metadata = array()) {
public function _clientStreamRequest($method,
$arguments,
callable $deserialize,
$metadata = array()) {
return new ClientStreamingSurfaceActiveCall($this->channel,
$method,
$deserialize,
@ -76,10 +76,10 @@ class BaseStub {
* @param array $metadata A metadata map to send to the server
* @return ServerStreamingSurfaceActiveCall The active call object
*/
protected function _serverStreamRequest($method,
$argument,
callable $deserialize,
$metadata = array()) {
public function _serverStreamRequest($method,
$argument,
callable $deserialize,
$metadata = array()) {
return new ServerStreamingSurfaceActiveCall($this->channel,
$method,
$deserialize,
@ -95,9 +95,9 @@ class BaseStub {
* @param array $metadata A metadata map to send to the server
* @return BidiStreamingSurfaceActiveCall The active call object
*/
protected function _bidiRequest($method,
callable $deserialize,
$metadata = array()) {
public function _bidiRequest($method,
callable $deserialize,
$metadata = array()) {
return new BidiStreamingSurfaceActiveCall($this->channel,
$method,
$deserialize,

@ -1,9 +1,9 @@
<?php
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
// Source: net/proto2/proto/empty.proto
// Date: 2014-12-03 22:02:20
// Source: test/cpp/interop/empty.proto
// Date: 2015-01-30 23:30:46
namespace proto2 {
namespace grpc\testing {
class EmptyMessage extends \DrSlump\Protobuf\Message {
@ -13,7 +13,7 @@ namespace proto2 {
public static function descriptor()
{
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'proto2.EmptyMessage');
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.EmptyMessage');
foreach (self::$__extensions as $cb) {
$descriptor->addField($cb(), true);
@ -23,4 +23,3 @@ namespace proto2 {
}
}
}

@ -25,7 +25,7 @@ function hardAssert($value, $error_message) {
* @param $stub Stub object that has service methods
*/
function emptyUnary($stub) {
list($result, $status) = $stub->EmptyCall(new proto2\EmptyMessage())->wait();
list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait();
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result != null, 'Call completed with a null response');
}
@ -161,11 +161,12 @@ $server_address = $args['server_host'] . ':' . $args['server_port'];
$credentials = Grpc\Credentials::createSsl(
file_get_contents(dirname(__FILE__) . '/../data/ca.pem'));
$stub = new grpc\testing\TestServiceClient(
$server_address,
[
'grpc.ssl_target_name_override' => 'foo.test.google.com',
'credentials' => $credentials
]);
new Grpc\BaseStub(
$server_address,
[
'grpc.ssl_target_name_override' => 'foo.test.google.com',
'credentials' => $credentials
]));
echo "Connecting to $server_address\n";
echo "Running test case $args[test_case]\n";

@ -1,7 +1,7 @@
<?php
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
// Source: third_party/stubby/testing/proto/messages.proto
// Date: 2014-12-03 22:02:20
// Source: test/cpp/interop/messages.proto
// Date: 2015-01-30 23:30:46
namespace grpc\testing {
@ -142,6 +142,12 @@ namespace grpc\testing {
/** @var \grpc\testing\Payload */
public $payload = null;
/** @var boolean */
public $fill_username = null;
/** @var boolean */
public $fill_oauth_scope = null;
/** @var \Closure[] */
protected static $__extensions = array();
@ -176,6 +182,22 @@ namespace grpc\testing {
$f->reference = '\grpc\testing\Payload';
$descriptor->addField($f);
// OPTIONAL BOOL fill_username = 4
$f = new \DrSlump\Protobuf\Field();
$f->number = 4;
$f->name = "fill_username";
$f->type = \DrSlump\Protobuf::TYPE_BOOL;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL BOOL fill_oauth_scope = 5
$f = new \DrSlump\Protobuf\Field();
$f->number = 5;
$f->name = "fill_oauth_scope";
$f->type = \DrSlump\Protobuf::TYPE_BOOL;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
foreach (self::$__extensions as $cb) {
$descriptor->addField($cb(), true);
}
@ -293,6 +315,80 @@ namespace grpc\testing {
public function setPayload(\grpc\testing\Payload $value){
return $this->_set(3, $value);
}
/**
* Check if <fill_username> has a value
*
* @return boolean
*/
public function hasFillUsername(){
return $this->_has(4);
}
/**
* Clear <fill_username> value
*
* @return \grpc\testing\SimpleRequest
*/
public function clearFillUsername(){
return $this->_clear(4);
}
/**
* Get <fill_username> value
*
* @return boolean
*/
public function getFillUsername(){
return $this->_get(4);
}
/**
* Set <fill_username> value
*
* @param boolean $value
* @return \grpc\testing\SimpleRequest
*/
public function setFillUsername( $value){
return $this->_set(4, $value);
}
/**
* Check if <fill_oauth_scope> has a value
*
* @return boolean
*/
public function hasFillOauthScope(){
return $this->_has(5);
}
/**
* Clear <fill_oauth_scope> value
*
* @return \grpc\testing\SimpleRequest
*/
public function clearFillOauthScope(){
return $this->_clear(5);
}
/**
* Get <fill_oauth_scope> value
*
* @return boolean
*/
public function getFillOauthScope(){
return $this->_get(5);
}
/**
* Set <fill_oauth_scope> value
*
* @param boolean $value
* @return \grpc\testing\SimpleRequest
*/
public function setFillOauthScope( $value){
return $this->_set(5, $value);
}
}
}
@ -303,8 +399,11 @@ namespace grpc\testing {
/** @var \grpc\testing\Payload */
public $payload = null;
/** @var int */
public $effective_gaia_user_id = null;
/** @var string */
public $username = null;
/** @var string */
public $oauth_scope = null;
/** @var \Closure[] */
@ -323,11 +422,19 @@ namespace grpc\testing {
$f->reference = '\grpc\testing\Payload';
$descriptor->addField($f);
// OPTIONAL INT64 effective_gaia_user_id = 2
// OPTIONAL STRING username = 2
$f = new \DrSlump\Protobuf\Field();
$f->number = 2;
$f->name = "effective_gaia_user_id";
$f->type = \DrSlump\Protobuf::TYPE_INT64;
$f->name = "username";
$f->type = \DrSlump\Protobuf::TYPE_STRING;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL STRING oauth_scope = 3
$f = new \DrSlump\Protobuf\Field();
$f->number = 3;
$f->name = "oauth_scope";
$f->type = \DrSlump\Protobuf::TYPE_STRING;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
@ -376,109 +483,77 @@ namespace grpc\testing {
}
/**
* Check if <effective_gaia_user_id> has a value
* Check if <username> has a value
*
* @return boolean
*/
public function hasEffectiveGaiaUserId(){
public function hasUsername(){
return $this->_has(2);
}
/**
* Clear <effective_gaia_user_id> value
* Clear <username> value
*
* @return \grpc\testing\SimpleResponse
*/
public function clearEffectiveGaiaUserId(){
public function clearUsername(){
return $this->_clear(2);
}
/**
* Get <effective_gaia_user_id> value
* Get <username> value
*
* @return int
* @return string
*/
public function getEffectiveGaiaUserId(){
public function getUsername(){
return $this->_get(2);
}
/**
* Set <effective_gaia_user_id> value
* Set <username> value
*
* @param int $value
* @param string $value
* @return \grpc\testing\SimpleResponse
*/
public function setEffectiveGaiaUserId( $value){
public function setUsername( $value){
return $this->_set(2, $value);
}
}
}
namespace grpc\testing {
class SimpleContext extends \DrSlump\Protobuf\Message {
/** @var string */
public $value = null;
/** @var \Closure[] */
protected static $__extensions = array();
public static function descriptor()
{
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.SimpleContext');
// OPTIONAL STRING value = 1
$f = new \DrSlump\Protobuf\Field();
$f->number = 1;
$f->name = "value";
$f->type = \DrSlump\Protobuf::TYPE_STRING;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
foreach (self::$__extensions as $cb) {
$descriptor->addField($cb(), true);
}
return $descriptor;
}
/**
* Check if <value> has a value
* Check if <oauth_scope> has a value
*
* @return boolean
*/
public function hasValue(){
return $this->_has(1);
public function hasOauthScope(){
return $this->_has(3);
}
/**
* Clear <value> value
* Clear <oauth_scope> value
*
* @return \grpc\testing\SimpleContext
* @return \grpc\testing\SimpleResponse
*/
public function clearValue(){
return $this->_clear(1);
public function clearOauthScope(){
return $this->_clear(3);
}
/**
* Get <value> value
* Get <oauth_scope> value
*
* @return string
*/
public function getValue(){
return $this->_get(1);
public function getOauthScope(){
return $this->_get(3);
}
/**
* Set <value> value
* Set <oauth_scope> value
*
* @param string $value
* @return \grpc\testing\SimpleContext
* @return \grpc\testing\SimpleResponse
*/
public function setValue( $value){
return $this->_set(1, $value);
public function setOauthScope( $value){
return $this->_set(3, $value);
}
}
}
@ -997,15 +1072,3 @@ namespace grpc\testing {
}
}
namespace {
\proto2\bridge\MessageSet::extension(function(){
// OPTIONAL MESSAGE grpc\testing\SimpleContext\message_set_extension = 71139615
$f = new \DrSlump\Protobuf\Field();
$f->number = 71139615;
$f->name = "grpc\testing\SimpleContext\message_set_extension";
$f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$f->reference = '\grpc\testing\SimpleContext';
return $f;
});
}

@ -1,52 +1,52 @@
<?php
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
// Source: third_party/stubby/testing/proto/test.proto
// Date: 2014-12-03 22:02:20
// Source: test/cpp/interop/test.proto
// Date: 2015-01-30 23:30:46
namespace grpc\testing {
class TestServiceClient extends \Grpc\BaseStub {
class TestServiceClient{
private $rpc_impl;
public function __construct($rpc_impl) {
$this->rpc_impl = $rpc_impl;
}
/**
* @param proto2\EmptyMessage $input
* @return proto2\EmptyMessage
* @param grpc\testing\EmptyMessage $input
*/
public function EmptyCall(\proto2\EmptyMessage $argument, $metadata = array()) {
return $this->_simpleRequest('/TestService/EmptyCall', $argument, '\proto2\EmptyMessage::deserialize', $metadata);
public function EmptyCall(\grpc\testing\EmptyMessage $argument, $metadata = array()) {
return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/EmptyCall', $argument, '\grpc\testing\EmptyMessage::deserialize', $metadata);
}
/**
* @param grpc\testing\SimpleRequest $input
* @return grpc\testing\SimpleResponse
*/
public function UnaryCall(\grpc\testing\SimpleRequest $argument, $metadata = array()) {
return $this->_simpleRequest('/TestService/UnaryCall', $argument, '\grpc\testing\SimpleResponse::deserialize', $metadata);
return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/UnaryCall', $argument, '\grpc\testing\SimpleResponse::deserialize', $metadata);
}
/**
* @param grpc\testing\StreamingOutputCallRequest $input
* @return grpc\testing\StreamingOutputCallResponse
*/
public function StreamingOutputCall($argument, $metadata = array()) {
return $this->_serverStreamRequest('/TestService/StreamingOutputCall', $argument, '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
return $this->rpc_impl->_serverStreamRequest('/grpc.testing.TestService/StreamingOutputCall', $argument, '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
}
/**
* @param grpc\testing\StreamingInputCallRequest $input
* @return grpc\testing\StreamingInputCallResponse
*/
public function StreamingInputCall($arguments, $metadata = array()) {
return $this->_clientStreamRequest('/TestService/StreamingInputCall', $arguments, '\grpc\testing\StreamingInputCallResponse::deserialize', $metadata);
return $this->rpc_impl->_clientStreamRequest('/grpc.testing.TestService/StreamingInputCall', $arguments, '\grpc\testing\StreamingInputCallResponse::deserialize', $metadata);
}
/**
* @param grpc\testing\StreamingOutputCallRequest $input
* @return grpc\testing\StreamingOutputCallResponse
*/
public function FullDuplexCall($metadata = array()) {
return $this->_bidiRequest('/TestService/FullDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/FullDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
}
/**
* @param grpc\testing\StreamingOutputCallRequest $input
* @return grpc\testing\StreamingOutputCallResponse
*/
public function HalfDuplexCall($metadata = array()) {
return $this->_bidiRequest('/TestService/HalfDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/HalfDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
}
}
}

@ -86,19 +86,49 @@ def which(filename):
raise Exception('%s not found' % filename)
class JobSpec(object):
"""Specifies what to run for a job."""
def __init__(self, cmdline, shortname=None, environ={}, hash_targets=[]):
"""
Arguments:
cmdline: a list of arguments to pass as the command line
environ: a dictionary of environment variables to set in the child process
hash_targets: which files to include in the hash representing the jobs version
(or empty, indicating the job should not be hashed)
"""
self.cmdline = cmdline
self.environ = environ
self.shortname = cmdline[0] if shortname is None else shortname
self.hash_targets = hash_targets or []
def identity(self):
return '%r %r %r' % (self.cmdline, self.environ, self.hash_targets)
def __hash__(self):
return hash(self.identity())
def __cmp__(self, other):
return self.identity() == other.identity()
class Job(object):
"""Manages one job."""
def __init__(self, cmdline, bin_hash, newline_on_success):
self._cmdline = cmdline
def __init__(self, spec, bin_hash, newline_on_success):
self._spec = spec
self._bin_hash = bin_hash
self._tempfile = tempfile.TemporaryFile()
self._process = subprocess.Popen(args=cmdline,
env = os.environ.copy()
for k, v in spec.environ.iteritems():
env[k] = v
self._process = subprocess.Popen(args=spec.cmdline,
stderr=subprocess.STDOUT,
stdout=self._tempfile)
stdout=self._tempfile,
env=env)
self._state = _RUNNING
self._newline_on_success = newline_on_success
message('START', ' '.join(self._cmdline))
message('START', spec.shortname)
def state(self, update_cache):
"""Poll current state of the job. Prints messages at completion."""
@ -108,12 +138,13 @@ class Job(object):
self._tempfile.seek(0)
stdout = self._tempfile.read()
message('FAILED', '%s [ret=%d]' % (
' '.join(self._cmdline), self._process.returncode), stdout)
self._spec.shortname, self._process.returncode), stdout)
else:
self._state = _SUCCESS
message('PASSED', '%s' % ' '.join(self._cmdline),
message('PASSED', self._spec.shortname,
do_newline=self._newline_on_success)
update_cache.finished(self._cmdline, self._bin_hash)
if self._bin_hash:
update_cache.finished(self._spec.identity(), self._bin_hash)
return self._state
def kill(self):
@ -135,16 +166,26 @@ class Jobset(object):
self._newline_on_success = newline_on_success
self._cache = cache
def start(self, cmdline):
def start(self, spec):
"""Start a job. Return True on success, False on failure."""
while len(self._running) >= self._maxjobs:
if self.cancelled(): return False
self.reap()
if self.cancelled(): return False
with open(which(cmdline[0])) as f:
bin_hash = hashlib.sha1(f.read()).hexdigest()
if self._cache.should_run(cmdline, bin_hash):
self._running.add(Job(cmdline, bin_hash, self._newline_on_success))
if spec.hash_targets:
bin_hash = hashlib.sha1()
for fn in spec.hash_targets:
with open(which(fn)) as f:
bin_hash.update(f.read())
bin_hash = bin_hash.hexdigest()
should_run = self._cache.should_run(spec.identity(), bin_hash)
else:
bin_hash = None
should_run = True
if should_run:
self._running.add(Job(spec,
bin_hash,
self._newline_on_success))
return True
def reap(self):

@ -17,13 +17,17 @@ import watch_dirs
# SimpleConfig: just compile with CONFIG=config, and run the binary to test
class SimpleConfig(object):
def __init__(self, config):
def __init__(self, config, environ={}):
self.build_config = config
self.maxjobs = 2 * multiprocessing.cpu_count()
self.allow_hashing = (config != 'gcov')
self.environ = environ
def run_command(self, binary):
return [binary]
def job_spec(self, binary, hash_targets):
return jobset.JobSpec(cmdline=[binary],
environ=self.environ,
hash_targets=hash_targets
if self.allow_hashing else None)
# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
@ -35,14 +39,14 @@ class ValgrindConfig(object):
self.maxjobs = 2 * multiprocessing.cpu_count()
self.allow_hashing = False
def run_command(self, binary):
return ['valgrind', binary, '--tool=%s' % self.tool]
def job_spec(self, binary, hash_targets):
return JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool, binary],
hash_targets=None)
class CLanguage(object):
def __init__(self, make_target, test_lang):
self.allow_hashing = True
self.make_target = make_target
with open('tools/run_tests/tests.json') as f:
js = json.load(f)
@ -50,8 +54,12 @@ class CLanguage(object):
for tgt in js
if tgt['language'] == test_lang]
def test_binaries(self, config):
return ['bins/%s/%s' % (config, binary) for binary in self.binaries]
def test_specs(self, config):
out = []
for name in self.binaries:
binary = 'bins/%s/%s' % (config.build_config, name)
out.append(config.job_spec(binary, [binary]))
return out
def make_targets(self):
return ['buildtests_%s' % self.make_target]
@ -59,13 +67,11 @@ class CLanguage(object):
def build_steps(self):
return []
class NodeLanguage(object):
def __init__(self):
self.allow_hashing = False
class NodeLanguage(object):
def test_binaries(self, config):
return ['tools/run_tests/run_node.sh']
def test_specs(self, config):
return [config.job_spec('tools/run_tests/run_node.sh', None)]
def make_targets(self):
return ['static_c']
@ -73,13 +79,11 @@ class NodeLanguage(object):
def build_steps(self):
return [['tools/run_tests/build_node.sh']]
class PhpLanguage(object):
def __init__(self):
self.allow_hashing = False
class PhpLanguage(object):
def test_binaries(self, config):
return ['src/php/bin/run_tests.sh']
def test_specs(self, config):
return [config.job_spec('src/php/bin/run_tests.sh', None)]
def make_targets(self):
return ['static_c']
@ -90,11 +94,8 @@ class PhpLanguage(object):
class PythonLanguage(object):
def __init__(self):
self.allow_hashing = False
def test_binaries(self, config):
return ['tools/run_tests/run_python.sh']
def test_specs(self, config):
return [config.job_spec('tools/run_tests/run_python.sh', None)]
def make_targets(self):
return[]
@ -109,7 +110,8 @@ _CONFIGS = {
'opt': SimpleConfig('opt'),
'tsan': SimpleConfig('tsan'),
'msan': SimpleConfig('msan'),
'asan': SimpleConfig('asan'),
'asan': SimpleConfig('asan', environ={
'ASAN_OPTIONS': 'detect_leaks=1:color=always'}),
'gcov': SimpleConfig('gcov'),
'memcheck': ValgrindConfig('valgrind', 'memcheck'),
'helgrind': ValgrindConfig('dbg', 'helgrind')
@ -123,7 +125,7 @@ _LANGUAGES = {
'node': NodeLanguage(),
'php': PhpLanguage(),
'python': PythonLanguage(),
}
}
# parse command line
argp = argparse.ArgumentParser(description='Run grpc tests.')
@ -155,14 +157,20 @@ build_configs = set(cfg.build_config for cfg in run_configs)
make_targets = []
languages = set(_LANGUAGES[l] for l in args.language)
build_steps = [['make',
'-j', '%d' % (multiprocessing.cpu_count() + 1),
'CONFIG=%s' % cfg] + list(set(
itertools.chain.from_iterable(l.make_targets()
for l in languages)))
for cfg in build_configs] + list(
itertools.chain.from_iterable(l.build_steps()
for l in languages))
build_steps = [jobset.JobSpec(['make',
'-j', '%d' % (multiprocessing.cpu_count() + 1),
'CONFIG=%s' % cfg] + list(set(
itertools.chain.from_iterable(
l.make_targets() for l in languages))))
for cfg in build_configs] + list(set(
jobset.JobSpec(cmdline)
for l in languages
for cmdline in l.build_steps()))
one_run = set(
spec
for config in run_configs
for language in args.language
for spec in _LANGUAGES[language].test_specs(config))
runs_per_test = args.runs_per_test
forever = args.forever
@ -175,7 +183,6 @@ class TestCache(object):
self._last_successful_run = {}
def should_run(self, cmdline, bin_hash):
cmdline = ' '.join(cmdline)
if cmdline not in self._last_successful_run:
return True
if self._last_successful_run[cmdline] != bin_hash:
@ -183,7 +190,7 @@ class TestCache(object):
return False
def finished(self, cmdline, bin_hash):
self._last_successful_run[' '.join(cmdline)] = bin_hash
self._last_successful_run[cmdline] = bin_hash
def dump(self):
return [{'cmdline': k, 'hash': v}
@ -209,12 +216,6 @@ def _build_and_run(check_cancelled, newline_on_success, cache):
return 1
# run all the tests
one_run = dict(
(' '.join(config.run_command(x)), config.run_command(x))
for config in run_configs
for language in args.language
for x in _LANGUAGES[language].test_binaries(config.build_config)
).values()
all_runs = itertools.chain.from_iterable(
itertools.repeat(one_run, runs_per_test))
if not jobset.run(all_runs, check_cancelled,
@ -226,12 +227,8 @@ def _build_and_run(check_cancelled, newline_on_success, cache):
return 0
test_cache = (None
if not all(x.allow_hashing
for x in itertools.chain(languages, run_configs))
else TestCache())
if test_cache:
test_cache.maybe_load()
test_cache = TestCache()
test_cache.maybe_load()
if forever:
success = True
@ -248,7 +245,7 @@ if forever:
'All tests are now passing properly',
do_newline=True)
jobset.message('IDLE', 'No change detected')
if test_cache: test_cache.save()
test_cache.save()
while not have_files_changed():
time.sleep(1)
else:
@ -259,5 +256,5 @@ else:
jobset.message('SUCCESS', 'All tests passed', do_newline=True)
else:
jobset.message('FAILED', 'Some tests failed', do_newline=True)
if test_cache: test_cache.save()
test_cache.save()
sys.exit(result)

Loading…
Cancel
Save