merge with head

pull/2656/head
yang-g 9 years ago
commit b36a582c96
  1. 77
      doc/connection-backoff-interop-test-description.md
  2. 57
      doc/interop-test-descriptions.md
  3. 8
      include/grpc++/client_context.h
  4. 1
      include/grpc++/dynamic_thread_pool.h
  5. 2
      include/grpc++/impl/sync_no_cxx11.h
  6. 7
      include/grpc++/server_context.h
  7. 32
      include/grpc/census.h
  8. 2
      src/core/census/grpc_context.c
  9. 19
      src/core/census/initialize.c
  10. 6
      src/core/client_config/subchannel.c
  11. 22
      src/core/iomgr/tcp_server_windows.c
  12. 14
      src/core/iomgr/tcp_windows.c
  13. 7
      src/core/surface/init.c
  14. 2
      src/cpp/client/channel.cc
  15. 5
      src/cpp/server/server_context.cc
  16. 3
      src/node/examples/perf_test.js
  17. 3
      src/node/examples/qps_test.js
  18. 3
      src/node/examples/route_guide_client.js
  19. 3
      src/node/examples/stock_client.js
  20. 52
      src/node/ext/channel.cc
  21. 47
      src/node/ext/credentials.cc
  22. 1
      src/node/ext/credentials.h
  23. 8
      src/node/interop/interop_client.js
  24. 6
      src/node/src/client.js
  25. 6
      src/node/test/call_test.js
  26. 33
      src/node/test/channel_test.js
  27. 4
      src/node/test/end_to_end_test.js
  28. 3
      src/node/test/health_test.js
  29. 3
      src/node/test/math_client_test.js
  30. 14
      src/node/test/surface_test.js
  31. 4
      src/python/src/.gitignore
  32. 1
      src/python/src/MANIFEST.in
  33. 75
      src/python/src/commands.py
  34. 2
      src/python/src/setup.cfg
  35. 28
      src/python/src/setup.py
  36. 2
      test/core/security/oauth2_utils.c
  37. 4
      test/cpp/qps/qps_test.cc
  38. 1
      tools/distrib/python/.gitignore
  39. 113
      tools/distrib/python/docgen.py
  40. 4
      tools/gce_setup/cloud_prod_runner.sh
  41. 7
      tools/gce_setup/grpc_docker.sh
  42. 2
      tools/gce_setup/interop_test_runner.sh
  43. 15
      tools/jenkins/run_jenkins.sh
  44. 2
      tools/run_tests/build_ruby.sh
  45. 2
      tools/run_tests/jobset.py
  46. 36
      tools/run_tests/run_interops.py
  47. 47
      tools/run_tests/run_interops_build.sh
  48. 43
      tools/run_tests/run_interops_test.sh
  49. 4
      tools/run_tests/run_tests.py

@ -0,0 +1,77 @@
Connection Backoff Interop Test Descriptions
===============================================
This test is to verify the client is reconnecting the server with correct
backoffs as specified in
[the spec](http://github.com/grpc/grpc/blob/master/doc/connection-backoff.md).
The test server has a port (control_port) running a rpc service for controlling
the server and another port (retry_port) to close any incoming tcp connections.
The test has the following flow:
1. The server starts listening on control_port.
2. The client calls Start rpc on server control_port.
3. The server starts listening on retry_port.
4. The client connects to server retry_port and retries with backoff for 540s,
which translates to about 13 retries.
5. The client calls Stop rpc on server control port.
6. The client checks the response to see whether the server thinks the backoffs
are conforming the spec or do its own check on the backoffs in the response.
Client and server use
[test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto).
Each language should implement its own client. The C++ server is shared among
languages.
Client
------
Clients should accept these arguments:
* --server_control_port=PORT
* The server port to connect to for rpc. For example, "8080"
* --server_retry_port=PORT
* The server port to connect to for testing backoffs. For example, "8081"
The client must connect to the control port without TLS. The client should
either assert on the server returned backoff status or check the returned
backoffs on its own.
Procedure of client:
1. Calls Start on server control port with a large deadline or no deadline,
waits for its finish and checks it succeeded.
2. Initiates a channel connection to server retry port, which should perform
reconnections with proper backoffs. A convienent way to achieve this is to
call Start with a deadline of 540s. The rpc should fail with deadline exceeded.
3. Calls Stop on server control port and checks it succeeded.
4. Checks the response to see whether the server thinks the backoffs passed the
test.
5. Optionally, the client can do its own check on the returned backoffs.
Server
------
A C++ server can be used for the test. Other languages do NOT need to implement
a server. To minimize the network delay, the server binary should run on the
same machine or on a nearby machine (in terms of network distance) with the
client binary.
A server implements the ReconnectService to its state. It also opens a
tcp server on the retry_port, which just shuts down all incoming tcp
connections to simulate connection failures. The server will keep a record of
all the reconnection timestamps and return the connection backoffs in the
response in milliseconds. The server also checks the backoffs to see whether
they conform the spec and returns whether the client passes the test.
If the server receives a Start call when another client is being tested, it
finishes the call when the other client is done. If some other host connects
to the server retry_port when a client is being tested, the server will log an
error but likely would think the client fails the test.
The server accepts these arguments:
* --control_port=PORT
* The port to listen on for control rpcs. For example, "8080"
* --retry_port=PORT
* The tcp server port. For example, "8081"

@ -483,18 +483,17 @@ library to obtain the authorization token
* received SimpleResponse.oauth_scope is in `--oauth_scope`
### Metadata (TODO: fix name)
Status: Not yet implementable
### custom_metadata
This test verifies that custom metadata in either binary or ascii format can be
sent in header and trailer.
sent as initial-metadata by the client and as both initial- and trailing-metadata
by the server.
Server features:
* [UnaryCall][]
* [FullDuplexCall][]
* [Compressable Payload][]
* Ability to receive custom metadata from client in header and send custom data
back to client in both header and trailer. (TODO: this is not defined)
* [Echo Metadata][]
Procedure:
1. While sending custom metadata (ascii + binary) in the header, client calls
@ -509,21 +508,29 @@ Procedure:
}
}
```
The client attaches custom metadata with the following keys and values:
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts:
* call was successful
* custom metadata is echoed back in the response header.
* custom metadata is echoed back in the response trailer.
* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata.
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata.
### status_code_and_message
Status: Not yet implementable
### status_code_and_message
This test verifies unary calls succeed in sending messages, and propagates back
status code and message sent along with the messages.
Server features:
* [UnaryCall][]
* [FullDuplexCall][]
* [Echo Status][]
Procedure:
1. Client calls UnaryCall with:
@ -536,6 +543,8 @@ Procedure:
}
}
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts:
* received status code is the same with sent code
@ -543,21 +552,15 @@ Asserts:
### unimplemented_method
Status: Not yet implementable
Status: Ready for implementation. Blocking beta.
This test verifies calling unimplemented RPC method returns unimplemented
status.
This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code.
Procedure:
* Client calls UnimplementedCall with:
* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`):
```
{
response_type: COMPRESSABLE
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
@ -767,6 +770,22 @@ When the client requests COMPRESSABLE payload, the response includes a payload
of the size requested containing all zeros and the payload type is
COMPRESSABLE.
### Echo Status
[Echo Status]: #echo-status
When the client sends a response_status in the request payload, the server closes
the stream with the status code and messsage contained within said response_status.
The server will not process any further messages on the stream sent by the client.
This can be used by clients to verify correct handling of different status codes and
associated status messages end-to-end.
### Echo Metadata
[Echo Metadata]: #echo-metadata
When the client sends metadata with the key `"x-grpc-test-echo-initial"` with its
request, the server sends back exactly this key and the corresponding value back to
the client as part of initial metadata. When the client sends metadata with the key
`"x-grpc-test-echo-trailing-bin"` with its request, the server sends back exactly this
key and the corresponding value back to the client as trailing metadata.
### Observe ResponseParameters.interval_us
[Observe ResponseParameters.interval_us]: #observe-responseparametersinterval_us

@ -110,7 +110,7 @@ class ClientContext {
creds_ = creds;
}
grpc_compression_algorithm get_compression_algorithm() const {
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
@ -119,8 +119,8 @@ class ClientContext {
std::shared_ptr<const AuthContext> auth_context() const;
// Get and set census context
void set_census_context(census_context* ccp) { census_context_ = ccp; }
census_context* get_census_context() const { return census_context_; }
void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
struct census_context* census_context() const { return census_context_; }
void TryCancel();
@ -170,7 +170,7 @@ class ClientContext {
grpc::string authority_;
std::shared_ptr<Credentials> creds_;
mutable std::shared_ptr<const AuthContext> auth_context_;
census_context* census_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
std::multimap<grpc::string, grpc::string> recv_initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;

@ -41,6 +41,7 @@
#include <grpc++/thread_pool_interface.h>
#include <list>
#include <memory>
#include <queue>
namespace grpc {

@ -87,7 +87,7 @@ class condition_variable {
~condition_variable() { gpr_cv_destroy(&cv_); }
void wait(lock_guard<mutex> &mu) {
mu.locked = false;
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME);
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
mu.locked = true;
}
void notify_one() { gpr_cv_signal(&cv_); }

@ -46,6 +46,7 @@
struct gpr_timespec;
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc {
@ -104,18 +105,20 @@ class ServerContext {
return client_metadata_;
}
grpc_compression_level get_compression_level() const {
grpc_compression_level compression_level() const {
return compression_level_;
}
void set_compression_level(grpc_compression_level level);
grpc_compression_algorithm get_compression_algorithm() const {
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
void set_compression_algorithm(grpc_compression_algorithm algorithm);
std::shared_ptr<const AuthContext> auth_context() const;
const struct census_context* census_context() const;
private:
friend class ::grpc::testing::InteropContextInspector;
friend class ::grpc::Server;

@ -44,26 +44,30 @@
extern "C" {
#endif
/* Identify census functionality that can be enabled via census_initialize(). */
enum census_functions {
CENSUS_NONE = 0, /* Do not enable census. */
CENSUS_TRACING = 1, /* Enable census tracing. */
CENSUS_STATS = 2, /* Enable Census stats collection. */
CENSUS_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_ALL = CENSUS_TRACING | CENSUS_STATS | CENSUS_CPU
/* Identify census features that can be enabled via census_initialize(). */
enum census_features {
CENSUS_FEATURE_NONE = 0, /* Do not enable census. */
CENSUS_FEATURE_TRACING = 1, /* Enable census tracing. */
CENSUS_FEATURE_STATS = 2, /* Enable Census stats collection. */
CENSUS_FEATURE_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_FEATURE_ALL =
CENSUS_FEATURE_TRACING | CENSUS_FEATURE_STATS | CENSUS_FEATURE_CPU
};
/* Shutdown and startup census subsystem. The 'functions' argument should be
* the OR (|) of census_functions values. If census fails to initialize, then
/** Shutdown and startup census subsystem. The 'features' argument should be
* the OR (|) of census_features values. If census fails to initialize, then
* census_initialize() will return a non-zero value. It is an error to call
* census_initialize() more than once (without an intervening
* census_shutdown()). */
int census_initialize(int functions);
void census_shutdown();
int census_initialize(int features);
void census_shutdown(void);
/* If any census feature has been initialized, this funtion will return a
* non-zero value. */
int census_available();
/** Return the features supported by the current census implementation (not all
* features will be available on all platforms). */
int census_supported(void);
/** Return the census features currently enabled. */
int census_enabled(void);
/* Internally, Census relies on a context, which should be propagated across
* RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.

@ -39,7 +39,7 @@ static void grpc_census_context_destroy(void *context) {
}
void grpc_census_call_set_context(grpc_call *call, census_context *context) {
if (!census_available()) {
if (census_enabled() == CENSUS_FEATURE_NONE) {
return;
}
if (context == NULL) {

@ -33,20 +33,25 @@
#include <grpc/census.h>
static int census_fns_enabled = CENSUS_NONE;
static int features_enabled = CENSUS_FEATURE_NONE;
int census_initialize(int functions) {
if (census_fns_enabled != CENSUS_NONE) {
int census_initialize(int features) {
if (features_enabled != CENSUS_FEATURE_NONE) {
return 1;
}
if (functions != CENSUS_NONE) {
if (features != CENSUS_FEATURE_NONE) {
return 1;
} else {
census_fns_enabled = functions;
features_enabled = features;
return 0;
}
}
void census_shutdown() { census_fns_enabled = CENSUS_NONE; }
void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; }
int census_available() { return (census_fns_enabled != CENSUS_NONE); }
int census_supported(void) {
/* TODO(aveitch): improve this as we implement features... */
return CENSUS_FEATURE_NONE;
}
int census_enabled(void) { return features_enabled; }

@ -132,7 +132,7 @@ struct grpc_subchannel {
/** our alarm */
grpc_alarm alarm;
/** current random value */
gpr_int32 random;
gpr_uint32 random;
};
struct grpc_subchannel_call {
@ -272,8 +272,8 @@ void grpc_subchannel_del_interested_party(grpc_subchannel *c,
grpc_pollset_set_del_pollset(c->pollset_set, pollset);
}
static gpr_int32 random_seed() {
return gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC));
static gpr_uint32 random_seed() {
return (gpr_uint32)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC)));
}
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,

@ -79,6 +79,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
/* number of iomgr callbacks that have been explicitly scheduled during shutdown */
int iomgr_callbacks_pending;
/* all listening ports */
server_port *ports;
@ -93,6 +95,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->active_ports = 0;
s->iomgr_callbacks_pending = 0;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@ -112,10 +115,10 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s,
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
s->iomgr_callbacks_pending += grpc_winsocket_shutdown(sp->socket);
}
/* This happens asynchronously. Wait while that happens. */
while (s->active_ports) {
while (s->active_ports || s->iomgr_callbacks_pending) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
}
gpr_mu_unlock(&s->mu);
@ -254,8 +257,16 @@ static void on_accept(void *arg, int from_iocp) {
/* The general mechanism for shutting down is to queue abortion calls. While
this is necessary in the read/write case, it's useless for the accept
case. Let's do nothing. */
if (!from_iocp) return;
case. We only need to adjust the pending callback count */
if (!from_iocp) {
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->iomgr_callbacks_pending > 0);
if (0 == --sp->server->iomgr_callbacks_pending) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
return;
}
/* The IOCP notified us of a completed operation. Let's grab the results,
and act accordingly. */
@ -264,11 +275,12 @@ static void on_accept(void *arg, int from_iocp) {
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
if (sp->shutting_down) {
/* During the shutdown case, we ARE expecting an error. So that's swell,
/* During the shutdown case, we ARE expecting an error. So that's well,
and we can wake up the shutdown thread. */
sp->shutting_down = 0;
sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}

@ -368,7 +368,14 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
return GRPC_ENDPOINT_WRITE_PENDING;
}
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
(void) ps;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
(void) pss;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
@ -402,8 +409,9 @@ static char *win_get_peer(grpc_endpoint *ep) {
}
static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write,
win_add_to_pollset, win_shutdown,
win_destroy, win_get_peer};
win_add_to_pollset, win_add_to_pollset_set,
win_shutdown, win_destroy,
win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));

@ -80,8 +80,11 @@ void grpc_init(void) {
grpc_security_pre_init();
grpc_iomgr_init();
grpc_tracer_init("GRPC_TRACE");
if (census_initialize(CENSUS_NONE)) {
gpr_log(GPR_ERROR, "Could not initialize census.");
/* Only initialize census if noone else has. */
if (census_enabled() == CENSUS_FEATURE_NONE) {
if (census_initialize(census_supported())) { /* enable all features. */
gpr_log(GPR_ERROR, "Could not initialize census.");
}
}
grpc_timers_global_init();
}

@ -69,7 +69,7 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
? target_.c_str()
: context->authority().c_str(),
context->raw_deadline());
grpc_census_call_set_context(c_call, context->get_census_context());
grpc_census_call_set_context(c_call, context->census_context());
GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call);
context->set_call(c_call, shared_from_this());
return Call(c_call, this, cq);

@ -39,6 +39,7 @@
#include <grpc++/impl/sync.h>
#include <grpc++/time.h>
#include "src/core/census/grpc_context.h"
#include "src/core/channel/compress_filter.h"
#include "src/cpp/common/create_auth_context.h"
@ -179,4 +180,8 @@ std::shared_ptr<const AuthContext> ServerContext::auth_context() const {
return auth_context_;
}
const struct census_context* ServerContext::census_context() const {
return grpc_census_call_get_context(call_);
}
} // namespace grpc

@ -41,7 +41,8 @@ var interop_server = require('../interop/interop_server.js');
function runTest(iterations, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.listen();
var client = new testProto.TestService('localhost:' + testServer.port);
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
function runIterations(finish) {
var start = process.hrtime();

@ -61,7 +61,8 @@ var interop_server = require('../interop/interop_server.js');
function runTest(concurrent_calls, seconds, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.listen();
var client = new testProto.TestService('localhost:' + testServer.port);
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
var warmup_num = 100;

@ -40,7 +40,8 @@ var path = require('path');
var _ = require('lodash');
var grpc = require('..');
var examples = grpc.load(__dirname + '/route_guide.proto').examples;
var client = new examples.RouteGuide('localhost:50051');
var client = new examples.RouteGuide('localhost:50051',
grpc.Credentials.createInsecure());
var COORD_FACTOR = 1e7;

@ -38,7 +38,8 @@ 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);
* var stockClient = new StockClient(server_address,
* grpc.Credentials.createInsecure());
* stockClient.getLastTradePrice({symbol: 'GOOG'}, function(error, response) {
* console.log(error || response);
* });

@ -98,31 +98,30 @@ NAN_METHOD(Channel::New) {
if (args.IsConstructCall()) {
if (!args[0]->IsString()) {
return NanThrowTypeError("Channel expects a string and an object");
return NanThrowTypeError(
"Channel expects a string, a credential and an object");
}
grpc_channel *wrapped_channel;
// Owned by the Channel object
NanUtf8String *host = new NanUtf8String(args[0]);
NanUtf8String *host_override = NULL;
if (args[1]->IsUndefined()) {
grpc_credentials *creds;
if (!Credentials::HasInstance(args[1])) {
return NanThrowTypeError(
"Channel's second argument must be a credential");
}
Credentials *creds_object = ObjectWrap::Unwrap<Credentials>(
args[1]->ToObject());
creds = creds_object->GetWrappedCredentials();
grpc_channel_args *channel_args_ptr;
if (args[2]->IsUndefined()) {
channel_args_ptr = NULL;
wrapped_channel = grpc_insecure_channel_create(**host, NULL);
} else if (args[1]->IsObject()) {
grpc_credentials *creds = NULL;
Handle<Object> args_hash(args[1]->ToObject()->Clone());
} else if (args[2]->IsObject()) {
Handle<Object> args_hash(args[2]->ToObject()->Clone());
if (args_hash->HasOwnProperty(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))) {
host_override = new NanUtf8String(args_hash->Get(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)));
}
if (args_hash->HasOwnProperty(NanNew("credentials"))) {
Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
if (!Credentials::HasInstance(creds_value)) {
return NanThrowTypeError(
"credentials arg must be a Credentials object");
}
Credentials *creds_object =
ObjectWrap::Unwrap<Credentials>(creds_value->ToObject());
creds = creds_object->GetWrappedCredentials();
args_hash->Delete(NanNew("credentials"));
}
Handle<Array> keys(args_hash->GetOwnPropertyNames());
grpc_channel_args channel_args;
channel_args.num_args = keys->Length();
@ -149,16 +148,19 @@ NAN_METHOD(Channel::New) {
return NanThrowTypeError("Arg values must be strings");
}
}
if (creds == NULL) {
wrapped_channel = grpc_insecure_channel_create(**host, &channel_args);
} else {
wrapped_channel =
grpc_secure_channel_create(creds, **host, &channel_args);
}
free(channel_args.args);
channel_args_ptr = &channel_args;
} else {
return NanThrowTypeError("Channel expects a string and an object");
}
if (creds == NULL) {
wrapped_channel = grpc_insecure_channel_create(**host, channel_args_ptr);
} else {
wrapped_channel =
grpc_secure_channel_create(creds, **host, channel_args_ptr);
}
if (channel_args_ptr != NULL) {
free(channel_args_ptr->args);
}
Channel *channel;
if (host_override == NULL) {
channel = new Channel(wrapped_channel, host);
@ -168,8 +170,8 @@ NAN_METHOD(Channel::New) {
channel->Wrap(args.This());
NanReturnValue(args.This());
} else {
const int argc = 2;
Local<Value> argv[argc] = {args[0], args[1]};
const int argc = 3;
Local<Value> argv[argc] = {args[0], args[1], args[2]};
NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv));
}
}

@ -81,6 +81,8 @@ void Credentials::Init(Handle<Object> exports) {
NanNew<FunctionTemplate>(CreateGce)->GetFunction());
ctr->Set(NanNew("createIam"),
NanNew<FunctionTemplate>(CreateIam)->GetFunction());
ctr->Set(NanNew("createInsecure"),
NanNew<FunctionTemplate>(CreateInsecure)->GetFunction());
constructor = new NanCallback(ctr);
exports->Set(NanNew("Credentials"), ctr);
}
@ -92,9 +94,6 @@ bool Credentials::HasInstance(Handle<Value> val) {
Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
NanEscapableScope();
if (credentials == NULL) {
return NanEscapeScope(NanNull());
}
const int argc = 1;
Handle<Value> argv[argc] = {
NanNew<External>(reinterpret_cast<void *>(credentials))};
@ -128,7 +127,11 @@ NAN_METHOD(Credentials::New) {
NAN_METHOD(Credentials::CreateDefault) {
NanScope();
NanReturnValue(WrapStruct(grpc_google_default_credentials_create()));
grpc_credentials *creds = grpc_google_default_credentials_create();
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateSsl) {
@ -152,9 +155,12 @@ NAN_METHOD(Credentials::CreateSsl) {
return NanThrowTypeError(
"createSSl's third argument must be a Buffer if provided");
}
NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
grpc_credentials *creds = grpc_ssl_credentials_create(
root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateComposite) {
@ -169,13 +175,21 @@ NAN_METHOD(Credentials::CreateComposite) {
}
Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
NanReturnValue(WrapStruct(grpc_composite_credentials_create(
creds1->wrapped_credentials, creds2->wrapped_credentials)));
grpc_credentials *creds = grpc_composite_credentials_create(
creds1->wrapped_credentials, creds2->wrapped_credentials);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateGce) {
NanScope();
NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
grpc_credentials *creds = grpc_compute_engine_credentials_create();
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateIam) {
@ -188,8 +202,17 @@ NAN_METHOD(Credentials::CreateIam) {
}
NanUtf8String auth_token(args[0]);
NanUtf8String auth_selector(args[1]);
NanReturnValue(
WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
grpc_credentials *creds = grpc_iam_credentials_create(*auth_token,
*auth_selector);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateInsecure) {
NanScope();
NanReturnValue(WrapStruct(NULL));
}
} // namespace node

@ -68,6 +68,7 @@ class Credentials : public ::node::ObjectWrap {
static NAN_METHOD(CreateGce);
static NAN_METHOD(CreateFake);
static NAN_METHOD(CreateIam);
static NAN_METHOD(CreateInsecure);
static NanCallback *constructor;
// Used for typechecking instances of this javascript class
static v8::Persistent<v8::FunctionTemplate> fun_tpl;

@ -397,6 +397,7 @@ var test_cases = {
function runTest(address, host_override, test_case, tls, test_ca, done) {
// TODO(mlumish): enable TLS functionality
var options = {};
var creds;
if (tls) {
var ca_path;
if (test_ca) {
@ -405,13 +406,14 @@ function runTest(address, host_override, test_case, tls, test_ca, done) {
ca_path = process.env.SSL_CERT_FILE;
}
var ca_data = fs.readFileSync(ca_path);
var creds = grpc.Credentials.createSsl(ca_data);
options.credentials = creds;
creds = grpc.Credentials.createSsl(ca_data);
if (host_override) {
options['grpc.ssl_target_name_override'] = host_override;
}
} else {
creds = grpc.Credentials.createInsecure();
}
var client = new testProto.TestService(address, options);
var client = new testProto.TestService(address, creds, options);
test_cases[test_case](client, done);
}

@ -531,11 +531,13 @@ exports.makeClientConstructor = function(methods, serviceName) {
* Create a client with the given methods
* @constructor
* @param {string} address The address of the server to connect to
* @param {grpc.Credentials} credentials Credentials to use to connect
* to the server
* @param {Object} options Options to pass to the underlying channel
* @param {function(string, Object, function)=} updateMetadata function to
* update the metadata for each request
*/
function Client(address, options, updateMetadata) {
function Client(address, credentials, options, updateMetadata) {
if (!updateMetadata) {
updateMetadata = function(uri, metadata, callback) {
callback(null, metadata);
@ -545,7 +547,7 @@ exports.makeClientConstructor = function(methods, serviceName) {
options = {};
}
options['grpc.primary_user_agent'] = 'grpc-node/' + version;
this.channel = new grpc.Channel(address, options);
this.channel = new grpc.Channel(address, credentials, options);
this.server_address = address.replace(/\/$/, '');
this.auth_uri = this.server_address + '/' + serviceName;
this.updateMetadata = updateMetadata;

@ -48,6 +48,8 @@ function getDeadline(timeout_secs) {
return deadline;
}
var insecureCreds = grpc.Credentials.createInsecure();
describe('call', function() {
var channel;
var server;
@ -55,7 +57,7 @@ describe('call', function() {
server = new grpc.Server();
var port = server.addHttp2Port('localhost:0');
server.start();
channel = new grpc.Channel('localhost:' + port);
channel = new grpc.Channel('localhost:' + port, insecureCreds);
});
after(function() {
server.shutdown();
@ -82,7 +84,7 @@ describe('call', function() {
});
});
it('should fail with a closed channel', function() {
var local_channel = new grpc.Channel('hostname');
var local_channel = new grpc.Channel('hostname', insecureCreds);
local_channel.close();
assert.throws(function() {
new grpc.Call(channel, 'method');

@ -36,11 +36,13 @@
var assert = require('assert');
var grpc = require('bindings')('grpc.node');
var insecureCreds = grpc.Credentials.createInsecure();
describe('channel', function() {
describe('constructor', function() {
it('should require a string for the first argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname');
new grpc.Channel('hostname', insecureCreds);
});
assert.throws(function() {
new grpc.Channel();
@ -49,38 +51,49 @@ describe('channel', function() {
new grpc.Channel(5);
});
});
it('should accept an object for the second parameter', function() {
it('should require a credential for the second argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {});
new grpc.Channel('hostname', insecureCreds);
});
assert.throws(function() {
new grpc.Channel('hostname', 5);
});
assert.throws(function() {
new grpc.Channel('hostname');
});
});
it('should accept an object for the third argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', insecureCreds, {});
});
assert.throws(function() {
new grpc.Channel('hostname', insecureCreds, 'abc');
});
});
it('should only accept objects with string or int values', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {'key' : 'value'});
new grpc.Channel('hostname', insecureCreds,{'key' : 'value'});
});
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {'key' : 5});
new grpc.Channel('hostname', insecureCreds, {'key' : 5});
});
assert.throws(function() {
new grpc.Channel('hostname', {'key' : null});
new grpc.Channel('hostname', insecureCreds, {'key' : null});
});
assert.throws(function() {
new grpc.Channel('hostname', {'key' : new Date()});
new grpc.Channel('hostname', insecureCreds, {'key' : new Date()});
});
});
});
describe('close', function() {
it('should succeed silently', function() {
var channel = new grpc.Channel('hostname', {});
var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
});
});
it('should be idempotent', function() {
var channel = new grpc.Channel('hostname', {});
var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
channel.close();
@ -89,7 +102,7 @@ describe('channel', function() {
});
describe('getTarget', function() {
it('should return a string', function() {
var channel = new grpc.Channel('localhost', {});
var channel = new grpc.Channel('localhost', insecureCreds, {});
assert.strictEqual(typeof channel.getTarget(), 'string');
});
});

@ -57,6 +57,8 @@ function multiDone(done, count) {
};
}
var insecureCreds = grpc.Credentials.createInsecure();
describe('end-to-end', function() {
var server;
var channel;
@ -64,7 +66,7 @@ describe('end-to-end', function() {
server = new grpc.Server();
var port_num = server.addHttp2Port('0.0.0.0:0');
server.start();
channel = new grpc.Channel('localhost:' + port_num);
channel = new grpc.Channel('localhost:' + port_num, insecureCreds);
});
after(function() {
server.shutdown();

@ -56,7 +56,8 @@ describe('Health Checking', function() {
before(function() {
var port_num = healthServer.bind('0.0.0.0:0');
healthServer.start();
healthClient = new health.Client('localhost:' + port_num);
healthClient = new health.Client('localhost:' + port_num,
grpc.Credentials.createInsecure());
});
after(function() {
healthServer.shutdown();

@ -53,7 +53,8 @@ describe('Math client', function() {
before(function(done) {
var port_num = server.bind('0.0.0.0:0');
server.start();
math_client = new math.Math('localhost:' + port_num);
math_client = new math.Math('localhost:' + port_num,
grpc.Credentials.createInsecure());
done();
});
after(function() {

@ -124,7 +124,7 @@ describe('Echo service', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(echo_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -169,7 +169,8 @@ describe('Generic client and server', function() {
var port = server.bind('localhost:0');
server.start();
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port,
grpc.Credentials.createInsecure());
});
after(function() {
server.shutdown();
@ -216,7 +217,7 @@ describe('Echo metadata', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -337,7 +338,7 @@ describe('Other conditions', function() {
});
port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -382,7 +383,8 @@ describe('Other conditions', function() {
};
var Client = surface_client.makeClientConstructor(test_service_attrs,
'TestService');
misbehavingClient = new Client('localhost:' + port);
misbehavingClient = new Client('localhost:' + port,
grpc.Credentials.createInsecure());
});
it('should respond correctly to a unary call', function(done) {
misbehavingClient.unary(badArg, function(err, data) {
@ -602,7 +604,7 @@ describe('Cancelling surface client', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(mathService);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {

@ -2,3 +2,7 @@ MANIFEST
grpcio.egg-info/
build/
dist/
*.egg
*.egg/
*.eggs/
doc/

@ -1 +1,2 @@
graft grpc
include commands.py

@ -0,0 +1,75 @@
# 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.
"""Provides distutils command classes for the GRPC Python setup process."""
import os
import os.path
import sys
import setuptools
_CONF_PY_ADDENDUM = """
extensions.append('sphinx.ext.napoleon')
napoleon_google_docstring = True
napoleon_numpy_docstring = True
html_theme = 'sphinx_rtd_theme'
"""
class SphinxDocumentation(setuptools.Command):
"""Command to generate documentation via sphinx."""
description = ''
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# We import here to ensure that setup.py has had a chance to install the
# relevant package eggs first.
import sphinx
import sphinx.apidoc
metadata = self.distribution.metadata
src_dir = os.path.join(
os.getcwd(), self.distribution.package_dir['grpc'])
sys.path.append(src_dir)
sphinx.apidoc.main([
'', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
'-V', metadata.version, '-R', metadata.version,
'-o', os.path.join('doc', 'src'), src_dir])
conf_filepath = os.path.join('doc', 'src', 'conf.py')
with open(conf_filepath, 'a') as conf_file:
conf_file.write(_CONF_PY_ADDENDUM)
sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])

@ -0,0 +1,2 @@
[build_ext]
inplace=1

@ -30,11 +30,17 @@
"""A setup module for the GRPC Python package."""
import os
import os.path
import sys
from distutils import core as _core
import setuptools
# Ensure we're in the proper directory whether or not we're being used by pip.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our commands module.
import commands
# Use environment variables to determine whether or not the Cython extension
# should *use* Cython or use the generated C files. Note that this requires the
@ -98,15 +104,27 @@ _PACKAGE_DIRECTORIES = {
'grpc.framework': 'grpc/framework',
}
_INSTALL_REQUIRES = (
'enum34==1.0.4',
'futures==2.2.0',
'protobuf==3.0.0a3'
)
_SETUP_REQUIRES = (
'sphinx>=1.3',
) + _INSTALL_REQUIRES
_COMMAND_CLASS = {
'doc': commands.SphinxDocumentation
}
setuptools.setup(
name='grpcio',
version='0.10.0a0',
ext_modules=_EXTENSION_MODULES,
packages=list(_PACKAGES),
package_dir=_PACKAGE_DIRECTORIES,
install_requires=[
'enum34==1.0.4',
'futures==2.2.0',
'protobuf==3.0.0a3'
]
install_requires=_INSTALL_REQUIRES,
setup_requires=_SETUP_REQUIRES,
cmdclass=_COMMAND_CLASS
)

@ -84,7 +84,7 @@ char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
gpr_mu_lock(GRPC_POLLSET_MU(&request.pollset));
while (!request.is_done)
grpc_pollset_work(&request.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
grpc_pollset_work(&request.pollset, gpr_inf_future(GPR_CLOCK_MONOTONIC));
gpr_mu_unlock(GRPC_POLLSET_MU(&request.pollset));
grpc_pollset_shutdown(&request.pollset, do_nothing, NULL);

@ -53,8 +53,8 @@ static void RunQPS() {
ClientConfig client_config;
client_config.set_client_type(ASYNC_CLIENT);
client_config.set_enable_ssl(false);
client_config.set_outstanding_rpcs_per_channel(10);
client_config.set_client_channels(800);
client_config.set_outstanding_rpcs_per_channel(1000);
client_config.set_client_channels(8);
client_config.set_payload_size(1);
client_config.set_async_client_threads(8);
client_config.set_rpc_type(UNARY);

@ -0,0 +1 @@
distrib_virtualenv/

@ -0,0 +1,113 @@
#!/usr/bin/env python
# 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.
import argparse
import os
import os.path
import shutil
import subprocess
import tempfile
parser = argparse.ArgumentParser()
parser.add_argument('--config', metavar='c', type=str, nargs=1,
help='GRPC/GPR libraries build configuration',
default='opt')
parser.add_argument('--submit', action='store_true')
parser.add_argument('--gh-user', type=str, help='GitHub user to push as.')
parser.add_argument('--gh-repo-owner', type=str,
help=('Owner of the GitHub repository to be pushed; '
'defaults to --gh-user.'))
parser.add_argument('--doc-branch', type=str)
args = parser.parse_args()
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
CONFIG = args.config
SETUP_PATH = os.path.join(PROJECT_ROOT, 'src/python/src/setup.py')
DOC_PATH = os.path.join(PROJECT_ROOT, 'src/python/src/doc/build')
INCLUDE_PATH = os.path.join(PROJECT_ROOT, 'include')
LIBRARY_PATH = os.path.join(PROJECT_ROOT, 'libs/{}'.format(CONFIG))
VIRTUALENV_DIR = os.path.join(SCRIPT_DIR, 'distrib_virtualenv')
VIRTUALENV_PYTHON_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'python')
environment = os.environ.copy()
environment.update({
'CONFIG': CONFIG,
'CFLAGS': '-I{}'.format(INCLUDE_PATH),
'LDFLAGS': '-L{}'.format(LIBRARY_PATH),
'LD_LIBRARY_PATH': LIBRARY_PATH
})
subprocess_arguments_list = [
{'args': ['make'], 'cwd': PROJECT_ROOT},
{'args': ['virtualenv', VIRTUALENV_DIR], 'env': environment},
{'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'build'], 'env': environment},
{'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'doc'], 'env': environment},
]
for subprocess_arguments in subprocess_arguments_list:
subprocess.check_call(**subprocess_arguments)
if args.submit:
assert args.gh_user
assert args.doc_branch
github_user = args.gh_user
github_repository_owner = (
args.gh_repo_owner if args.gh_repo_owner else gh_user)
# Create a temporary directory out of tree, checkout gh-pages from the
# specified repository, edit it, and push it. It's up to the user to then go
# onto GitHub and make a PR against grpc/grpc:gh-pages.
repo_parent_dir = tempfile.mkdtemp()
repo_dir = os.path.join(repo_parent_dir, 'grpc')
python_doc_dir = os.path.join(repo_dir, 'python')
doc_branch = args.doc_branch
subprocess.check_call([
'git', 'clone', 'https://{}@github.com/{}/grpc'.format(
github_user, github_repository_owner)
], cwd=repo_parent_dir)
subprocess.check_call([
'git', 'remote', 'add', 'upstream', 'https://github.com/grpc/grpc'
], cwd=repo_dir)
subprocess.check_call(['git', 'fetch', 'upstream'], cwd=repo_dir)
subprocess.check_call([
'git', 'checkout', 'upstream/gh-pages', '-b', doc_branch
], cwd=repo_dir)
shutil.rmtree(python_doc_dir, ignore_errors=True)
shutil.copytree(DOC_PATH, python_doc_dir)
subprocess.check_call(['git', 'add', '--all'], cwd=repo_dir)
subprocess.check_call([
'git', 'commit', '-m', 'Auto-update Python documentation'
], cwd=repo_dir)
subprocess.check_call([
'git', 'push', '--set-upstream', 'origin', doc_branch
], cwd=repo_dir)
shutil.rmtree(repo_parent_dir)

@ -34,8 +34,8 @@ log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-656-ou
main() {
source grpc_docker.sh
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds)
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds oauth2_auth_token per_rpc_creds)
clients=(cxx java go ruby node csharp_mono csharp_dotnet python php)
for test_case in "${test_cases[@]}"
do

@ -508,7 +508,12 @@ grpc_cloud_prod_auth_test_args() {
grpc_gen_test_cmd="grpc_cloud_prod_auth_"
[[ -n $1 ]] && { # test_case
test_case=$1
grpc_gen_test_cmd+="$1"
test_command="service_account_creds"
if [ "$test_case" == "compute_engine_creds" ]
then
test_command="compute_engine_creds"
fi
grpc_gen_test_cmd+=$test_command
shift
} || {
echo "$FUNCNAME: missing arg: test_case" 1>&2

@ -37,7 +37,7 @@ fail_log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-6
main() {
source grpc_docker.sh
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
clients=(cxx java go ruby node python csharp_mono php)
servers=(cxx java go ruby node python csharp_mono)
for test_case in "${test_cases[@]}"

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
@ -31,6 +31,8 @@
# This script is invoked by Jenkins and triggers a test run based on
# env variable settings.
#
# Bootstrap into bash
[ -z $1 ] && exec bash $0 bootstrapped
# Setting up rvm environment BEFORE we set -ex.
[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
# To prevent cygwin bash complaining about empty lines ending with \r
@ -90,7 +92,9 @@ then
docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
sleep 4
docker rm $DOCKER_CID || true
elif [ "$platform" == "interop" ]
then
python tools/run_tests/run_interops.py --language=$language
elif [ "$platform" == "windows" ]
then
echo "building $language on Windows"
@ -103,11 +107,18 @@ then
/cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln
python tools/run_tests/run_tests.py -t -l $language -x report.xml || true
elif [ "$platform" == "macos" ]
then
echo "building $language on MacOS"
./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
elif [ "$platform" == "freebsd" ]
then
echo "building $language on FreeBSD"
MAKE=gmake ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
else
echo "Unknown platform $platform"
exit 1

@ -36,5 +36,7 @@ export GRPC_CONFIG=${CONFIG:-opt}
# change to grpc's ruby directory
cd $(dirname $0)/../../src/ruby
rm -rf ./tmp
bundle install
rake compile:grpc

@ -206,7 +206,7 @@ class Job(object):
do_newline=self._newline_on_success or self._travis)
if self._bin_hash:
update_cache.finished(self._spec.identity(), self._bin_hash)
elif self._state == _RUNNING and time.time() - self._start > 600:
elif self._state == _RUNNING and time.time() - self._start > 900:
self._tempfile.seek(0)
stdout = self._tempfile.read()
filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))

@ -0,0 +1,36 @@
import argparse
import xml.etree.cElementTree as ET
import jobset
argp = argparse.ArgumentParser(description='Run interop tests.')
argp.add_argument('-l', '--language',
choices=['build_only', 'c++'],
nargs='+',
default=['build_only'])
args = argp.parse_args()
# build job
build_steps = 'tools/run_tests/run_interops_build.sh'
build_job = jobset.JobSpec(cmdline=build_steps, shortname='build')
# test jobs
_TESTS = ['large_unary', 'empty_unary', 'ping_pong', 'client_streaming', 'server_streaming']
jobs = []
jobNumber = 0
for lang in args.language:
for test in _TESTS:
test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % lang, '%s' % test], shortname=test)
jobs.append(test_job)
jobNumber+=1
root = ET.Element('testsuites')
testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests')
# always do the build of docker first, and then all the tests can run in parallel
jobset.run([build_job], maxjobs=1, xml_report=testsuite)
jobset.run(jobs, maxjobs=jobNumber, xml_report=testsuite)
tree = ET.ElementTree(root)
tree.write('report.xml', encoding='UTF-8')

@ -0,0 +1,47 @@
#!/bin/sh
# 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
#clean up any old docker files and start mirroring repository if not started already
sudo docker rmi -f grpc/cxx || true
sudo docker rmi -f grpc/base || true
sudo docker rmi -f 0.0.0.0:5000/grpc/base || true
sudo docker run -d -e GCS_BUCKET=docker-interop-images -e STORAGE_PATH=/admin/docker_images -p 5000:5000 google/docker-registry || true
#prepare building by pulling down base images and necessary files
sudo docker pull 0.0.0.0:5000/grpc/base
sudo docker tag -f 0.0.0.0:5000/grpc/base grpc/base
gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_cxx
gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_cxx
#build docker file, add more languages later
sudo docker build --no-cache -t grpc/cxx tools/dockerfile/grpc_cxx

@ -0,0 +1,43 @@
#!/bin/sh
# 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.
language=$1
test_case=$2
set -e
if [ "$language" = "c++" ]
then
sudo docker run grpc/cxx /var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots --server_host_override=grpc-test.sandbox.google.com --server_host=grpc-test.sandbox.google.com --server_port=443 --test_case=$test_case
else
echo "interop testss not added for $language"
exit 1
fi

@ -253,7 +253,7 @@ class RubyLanguage(object):
environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
def make_targets(self):
return ['run_dep_checks']
return ['static_c']
def build_steps(self):
return [['tools/run_tests/build_ruby.sh']]
@ -458,7 +458,7 @@ if platform.system() == 'Windows':
cwd='vsprojects', shell=True)
else:
def make_jobspec(cfg, targets):
return jobset.JobSpec(['make',
return jobset.JobSpec([os.getenv('MAKE', 'make'),
'-j', '%d' % (multiprocessing.cpu_count() + 1),
'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
args.slowdown,

Loading…
Cancel
Save