Merge branch 'master' of github.com:grpc/grpc into cpp_docs

pull/3074/head
David Garcia Quintas 9 years ago
commit c31c8f3d0e
  1. 2
      .gitmodules
  2. 12
      Makefile
  3. 6
      build.json
  4. 11
      include/grpc++/support/auth_context.h
  5. 10
      include/grpc++/support/string_ref.h
  6. 6
      src/core/census/grpc_filter.h
  7. 6
      src/cpp/common/auth_property_iterator.cc
  8. 17
      src/cpp/common/secure_auth_context.cc
  9. 6
      src/cpp/common/secure_auth_context.h
  10. 2
      src/cpp/util/string_ref.cc
  11. 51
      src/node/ext/server.cc
  12. 3
      src/node/ext/server.h
  13. 21
      src/node/src/server.js
  14. 2
      src/node/test/call_test.js
  15. 2
      src/node/test/end_to_end_test.js
  16. 2
      src/node/test/health_test.js
  17. 2
      src/node/test/interop_sanity_test.js
  18. 2
      src/node/test/math_client_test.js
  19. 31
      src/node/test/server_test.js
  20. 16
      src/node/test/surface_test.js
  21. 14
      src/python/README.md
  22. 2
      src/python/grpcio/grpc/_adapter/_c/types/channel.c
  23. 28
      src/python/grpcio/grpc/beta/__init__.py
  24. 148
      src/python/grpcio/grpc/beta/_connectivity_channel.py
  25. 114
      src/python/grpcio/grpc/beta/beta.py
  26. 161
      src/python/grpcio/grpc/beta/utilities.py
  27. 2
      src/python/grpcio/grpc/framework/core/_context.py
  28. 3
      src/python/grpcio/grpc/framework/core/_emission.py
  29. 2
      src/python/grpcio/grpc/framework/core/_expiration.py
  30. 66
      src/python/grpcio/grpc/framework/core/_ingestion.py
  31. 8
      src/python/grpcio/grpc/framework/core/_interfaces.py
  32. 2
      src/python/grpcio/grpc/framework/core/_operation.py
  33. 2
      src/python/grpcio/grpc/framework/core/_reception.py
  34. 14
      src/python/grpcio/grpc/framework/core/_transmission.py
  35. 30
      src/python/grpcio/grpc/framework/crust/__init__.py
  36. 204
      src/python/grpcio/grpc/framework/crust/_calls.py
  37. 545
      src/python/grpcio/grpc/framework/crust/_control.py
  38. 166
      src/python/grpcio/grpc/framework/crust/_service.py
  39. 352
      src/python/grpcio/grpc/framework/crust/implementations.py
  40. 21
      src/python/grpcio/grpc/framework/interfaces/base/base.py
  41. 2
      src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
  42. 160
      src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
  43. 30
      src/python/grpcio_test/grpc_test/beta/__init__.py
  44. 180
      src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
  45. 123
      src/python/grpcio_test/grpc_test/beta/_utilities_test.py
  46. 111
      src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
  47. 2
      src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
  48. 37
      src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
  49. 9
      src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
  50. 11
      src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
  51. 17
      src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
  52. 2
      src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
  53. 15
      test/cpp/common/auth_property_iterator_test.cc
  54. 25
      test/cpp/common/secure_auth_context_test.cc
  55. 15
      test/cpp/end2end/end2end_test.cc
  56. 4
      test/cpp/util/string_ref_test.cc
  57. 1
      tools/run_tests/build_php.sh
  58. 1
      tools/run_tests/jobset.py
  59. 2
      tools/run_tests/run_python.sh
  60. 10
      tools/run_tests/run_tests.py
  61. 10
      tools/run_tests/sources_and_headers.json
  62. 8
      vsprojects/Grpc.mak

2
.gitmodules vendored

@ -14,4 +14,4 @@
url = https://github.com/gflags/gflags.git
[submodule "third_party/googletest"]
path = third_party/googletest
url = git://github.com/google/googletest
url = https://github.com/google/googletest.git

@ -8975,16 +8975,16 @@ $(BINDIR)/$(CONFIG)/auth_property_iterator_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test
$(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_auth_property_iterator_test: $(AUTH_PROPERTY_ITERATOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
@ -10185,16 +10185,16 @@ $(BINDIR)/$(CONFIG)/secure_auth_context_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test
$(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_secure_auth_context_test: $(SECURE_AUTH_CONTEXT_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)

@ -2029,8 +2029,11 @@
"test/cpp/common/auth_property_iterator_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
@ -2581,8 +2584,11 @@
"test/cpp/common/secure_auth_context_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},

@ -38,6 +38,7 @@
#include <vector>
#include <grpc++/support/config.h>
#include <grpc++/support/string_ref.h>
struct grpc_auth_context;
struct grpc_auth_property;
@ -46,7 +47,7 @@ struct grpc_auth_property_iterator;
namespace grpc {
class SecureAuthContext;
typedef std::pair<grpc::string, grpc::string> AuthProperty;
typedef std::pair<grpc::string_ref, grpc::string_ref> AuthProperty;
class AuthPropertyIterator
: public std::iterator<std::input_iterator_tag, const AuthProperty> {
@ -73,22 +74,22 @@ class AuthPropertyIterator
};
/// Class encapsulating the Authentication Information.
///
///
/// It includes the secure identity of the peer, the type of secure transport
/// used as well as any other properties required by the authorization layer.
class AuthContext {
public:
virtual ~AuthContext() {}
/// A peer identity.
/// A peer identity.
///
/// It is, in general, comprised of one or more properties (in which case they
/// have the same name).
virtual std::vector<grpc::string> GetPeerIdentity() const = 0;
virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
virtual grpc::string GetPeerIdentityPropertyName() const = 0;
/// Returns all the property values with the given name.
virtual std::vector<grpc::string> FindPropertyValues(
virtual std::vector<grpc::string_ref> FindPropertyValues(
const grpc::string& name) const = 0;
/// Iteration over all the properties.

@ -31,8 +31,8 @@
*
*/
#ifndef GRPCXX_STRING_REF_H
#define GRPCXX_STRING_REF_H
#ifndef GRPCXX_SUPPORT_STRING_REF_H
#define GRPCXX_SUPPORT_STRING_REF_H
#include <iterator>
#include <iosfwd>
@ -44,6 +44,8 @@ namespace grpc {
// This class is a non owning reference to a string.
// It should be a strict subset of the upcoming std::string_ref. See:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
// The constexpr is dropped or replaced with const for legacy compiler
// compatibility.
class string_ref {
public:
// types
@ -115,6 +117,4 @@ std::ostream& operator<<(std::ostream& stream, const string_ref& string);
} // namespace grpc
#endif // GRPCXX_STRING_REF_H
#endif // GRPCXX_SUPPORT_STRING_REF_H

@ -31,8 +31,8 @@
*
*/
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H
#define GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H
#ifndef GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
#define GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
#include "src/core/channel/channel_stack.h"
@ -41,4 +41,4 @@
extern const grpc_channel_filter grpc_client_census_filter;
extern const grpc_channel_filter grpc_server_census_filter;
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */
#endif /* GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H */

@ -77,9 +77,9 @@ bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const {
}
const AuthProperty AuthPropertyIterator::operator*() {
return std::make_pair<grpc::string, grpc::string>(
grpc::string(property_->name),
grpc::string(property_->value, property_->value_length));
return std::pair<grpc::string_ref, grpc::string_ref>(
property_->name,
grpc::string_ref(property_->value, property_->value_length));
}
} // namespace grpc

@ -41,15 +41,16 @@ SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {}
SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); }
std::vector<grpc::string> SecureAuthContext::GetPeerIdentity() const {
std::vector<grpc::string_ref> SecureAuthContext::GetPeerIdentity() const {
if (!ctx_) {
return std::vector<grpc::string>();
return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_);
std::vector<grpc::string> identity;
std::vector<grpc::string_ref> identity;
const grpc_auth_property* property = nullptr;
while ((property = grpc_auth_property_iterator_next(&iter))) {
identity.push_back(grpc::string(property->value, property->value_length));
identity.push_back(
grpc::string_ref(property->value, property->value_length));
}
return identity;
}
@ -62,17 +63,17 @@ grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const {
return name == nullptr ? "" : name;
}
std::vector<grpc::string> SecureAuthContext::FindPropertyValues(
std::vector<grpc::string_ref> SecureAuthContext::FindPropertyValues(
const grpc::string& name) const {
if (!ctx_) {
return std::vector<grpc::string>();
return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter =
grpc_auth_context_find_properties_by_name(ctx_, name.c_str());
const grpc_auth_property* property = nullptr;
std::vector<grpc::string> values;
std::vector<grpc::string_ref> values;
while ((property = grpc_auth_property_iterator_next(&iter))) {
values.push_back(grpc::string(property->value, property->value_length));
values.push_back(grpc::string_ref(property->value, property->value_length));
}
return values;
}

@ -46,12 +46,12 @@ class SecureAuthContext GRPC_FINAL : public AuthContext {
~SecureAuthContext() GRPC_OVERRIDE;
std::vector<grpc::string> GetPeerIdentity() const GRPC_OVERRIDE;
std::vector<grpc::string_ref> GetPeerIdentity() const GRPC_OVERRIDE;
grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE;
std::vector<grpc::string> FindPropertyValues(const grpc::string& name) const
GRPC_OVERRIDE;
std::vector<grpc::string_ref> FindPropertyValues(
const grpc::string& name) const GRPC_OVERRIDE;
AuthPropertyIterator begin() const GRPC_OVERRIDE;

@ -80,7 +80,7 @@ size_t string_ref::find(string_ref s) const {
}
size_t string_ref::find(char c) const {
auto it = std::find_if(cbegin(), cend(), [c](char cc) { return cc == c; });
auto it = std::find(cbegin(), cend(), c);
return it == cend() ? npos : std::distance(cbegin(), it);
}

@ -120,7 +120,7 @@ Server::Server(grpc_server *server) : wrapped_server(server) {
Server::~Server() {
this->ShutdownServer();
grpc_completion_queue_shutdown(this->shutdown_queue);
grpc_server_destroy(wrapped_server);
grpc_server_destroy(this->wrapped_server);
grpc_completion_queue_destroy(this->shutdown_queue);
}
@ -139,8 +139,11 @@ void Server::Init(Handle<Object> exports) {
NanSetPrototypeTemplate(tpl, "start",
NanNew<FunctionTemplate>(Start)->GetFunction());
NanSetPrototypeTemplate(tpl, "shutdown",
NanNew<FunctionTemplate>(Shutdown)->GetFunction());
NanSetPrototypeTemplate(tpl, "tryShutdown",
NanNew<FunctionTemplate>(TryShutdown)->GetFunction());
NanSetPrototypeTemplate(
tpl, "forceShutdown",
NanNew<FunctionTemplate>(ForceShutdown)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
Handle<Function> ctr = tpl->GetFunction();
@ -153,14 +156,12 @@ bool Server::HasInstance(Handle<Value> val) {
}
void Server::ShutdownServer() {
if (this->wrapped_server != NULL) {
grpc_server_shutdown_and_notify(this->wrapped_server,
this->shutdown_queue,
NULL);
grpc_completion_queue_pluck(this->shutdown_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
this->wrapped_server = NULL;
}
grpc_server_shutdown_and_notify(this->wrapped_server,
this->shutdown_queue,
NULL);
grpc_server_cancel_all_calls(this->wrapped_server);
grpc_completion_queue_pluck(this->shutdown_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
NAN_METHOD(Server::New) {
@ -222,9 +223,6 @@ NAN_METHOD(Server::RequestCall) {
return NanThrowTypeError("requestCall can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
if (server->wrapped_server == NULL) {
return NanThrowError("requestCall cannot be called on a shut down Server");
}
NewCallOp *op = new NewCallOp();
unique_ptr<OpVec> ops(new OpVec());
ops->push_back(unique_ptr<Op>(op));
@ -256,10 +254,6 @@ NAN_METHOD(Server::AddHttp2Port) {
"addHttp2Port's second argument must be ServerCredentials");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
if (server->wrapped_server == NULL) {
return NanThrowError(
"addHttp2Port cannot be called on a shut down Server");
}
ServerCredentials *creds_object = ObjectWrap::Unwrap<ServerCredentials>(
args[1]->ToObject());
grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials();
@ -281,21 +275,30 @@ NAN_METHOD(Server::Start) {
return NanThrowTypeError("start can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
if (server->wrapped_server == NULL) {
return NanThrowError("start cannot be called on a shut down Server");
}
grpc_server_start(server->wrapped_server);
NanReturnUndefined();
}
NAN_METHOD(ShutdownCallback) {
NAN_METHOD(Server::TryShutdown) {
NanScope();
if (!HasInstance(args.This())) {
return NanThrowTypeError("tryShutdown can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
unique_ptr<OpVec> ops(new OpVec());
grpc_server_shutdown_and_notify(
server->wrapped_server,
CompletionQueueAsyncWorker::GetQueue(),
new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
shared_ptr<Resources>(nullptr)));
CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
NAN_METHOD(Server::Shutdown) {
NAN_METHOD(Server::ForceShutdown) {
NanScope();
if (!HasInstance(args.This())) {
return NanThrowTypeError("shutdown can only be called on a Server");
return NanThrowTypeError("forceShutdown can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
server->ShutdownServer();

@ -67,7 +67,8 @@ class Server : public ::node::ObjectWrap {
static NAN_METHOD(RequestCall);
static NAN_METHOD(AddHttp2Port);
static NAN_METHOD(Start);
static NAN_METHOD(Shutdown);
static NAN_METHOD(TryShutdown);
static NAN_METHOD(ForceShutdown);
static NanCallback *constructor;
static v8::Persistent<v8::FunctionTemplate> fun_tpl;

@ -623,11 +623,26 @@ function Server(options) {
}
server.requestCall(handleNewCall);
};
/**
* Gracefully shuts down the server. The server will stop receiving new calls,
* and any pending calls will complete. The callback will be called when all
* pending calls have completed and the server is fully shut down. This method
* is idempotent with itself and forceShutdown.
* @param {function()} callback The shutdown complete callback
*/
this.tryShutdown = function(callback) {
server.tryShutdown(callback);
};
/**
* Shuts down the server.
* Forcibly shuts down the server. The server will stop receiving new calls
* and cancel all pending calls. When it returns, the server has shut down.
* This method is idempotent with itself and tryShutdown, and it will trigger
* any outstanding tryShutdown callbacks.
*/
this.shutdown = function() {
server.shutdown();
this.forceShutdown = function() {
server.forceShutdown();
};
}

@ -61,7 +61,7 @@ describe('call', function() {
channel = new grpc.Channel('localhost:' + port, insecureCreds);
});
after(function() {
server.shutdown();
server.forceShutdown();
});
describe('constructor', function() {
it('should reject anything less than 3 arguments', function() {

@ -70,7 +70,7 @@ describe('end-to-end', function() {
channel = new grpc.Channel('localhost:' + port_num, insecureCreds);
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('should start and end a request without error', function(complete) {
var done = multiDone(complete, 2);

@ -57,7 +57,7 @@ describe('Health Checking', function() {
grpc.Credentials.createInsecure());
});
after(function() {
healthServer.shutdown();
healthServer.forceShutdown();
});
it('should say an enabled service is SERVING', function(done) {
healthClient.check({service: ''}, function(err, response) {

@ -51,7 +51,7 @@ describe('Interop tests', function() {
done();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
// This depends on not using a binary stream
it('should pass empty_unary', function(done) {

@ -59,7 +59,7 @@ describe('Math client', function() {
done();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('should handle a single request', function(done) {
var arg = {dividend: 7, divisor: 4};

@ -92,7 +92,7 @@ describe('server', function() {
server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('should start without error', function() {
assert.doesNotThrow(function() {
@ -100,4 +100,33 @@ describe('server', function() {
});
});
});
describe('shutdown', function() {
var server;
beforeEach(function() {
server = new grpc.Server();
server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
server.start();
});
afterEach(function() {
server.forceShutdown();
});
it('tryShutdown should shutdown successfully', function(done) {
server.tryShutdown(done);
});
it('forceShutdown should shutdown successfully', function() {
server.forceShutdown();
});
it('tryShutdown should be idempotent', function(done) {
server.tryShutdown(done);
server.tryShutdown(function() {});
});
it('forceShutdown should be idempotent', function() {
server.forceShutdown();
server.forceShutdown();
});
it('forceShutdown should trigger tryShutdown', function(done) {
server.tryShutdown(done);
server.forceShutdown();
});
});
});

@ -104,7 +104,7 @@ describe('Server.prototype.addProtoService', function() {
server = new grpc.Server();
});
afterEach(function() {
server.shutdown();
server.forceShutdown();
});
it('Should succeed with a single service', function() {
assert.doesNotThrow(function() {
@ -148,7 +148,7 @@ describe('Client#$waitForReady', function() {
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('should complete when called alone', function(done) {
client.$waitForReady(Infinity, function(error) {
@ -203,7 +203,7 @@ describe('Echo service', function() {
server.start();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('should echo the recieved message directly', function(done) {
client.echo({value: 'test value', value2: 3}, function(error, response) {
@ -248,7 +248,7 @@ describe('Generic client and server', function() {
grpc.Credentials.createInsecure());
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('Should respond with a capitalized string', function(done) {
client.capitalize('abc', function(err, response) {
@ -296,7 +296,7 @@ describe('Echo metadata', function() {
server.start();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('with unary call', function(done) {
var call = client.unary({}, function(err, data) {
@ -419,7 +419,7 @@ describe('Other conditions', function() {
server.start();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('channel.getTarget should be available', function() {
assert.strictEqual(typeof client.channel.getTarget(), 'string');
@ -681,7 +681,7 @@ describe('Other conditions', function() {
});
afterEach(function() {
console.log('Shutting down server');
proxy.shutdown();
proxy.forceShutdown();
});
describe('Cancellation', function() {
it('With a unary call', function(done) {
@ -847,7 +847,7 @@ describe('Cancelling surface client', function() {
server.start();
});
after(function() {
server.shutdown();
server.forceShutdown();
});
it('Should correctly cancel a unary call', function(done) {
var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {

@ -52,9 +52,19 @@ BUILDING FROM SOURCE
---------------------
- Clone this repository
- Initialize the git submodules
```
$ git submodule update --init
```
- Make the libraries
```
$ make
```
- Use build_python.sh to build the Python code and install it into a virtual environment
```
$ tools/run_tests/build_python.sh
$ CONFIG=opt tools/run_tests/build_python.sh 2.7
```
TESTING
@ -62,7 +72,7 @@ TESTING
- Use run_python.sh to run gRPC as it was installed into the virtual environment
```
$ tools/run_tests/run_python.sh
$ CONFIG=opt PYVER=2.7 tools/run_tests/run_python.sh
```
PACKAGING

@ -164,7 +164,7 @@ PyObject *pygrpc_Channel_watch_connectivity_state(
int last_observed_state;
CompletionQueue *completion_queue;
char *keywords[] = {"last_observed_state", "deadline",
"completion_queue", "tag"};
"completion_queue", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "idO!O:watch_connectivity_state", keywords,
&last_observed_state, &deadline, &pygrpc_CompletionQueue_type,

@ -0,0 +1,28 @@
# 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.

@ -0,0 +1,148 @@
# 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.
"""Affords a connectivity-state-listenable channel."""
import threading
import time
from grpc._adapter import _low
from grpc.framework.foundation import callable_util
_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
'Exception calling channel subscription callback!')
class ConnectivityChannel(object):
def __init__(self, low_channel, mapping):
self._lock = threading.Lock()
self._low_channel = low_channel
self._mapping = mapping
self._polling = False
self._connectivity = None
self._try_to_connect = False
self._callbacks_and_connectivities = []
self._delivering = False
def _deliveries(self, connectivity):
callbacks_needing_update = []
for callback_and_connectivity in self._callbacks_and_connectivities:
callback, callback_connectivity = callback_and_connectivity
if callback_connectivity is not connectivity:
callbacks_needing_update.append(callback)
callback_and_connectivity[1] = connectivity
return callbacks_needing_update
def _deliver(self, initial_connectivity, initial_callbacks):
connectivity = initial_connectivity
callbacks = initial_callbacks
while True:
for callback in callbacks:
callable_util.call_logging_exceptions(
callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE,
connectivity)
with self._lock:
callbacks = self._deliveries(self._connectivity)
if callbacks:
connectivity = self._connectivity
else:
self._delivering = False
return
def _spawn_delivery(self, connectivity, callbacks):
delivering_thread = threading.Thread(
target=self._deliver, args=(connectivity, callbacks,))
delivering_thread.start()
self._delivering = True
# TODO(issue 3064): Don't poll.
def _poll_connectivity(self, low_channel, initial_try_to_connect):
try_to_connect = initial_try_to_connect
low_connectivity = low_channel.check_connectivity_state(try_to_connect)
with self._lock:
self._connectivity = self._mapping[low_connectivity]
callbacks = tuple(
callback for callback, unused_but_known_to_be_none_connectivity
in self._callbacks_and_connectivities)
for callback_and_connectivity in self._callbacks_and_connectivities:
callback_and_connectivity[1] = self._connectivity
if callbacks:
self._spawn_delivery(self._connectivity, callbacks)
completion_queue = _low.CompletionQueue()
while True:
low_channel.watch_connectivity_state(
low_connectivity, time.time() + 0.2, completion_queue, None)
event = completion_queue.next()
with self._lock:
if not self._callbacks_and_connectivities and not self._try_to_connect:
self._polling = False
self._connectivity = None
completion_queue.shutdown()
break
try_to_connect = self._try_to_connect
self._try_to_connect = False
if event.success or try_to_connect:
low_connectivity = low_channel.check_connectivity_state(try_to_connect)
with self._lock:
self._connectivity = self._mapping[low_connectivity]
if not self._delivering:
callbacks = self._deliveries(self._connectivity)
if callbacks:
self._spawn_delivery(self._connectivity, callbacks)
def subscribe(self, callback, try_to_connect):
with self._lock:
if not self._callbacks_and_connectivities and not self._polling:
polling_thread = threading.Thread(
target=self._poll_connectivity,
args=(self._low_channel, bool(try_to_connect)))
polling_thread.start()
self._polling = True
self._callbacks_and_connectivities.append([callback, None])
elif not self._delivering and self._connectivity is not None:
self._spawn_delivery(self._connectivity, (callback,))
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append(
[callback, self._connectivity])
else:
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append([callback, None])
def unsubscribe(self, callback):
with self._lock:
for index, (subscribed_callback, unused_connectivity) in enumerate(
self._callbacks_and_connectivities):
if callback == subscribed_callback:
self._callbacks_and_connectivities.pop(index)
break
def low_channel(self):
return self._low_channel

@ -0,0 +1,114 @@
# 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.
"""Entry points into gRPC Python Beta."""
import enum
from grpc._adapter import _low
from grpc._adapter import _types
from grpc.beta import _connectivity_channel
_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
'Exception calling channel subscription callback!')
@enum.unique
class ChannelConnectivity(enum.Enum):
"""Mirrors grpc_connectivity_state in the gRPC Core.
Attributes:
IDLE: The channel is idle.
CONNECTING: The channel is connecting.
READY: The channel is ready to conduct RPCs.
TRANSIENT_FAILURE: The channel has seen a failure from which it expects to
recover.
FATAL_FAILURE: The channel has seen a failure from which it cannot recover.
"""
IDLE = (_types.ConnectivityState.IDLE, 'idle',)
CONNECTING = (_types.ConnectivityState.CONNECTING, 'connecting',)
READY = (_types.ConnectivityState.READY, 'ready',)
TRANSIENT_FAILURE = (
_types.ConnectivityState.TRANSIENT_FAILURE, 'transient failure',)
FATAL_FAILURE = (_types.ConnectivityState.FATAL_FAILURE, 'fatal failure',)
_LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
state: connectivity for state, connectivity in zip(
_types.ConnectivityState, ChannelConnectivity)
}
class Channel(object):
"""A channel to a remote host through which RPCs may be conducted.
Only the "subscribe" and "unsubscribe" methods are supported for application
use. This class' instance constructor and all other attributes are
unsupported.
"""
def __init__(self, low_channel):
self._connectivity_channel = _connectivity_channel.ConnectivityChannel(
low_channel, _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY)
def subscribe(self, callback, try_to_connect=None):
"""Subscribes to this Channel's connectivity.
Args:
callback: A callable to be invoked and passed this Channel's connectivity.
The callable will be invoked immediately upon subscription and again for
every change to this Channel's connectivity thereafter until it is
unsubscribed.
try_to_connect: A boolean indicating whether or not this Channel should
attempt to connect if it is not already connected and ready to conduct
RPCs.
"""
self._connectivity_channel.subscribe(callback, try_to_connect)
def unsubscribe(self, callback):
"""Unsubscribes a callback from this Channel's connectivity.
Args:
callback: A callable previously registered with this Channel from having
been passed to its "subscribe" method.
"""
self._connectivity_channel.unsubscribe(callback)
def create_insecure_channel(host, port):
"""Creates an insecure Channel to a remote host.
Args:
host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect.
Returns:
A Channel to the remote host through which RPCs may be conducted.
"""
return Channel(_low.Channel('%s:%d' % (host, port), ()))

@ -0,0 +1,161 @@
# 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.
"""Utilities for the gRPC Python Beta API."""
import threading
import time
from grpc.beta import beta
from grpc.framework.foundation import callable_util
from grpc.framework.foundation import future
_DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
'Exception calling connectivity future "done" callback!')
class _ChannelReadyFuture(future.Future):
def __init__(self, channel):
self._condition = threading.Condition()
self._channel = channel
self._matured = False
self._cancelled = False
self._done_callbacks = []
def _block(self, timeout):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._cancelled:
raise future.CancelledError()
elif self._matured:
return
else:
if until is None:
self._condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise future.TimeoutError()
else:
self._condition.wait(timeout=remaining)
def _update(self, connectivity):
with self._condition:
if not self._cancelled and connectivity is beta.ChannelConnectivity.READY:
self._matured = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancel(self):
with self._condition:
if not self._matured:
self._cancelled = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return False
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._cancelled and not self._matured
def done(self):
with self._condition:
return self._cancelled or self._matured
def result(self, timeout=None):
self._block(timeout)
return None
def exception(self, timeout=None):
self._block(timeout)
return None
def traceback(self, timeout=None):
self._block(timeout)
return None
def add_done_callback(self, fn):
with self._condition:
if not self._cancelled and not self._matured:
self._done_callbacks.append(fn)
return
fn(self)
def start(self):
with self._condition:
self._channel.subscribe(self._update, try_to_connect=True)
def __del__(self):
with self._condition:
if not self._cancelled and not self._matured:
self._channel.unsubscribe(self._update)
def channel_ready_future(channel):
"""Creates a future.Future that matures when a beta.Channel is ready.
Cancelling the returned future.Future does not tell the given beta.Channel to
abandon attempts it may have been making to connect; cancelling merely
deactivates the return future.Future's subscription to the given
beta.Channel's connectivity.
Args:
channel: A beta.Channel.
Returns:
A future.Future that matures when the given Channel has connectivity
beta.ChannelConnectivity.READY.
"""
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future

@ -60,7 +60,7 @@ class OperationContext(base.OperationContext):
with self._lock:
if self._termination_manager.outcome is None:
self._termination_manager.abort(outcome)
self._transmission_manager.abort(outcome)
self._transmission_manager.abort(outcome, None, None)
self._expiration_manager.terminate()
def outcome(self):

@ -82,7 +82,8 @@ class EmissionManager(_interfaces.EmissionManager):
completion_present and self._completion_seen or
allowance_present and allowance <= 0):
self._termination_manager.abort(base.Outcome.LOCAL_FAILURE)
self._transmission_manager.abort(base.Outcome.LOCAL_FAILURE)
self._transmission_manager.abort(
base.Outcome.LOCAL_FAILURE, None, None)
self._expiration_manager.terminate()
else:
self._initial_metadata_seen |= initial_metadata_present

@ -73,7 +73,7 @@ class _ExpirationManager(_interfaces.ExpirationManager):
if self._future is not None and index == self._index:
self._future = None
self._termination_manager.expire()
self._transmission_manager.abort(base.Outcome.EXPIRED)
self._transmission_manager.abort(base.Outcome.EXPIRED, None, None)
return expire
def start(self):

@ -31,6 +31,7 @@
import abc
import collections
import enum
from grpc.framework.core import _constants
from grpc.framework.core import _interfaces
@ -42,21 +43,31 @@ _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!'
_INGESTION_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!'
class _SubscriptionCreation(collections.namedtuple(
'_SubscriptionCreation', ('subscription', 'remote_error', 'abandoned'))):
class _SubscriptionCreation(
collections.namedtuple(
'_SubscriptionCreation',
('kind', 'subscription', 'code', 'message',))):
"""A sum type for the outcome of ingestion initialization.
Either subscription will be non-None, remote_error will be True, or abandoned
will be True.
Attributes:
subscription: A base.Subscription describing the customer's interest in
operation values from the other side.
remote_error: A boolean indicating that the subscription could not be
created due to an error on the remote side of the operation.
abandoned: A boolean indicating that subscription creation was abandoned.
kind: A Kind value coarsely indicating how subscription creation completed.
subscription: The created subscription. Only present if kind is
Kind.SUBSCRIPTION.
code: A code value to be sent to the other side of the operation along with
an indication that the operation is being aborted due to an error on the
remote side of the operation. Only present if kind is Kind.REMOTE_ERROR.
message: A message value to be sent to the other side of the operation
along with an indication that the operation is being aborted due to an
error on the remote side of the operation. Only present if kind is
Kind.REMOTE_ERROR.
"""
@enum.unique
class Kind(enum.Enum):
SUBSCRIPTION = 'subscription'
REMOTE_ERROR = 'remote error'
ABANDONED = 'abandoned'
class _SubscriptionCreator(object):
"""Common specification of subscription-creating behavior."""
@ -101,12 +112,15 @@ class _ServiceSubscriptionCreator(_SubscriptionCreator):
try:
subscription = self._servicer.service(
group, method, self._operation_context, self._output_operator)
except base.NoSuchMethodError:
return _SubscriptionCreation(None, True, False)
except base.NoSuchMethodError as e:
return _SubscriptionCreation(
_SubscriptionCreation.Kind.REMOTE_ERROR, None, e.code, e.message)
except abandonment.Abandoned:
return _SubscriptionCreation(None, False, True)
return _SubscriptionCreation(
_SubscriptionCreation.Kind.ABANDONED, None, None, None)
else:
return _SubscriptionCreation(subscription, False, False)
return _SubscriptionCreation(
_SubscriptionCreation.Kind.SUBSCRIPTION, subscription, None, None)
def _wrap(behavior):
@ -176,10 +190,10 @@ class _IngestionManager(_interfaces.IngestionManager):
self._pending_payloads = None
self._pending_completion = None
def _abort_and_notify(self, outcome):
def _abort_and_notify(self, outcome, code, message):
self._abort_internal_only()
self._termination_manager.abort(outcome)
self._transmission_manager.abort(outcome)
self._transmission_manager.abort(outcome, code, message)
self._expiration_manager.terminate()
def _operator_next(self):
@ -236,12 +250,12 @@ class _IngestionManager(_interfaces.IngestionManager):
else:
with self._lock:
if self._termination_manager.outcome is None:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE)
self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
return
else:
with self._lock:
if self._termination_manager.outcome is None:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE)
self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
return
def _operator_post_create(self, subscription):
@ -260,20 +274,22 @@ class _IngestionManager(_interfaces.IngestionManager):
def _create(self, subscription_creator, group, name):
outcome = callable_util.call_logging_exceptions(
subscription_creator.create, _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE,
group, name)
subscription_creator.create,
_CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE, group, name)
if outcome.return_value is None:
with self._lock:
if self._termination_manager.outcome is None:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE)
elif outcome.return_value.abandoned:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
elif outcome.return_value.kind is _SubscriptionCreation.Kind.ABANDONED:
with self._lock:
if self._termination_manager.outcome is None:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE)
elif outcome.return_value.remote_error:
self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
elif outcome.return_value.kind is _SubscriptionCreation.Kind.REMOTE_ERROR:
code = outcome.return_value.code
message = outcome.return_value.message
with self._lock:
if self._termination_manager.outcome is None:
self._abort_and_notify(base.Outcome.REMOTE_FAILURE)
self._abort_and_notify(base.Outcome.REMOTE_FAILURE, code, message)
elif outcome.return_value.subscription.kind is base.Subscription.Kind.FULL:
self._operator_post_create(outcome.return_value.subscription)
else:

@ -155,13 +155,19 @@ class TransmissionManager(object):
raise NotImplementedError()
@abc.abstractmethod
def abort(self, outcome):
def abort(self, outcome, code, message):
"""Indicates that the operation has aborted.
Args:
outcome: An interfaces.Outcome for the operation. If None, indicates that
the operation abortion should not be communicated to the other side of
the operation.
code: A code value to communicate to the other side of the operation
along with indication of operation abortion. May be None, and has no
effect if outcome is None.
message: A message value to communicate to the other side of the
operation along with indication of operation abortion. May be None, and
has no effect if outcome is None.
"""
raise NotImplementedError()

@ -79,7 +79,7 @@ class _EasyOperation(_interfaces.Operation):
with self._lock:
if self._termination_manager.outcome is None:
self._termination_manager.abort(outcome)
self._transmission_manager.abort(outcome)
self._transmission_manager.abort(outcome, None, None)
self._expiration_manager.terminate()

@ -73,7 +73,7 @@ class ReceptionManager(_interfaces.ReceptionManager):
self._aborted = True
if self._termination_manager.outcome is None:
self._termination_manager.abort(outcome)
self._transmission_manager.abort(None)
self._transmission_manager.abort(None, None, None)
self._expiration_manager.terminate()
def _sequence_failure(self, ticket):

@ -104,9 +104,13 @@ class TransmissionManager(_interfaces.TransmissionManager):
return None
else:
self._abortion_outcome = None
if self._completion is None:
code, message = None, None
else:
code, message = self._completion.code, self._completion.message
return links.Ticket(
self._operation_id, self._lowest_unused_sequence_number, None,
None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, code, message,
termination, None)
action = False
@ -277,7 +281,7 @@ class TransmissionManager(_interfaces.TransmissionManager):
self._remote_complete = True
self._local_allowance = 0
def abort(self, outcome):
def abort(self, outcome, code, message):
"""See _interfaces.TransmissionManager.abort for specification."""
if self._transmitting:
self._aborted, self._abortion_outcome = True, outcome
@ -287,8 +291,12 @@ class TransmissionManager(_interfaces.TransmissionManager):
termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION[
outcome]
if termination is not None:
if self._completion is None:
code, message = None, None
else:
code, message = self._completion.code, self._completion.message
ticket = links.Ticket(
self._operation_id, self._lowest_unused_sequence_number, None,
None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, code, message,
termination, None)
self._transmit(ticket)

@ -0,0 +1,30 @@
# 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.

@ -0,0 +1,204 @@
# 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.
"""Utility functions for invoking RPCs."""
from grpc.framework.crust import _control
from grpc.framework.interfaces.base import utilities
from grpc.framework.interfaces.face import face
_ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!'
_EMPTY_COMPLETION = utilities.completion(None, None, None)
def _invoke(end, group, method, timeout, initial_metadata, payload, complete):
rendezvous = _control.Rendezvous(None, None)
operation_context, operator = end.operate(
group, method, utilities.full_subscription(rendezvous), timeout,
initial_metadata=initial_metadata, payload=payload,
completion=_EMPTY_COMPLETION if complete else None)
rendezvous.set_operator_and_context(operator, operation_context)
outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
if outcome is not None:
rendezvous.set_outcome(outcome)
return rendezvous, operation_context, outcome
def _event_return_unary(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool):
if outcome is None:
def in_pool():
abortion = rendezvous.add_abortion_callback(abortion_callback)
if abortion is None:
try:
receiver.initial_metadata(rendezvous.initial_metadata())
receiver.response(next(rendezvous))
receiver.complete(
rendezvous.terminal_metadata(), rendezvous.code(),
rendezvous.details())
except face.AbortionError:
pass
else:
abortion_callback(abortion)
pool.submit(_control.pool_wrap(in_pool, operation_context))
return rendezvous
def _event_return_stream(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool):
if outcome is None:
def in_pool():
abortion = rendezvous.add_abortion_callback(abortion_callback)
if abortion is None:
try:
receiver.initial_metadata(rendezvous.initial_metadata())
for response in rendezvous:
receiver.response(response)
receiver.complete(
rendezvous.terminal_metadata(), rendezvous.code(),
rendezvous.details())
except face.AbortionError:
pass
else:
abortion_callback(abortion)
pool.submit(_control.pool_wrap(in_pool, operation_context))
return rendezvous
def blocking_unary_unary(
end, group, method, timeout, with_call, initial_metadata, payload):
"""Services in a blocking fashion a unary-unary servicer method."""
rendezvous, unused_operation_context, unused_outcome = _invoke(
end, group, method, timeout, initial_metadata, payload, True)
if with_call:
return next(rendezvous, rendezvous)
else:
return next(rendezvous)
def future_unary_unary(end, group, method, timeout, initial_metadata, payload):
"""Services a value-in value-out servicer method by returning a Future."""
rendezvous, unused_operation_context, unused_outcome = _invoke(
end, group, method, timeout, initial_metadata, payload, True)
return rendezvous
def inline_unary_stream(end, group, method, timeout, initial_metadata, payload):
"""Services a value-in stream-out servicer method."""
rendezvous, unused_operation_context, unused_outcome = _invoke(
end, group, method, timeout, initial_metadata, payload, True)
return rendezvous
def blocking_stream_unary(
end, group, method, timeout, with_call, initial_metadata, payload_iterator,
pool):
"""Services in a blocking fashion a stream-in value-out servicer method."""
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, None, False)
if outcome is None:
def in_pool():
for payload in payload_iterator:
rendezvous.consume(payload)
rendezvous.terminate()
pool.submit(_control.pool_wrap(in_pool, operation_context))
if with_call:
return next(rendezvous), rendezvous
else:
return next(rendezvous)
else:
if with_call:
return next(rendezvous), rendezvous
else:
return next(rendezvous)
def future_stream_unary(
end, group, method, timeout, initial_metadata, payload_iterator, pool):
"""Services a stream-in value-out servicer method by returning a Future."""
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, None, False)
if outcome is None:
def in_pool():
for payload in payload_iterator:
rendezvous.consume(payload)
rendezvous.terminate()
pool.submit(_control.pool_wrap(in_pool, operation_context))
return rendezvous
def inline_stream_stream(
end, group, method, timeout, initial_metadata, payload_iterator, pool):
"""Services a stream-in stream-out servicer method."""
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, None, False)
if outcome is None:
def in_pool():
for payload in payload_iterator:
rendezvous.consume(payload)
rendezvous.terminate()
pool.submit(_control.pool_wrap(in_pool, operation_context))
return rendezvous
def event_unary_unary(
end, group, method, timeout, initial_metadata, payload, receiver,
abortion_callback, pool):
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, payload, True)
return _event_return_unary(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
def event_unary_stream(
end, group, method, timeout, initial_metadata, payload,
receiver, abortion_callback, pool):
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, payload, True)
return _event_return_stream(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
def event_stream_unary(
end, group, method, timeout, initial_metadata, receiver, abortion_callback,
pool):
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, None, False)
return _event_return_unary(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
def event_stream_stream(
end, group, method, timeout, initial_metadata, receiver, abortion_callback,
pool):
rendezvous, operation_context, outcome = _invoke(
end, group, method, timeout, initial_metadata, None, False)
return _event_return_stream(
receiver, abortion_callback, rendezvous, operation_context, outcome, pool)

@ -0,0 +1,545 @@
# 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.
"""State and behavior for translating between sync and async control flow."""
import collections
import enum
import sys
import threading
import time
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import callable_util
from grpc.framework.foundation import future
from grpc.framework.foundation import stream
from grpc.framework.interfaces.base import base
from grpc.framework.interfaces.base import utilities
from grpc.framework.interfaces.face import face
_DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!'
_INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Crust) Internal Error! )-:'
_CANNOT_SET_INITIAL_METADATA = (
'Could not set initial metadata - has it already been set, or has a ' +
'payload already been sent?')
_CANNOT_SET_TERMINAL_METADATA = (
'Could not set terminal metadata - has it already been set, or has RPC ' +
'completion already been indicated?')
_CANNOT_SET_CODE = (
'Could not set code - has it already been set, or has RPC completion ' +
'already been indicated?')
_CANNOT_SET_DETAILS = (
'Could not set details - has it already been set, or has RPC completion ' +
'already been indicated?')
class _DummyOperator(base.Operator):
def advance(
self, initial_metadata=None, payload=None, completion=None,
allowance=None):
pass
_DUMMY_OPERATOR = _DummyOperator()
class _Awaited(
collections.namedtuple('_Awaited', ('kind', 'value',))):
@enum.unique
class Kind(enum.Enum):
NOT_YET_ARRIVED = 'not yet arrived'
ARRIVED = 'arrived'
_NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None)
_ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None)
class _Transitory(
collections.namedtuple('_Transitory', ('kind', 'value',))):
@enum.unique
class Kind(enum.Enum):
NOT_YET_SEEN = 'not yet seen'
PRESENT = 'present'
GONE = 'gone'
_NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None)
_GONE = _Transitory(_Transitory.Kind.GONE, None)
class _Termination(
collections.namedtuple(
'_Termination', ('terminated', 'abortion', 'abortion_error',))):
"""Values indicating whether and how an RPC has terminated.
Attributes:
terminated: A boolean indicating whether or not the RPC has terminated.
abortion: A face.Abortion value describing the RPC's abortion or None if the
RPC did not abort.
abortion_error: A face.AbortionError describing the RPC's abortion or None
if the RPC did not abort.
"""
_NOT_TERMINATED = _Termination(False, None, None)
_OPERATION_OUTCOME_TO_TERMINATION_CONSTRUCTOR = {
base.Outcome.COMPLETED: lambda *unused_args: _Termination(True, None, None),
base.Outcome.CANCELLED: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.CANCELLED, *args),
face.CancellationError(*args)),
base.Outcome.EXPIRED: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.EXPIRED, *args),
face.ExpirationError(*args)),
base.Outcome.LOCAL_SHUTDOWN: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.LOCAL_SHUTDOWN, *args),
face.LocalShutdownError(*args)),
base.Outcome.REMOTE_SHUTDOWN: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.REMOTE_SHUTDOWN, *args),
face.RemoteShutdownError(*args)),
base.Outcome.RECEPTION_FAILURE: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args),
face.NetworkError(*args)),
base.Outcome.TRANSMISSION_FAILURE: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args),
face.NetworkError(*args)),
base.Outcome.LOCAL_FAILURE: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.LOCAL_FAILURE, *args),
face.LocalError(*args)),
base.Outcome.REMOTE_FAILURE: lambda *args: _Termination(
True, face.Abortion(face.Abortion.Kind.REMOTE_FAILURE, *args),
face.RemoteError(*args)),
}
def _wait_once_until(condition, until):
if until is None:
condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise future.TimeoutError()
else:
condition.wait(timeout=remaining)
def _done_callback_as_operation_termination_callback(
done_callback, rendezvous):
def operation_termination_callback(operation_outcome):
rendezvous.set_outcome(operation_outcome)
done_callback(rendezvous)
return operation_termination_callback
def _abortion_callback_as_operation_termination_callback(
rpc_abortion_callback, rendezvous_set_outcome):
def operation_termination_callback(operation_outcome):
termination = rendezvous_set_outcome(operation_outcome)
if termination.abortion is not None:
rpc_abortion_callback(termination.abortion)
return operation_termination_callback
class Rendezvous(base.Operator, future.Future, stream.Consumer, face.Call):
"""A rendez-vous for the threads of an operation.
Instances of this object present iterator and stream.Consumer interfaces for
interacting with application code and present a base.Operator interface and
maintain a base.Operator internally for interacting with base interface code.
"""
def __init__(self, operator, operation_context):
self._condition = threading.Condition()
self._operator = operator
self._operation_context = operation_context
self._up_initial_metadata = _NOT_YET_ARRIVED
self._up_payload = None
self._up_allowance = 1
self._up_completion = _NOT_YET_ARRIVED
self._down_initial_metadata = _NOT_YET_SEEN
self._down_payload = None
self._down_allowance = 1
self._down_terminal_metadata = _NOT_YET_SEEN
self._down_code = _NOT_YET_SEEN
self._down_details = _NOT_YET_SEEN
self._termination = _NOT_TERMINATED
# The semantics of future.Future.cancel and future.Future.cancelled are
# slightly wonky, so they have to be tracked separately from the rest of the
# result of the RPC. This field tracks whether cancellation was requested
# prior to termination of the RPC
self._cancelled = False
def set_operator_and_context(self, operator, operation_context):
with self._condition:
self._operator = operator
self._operation_context = operation_context
def _down_completion(self):
if self._down_terminal_metadata.kind is _Transitory.Kind.NOT_YET_SEEN:
terminal_metadata = None
self._down_terminal_metadata = _GONE
elif self._down_terminal_metadata.kind is _Transitory.Kind.PRESENT:
terminal_metadata = self._down_terminal_metadata.value
self._down_terminal_metadata = _GONE
else:
terminal_metadata = None
if self._down_code.kind is _Transitory.Kind.NOT_YET_SEEN:
code = None
self._down_code = _GONE
elif self._down_code.kind is _Transitory.Kind.PRESENT:
code = self._down_code.value
self._down_code = _GONE
else:
code = None
if self._down_details.kind is _Transitory.Kind.NOT_YET_SEEN:
details = None
self._down_details = _GONE
elif self._down_details.kind is _Transitory.Kind.PRESENT:
details = self._down_details.value
self._down_details = _GONE
else:
details = None
return utilities.completion(terminal_metadata, code, details)
def _set_outcome(self, outcome):
if not self._termination.terminated:
self._operator = _DUMMY_OPERATOR
self._operation_context = None
self._down_initial_metadata = _GONE
self._down_payload = None
self._down_terminal_metadata = _GONE
self._down_code = _GONE
self._down_details = _GONE
if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
initial_metadata = None
else:
initial_metadata = self._up_initial_metadata.value
if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED:
terminal_metadata, code, details = None, None, None
else:
terminal_metadata = self._up_completion.value.terminal_metadata
code = self._up_completion.value.code
details = self._up_completion.value.message
self._termination = _OPERATION_OUTCOME_TO_TERMINATION_CONSTRUCTOR[
outcome](initial_metadata, terminal_metadata, code, details)
self._condition.notify_all()
return self._termination
def advance(
self, initial_metadata=None, payload=None, completion=None,
allowance=None):
with self._condition:
if initial_metadata is not None:
self._up_initial_metadata = _Awaited(
_Awaited.Kind.ARRIVED, initial_metadata)
if payload is not None:
if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
self._up_initial_metadata = _ARRIVED_AND_NONE
self._up_payload = payload
self._up_allowance -= 1
if completion is not None:
if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
self._up_initial_metadata = _ARRIVED_AND_NONE
self._up_completion = _Awaited(
_Awaited.Kind.ARRIVED, completion)
if allowance is not None:
if self._down_payload is not None:
self._operator.advance(payload=self._down_payload)
self._down_payload = None
self._down_allowance += allowance - 1
else:
self._down_allowance += allowance
self._condition.notify_all()
def cancel(self):
with self._condition:
if self._operation_context is not None:
self._operation_context.cancel()
self._cancelled = True
return False
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._termination.terminated
def done(self):
with self._condition:
return self._termination.terminated
def result(self, timeout=None):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._termination.terminated:
if self._termination.abortion is None:
return self._up_payload
elif self._termination.abortion.kind is face.Abortion.Kind.CANCELLED:
raise future.CancelledError()
else:
raise self._termination.abortion_error # pylint: disable=raising-bad-type
else:
_wait_once_until(self._condition, until)
def exception(self, timeout=None):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._termination.terminated:
if self._termination.abortion is None:
return None
else:
return self._termination.abortion_error
else:
_wait_once_until(self._condition, until)
def traceback(self, timeout=None):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._termination.terminated:
if self._termination.abortion_error is None:
return None
else:
abortion_error = self._termination.abortion_error
break
else:
_wait_once_until(self._condition, until)
try:
raise abortion_error
except face.AbortionError:
return sys.exc_info()[2]
def add_done_callback(self, fn):
with self._condition:
if self._operation_context is not None:
outcome = self._operation_context.add_termination_callback(
_done_callback_as_operation_termination_callback(fn, self))
if outcome is None:
return
else:
self._set_outcome(outcome)
fn(self)
def consume(self, value):
with self._condition:
while True:
if self._termination.terminated:
return
elif 0 < self._down_allowance:
self._operator.advance(payload=value)
self._down_allowance -= 1
return
else:
self._condition.wait()
def terminate(self):
with self._condition:
if self._termination.terminated:
return
elif self._down_code.kind is _Transitory.Kind.GONE:
# Conform to specified idempotence of terminate by ignoring extra calls.
return
else:
completion = self._down_completion()
self._operator.advance(completion=completion)
def consume_and_terminate(self, value):
with self._condition:
while True:
if self._termination.terminated:
return
elif 0 < self._down_allowance:
completion = self._down_completion()
self._operator.advance(payload=value, completion=completion)
return
else:
self._condition.wait()
def __iter__(self):
return self
def next(self):
with self._condition:
while True:
if self._termination.abortion_error is not None:
raise self._termination.abortion_error
elif self._up_payload is not None:
payload = self._up_payload
self._up_payload = None
if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED:
self._operator.advance(allowance=1)
return payload
elif self._up_completion.kind is _Awaited.Kind.ARRIVED:
raise StopIteration()
else:
self._condition.wait()
def is_active(self):
with self._condition:
return not self._termination.terminated
def time_remaining(self):
if self._operation_context is None:
return 0
else:
return self._operation_context.time_remaining()
def add_abortion_callback(self, abortion_callback):
with self._condition:
if self._operation_context is None:
return self._termination.abortion
else:
outcome = self._operation_context.add_termination_callback(
_abortion_callback_as_operation_termination_callback(
abortion_callback, self.set_outcome))
if outcome is not None:
return self._set_outcome(outcome).abortion
else:
return self._termination.abortion
def initial_metadata(self):
with self._condition:
while True:
if self._up_initial_metadata.kind is _Awaited.Kind.ARRIVED:
return self._up_initial_metadata.value
elif self._termination.terminated:
return None
else:
self._condition.wait()
def terminal_metadata(self):
with self._condition:
while True:
if self._up_completion.kind is _Awaited.Kind.ARRIVED:
return self._up_completion.value.terminal_metadata
elif self._termination.terminated:
return None
else:
self._condition.wait()
def code(self):
with self._condition:
while True:
if self._up_completion.kind is _Awaited.Kind.ARRIVED:
return self._up_completion.value.code
elif self._termination.terminated:
return None
else:
self._condition.wait()
def details(self):
with self._condition:
while True:
if self._up_completion.kind is _Awaited.Kind.ARRIVED:
return self._up_completion.value.message
elif self._termination.terminated:
return None
else:
self._condition.wait()
def set_initial_metadata(self, initial_metadata):
with self._condition:
if (self._down_initial_metadata.kind is not
_Transitory.Kind.NOT_YET_SEEN):
raise ValueError(_CANNOT_SET_INITIAL_METADATA)
else:
self._down_initial_metadata = _GONE
self._operator.advance(initial_metadata=initial_metadata)
def set_terminal_metadata(self, terminal_metadata):
with self._condition:
if (self._down_terminal_metadata.kind is not
_Transitory.Kind.NOT_YET_SEEN):
raise ValueError(_CANNOT_SET_TERMINAL_METADATA)
else:
self._down_terminal_metadata = _Transitory(
_Transitory.Kind.PRESENT, terminal_metadata)
def set_code(self, code):
with self._condition:
if self._down_code.kind is not _Transitory.Kind.NOT_YET_SEEN:
raise ValueError(_CANNOT_SET_CODE)
else:
self._down_code = _Transitory(_Transitory.Kind.PRESENT, code)
def set_details(self, details):
with self._condition:
if self._down_details.kind is not _Transitory.Kind.NOT_YET_SEEN:
raise ValueError(_CANNOT_SET_DETAILS)
else:
self._down_details = _Transitory(_Transitory.Kind.PRESENT, details)
def set_outcome(self, outcome):
with self._condition:
return self._set_outcome(outcome)
def pool_wrap(behavior, operation_context):
"""Wraps an operation-related behavior so that it may be called in a pool.
Args:
behavior: A callable related to carrying out an operation.
operation_context: A base_interfaces.OperationContext for the operation.
Returns:
A callable that when called carries out the behavior of the given callable
and handles whatever exceptions it raises appropriately.
"""
def translation(*args):
try:
behavior(*args)
except (
abandonment.Abandoned,
face.CancellationError,
face.ExpirationError,
face.LocalShutdownError,
face.RemoteShutdownError,
face.NetworkError,
face.RemoteError,
) as e:
if operation_context.outcome() is None:
operation_context.fail(e)
except Exception as e:
operation_context.fail(e)
return callable_util.with_exceptions_logged(
translation, _INTERNAL_ERROR_LOG_MESSAGE)

@ -0,0 +1,166 @@
# 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.
"""Behaviors for servicing RPCs."""
from grpc.framework.crust import _control
from grpc.framework.foundation import abandonment
from grpc.framework.interfaces.base import utilities
from grpc.framework.interfaces.face import face
class _ServicerContext(face.ServicerContext):
def __init__(self, rendezvous):
self._rendezvous = rendezvous
def is_active(self):
return self._rendezvous.is_active()
def time_remaining(self):
return self._rendezvous.time_remaining()
def add_abortion_callback(self, abortion_callback):
return self._rendezvous.add_abortion_callback(abortion_callback)
def cancel(self):
self._rendezvous.cancel()
def invocation_metadata(self):
return self._rendezvous.initial_metadata()
def initial_metadata(self, initial_metadata):
self._rendezvous.set_initial_metadata(initial_metadata)
def terminal_metadata(self, terminal_metadata):
self._rendezvous.set_terminal_metadata(terminal_metadata)
def code(self, code):
self._rendezvous.set_code(code)
def details(self, details):
self._rendezvous.set_details(details)
def _adaptation(pool, in_pool):
def adaptation(operator, operation_context):
rendezvous = _control.Rendezvous(operator, operation_context)
outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
if outcome is None:
pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous)
return utilities.full_subscription(rendezvous)
else:
raise abandonment.Abandoned()
return adaptation
def adapt_inline_unary_unary(method, pool):
def in_pool(rendezvous):
request = next(rendezvous)
response = method(request, _ServicerContext(rendezvous))
rendezvous.consume_and_terminate(response)
return _adaptation(pool, in_pool)
def adapt_inline_unary_stream(method, pool):
def in_pool(rendezvous):
request = next(rendezvous)
response_iterator = method(request, _ServicerContext(rendezvous))
for response in response_iterator:
rendezvous.consume(response)
rendezvous.terminate()
return _adaptation(pool, in_pool)
def adapt_inline_stream_unary(method, pool):
def in_pool(rendezvous):
response = method(rendezvous, _ServicerContext(rendezvous))
rendezvous.consume_and_terminate(response)
return _adaptation(pool, in_pool)
def adapt_inline_stream_stream(method, pool):
def in_pool(rendezvous):
response_iterator = method(rendezvous, _ServicerContext(rendezvous))
for response in response_iterator:
rendezvous.consume(response)
rendezvous.terminate()
return _adaptation(pool, in_pool)
def adapt_event_unary_unary(method, pool):
def in_pool(rendezvous):
request = next(rendezvous)
method(
request, rendezvous.consume_and_terminate, _ServicerContext(rendezvous))
return _adaptation(pool, in_pool)
def adapt_event_unary_stream(method, pool):
def in_pool(rendezvous):
request = next(rendezvous)
method(request, rendezvous, _ServicerContext(rendezvous))
return _adaptation(pool, in_pool)
def adapt_event_stream_unary(method, pool):
def in_pool(rendezvous):
request_consumer = method(
rendezvous.consume_and_terminate, _ServicerContext(rendezvous))
for request in rendezvous:
request_consumer.consume(request)
request_consumer.terminate()
return _adaptation(pool, in_pool)
def adapt_event_stream_stream(method, pool):
def in_pool(rendezvous):
request_consumer = method(rendezvous, _ServicerContext(rendezvous))
for request in rendezvous:
request_consumer.consume(request)
request_consumer.terminate()
return _adaptation(pool, in_pool)
def adapt_multi_method(multi_method, pool):
def adaptation(group, method, operator, operation_context):
rendezvous = _control.Rendezvous(operator, operation_context)
outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
if outcome is None:
def in_pool():
request_consumer = multi_method(
group, method, rendezvous, _ServicerContext(rendezvous))
for request in rendezvous:
request_consumer.consume(request)
request_consumer.terminate()
pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous)
return utilities.full_subscription(rendezvous)
else:
raise abandonment.Abandoned()
return adaptation

@ -0,0 +1,352 @@
# 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.
"""Entry points into the Crust layer of RPC Framework."""
from grpc.framework.common import cardinality
from grpc.framework.common import style
from grpc.framework.crust import _calls
from grpc.framework.crust import _service
from grpc.framework.interfaces.base import base
from grpc.framework.interfaces.face import face
class _BaseServicer(base.Servicer):
def __init__(self, adapted_methods, adapted_multi_method):
self._adapted_methods = adapted_methods
self._adapted_multi_method = adapted_multi_method
def service(self, group, method, context, output_operator):
adapted_method = self._adapted_methods.get((group, method), None)
if adapted_method is not None:
return adapted_method(output_operator, context)
elif self._adapted_multi_method is not None:
try:
return self._adapted_multi_method.service(
group, method, output_operator, context)
except face.NoSuchMethodError:
raise base.NoSuchMethodError()
else:
raise base.NoSuchMethodError()
class _UnaryUnaryMultiCallable(face.UnaryUnaryMultiCallable):
def __init__(self, end, group, method, pool):
self._end = end
self._group = group
self._method = method
self._pool = pool
def __call__(
self, request, timeout, metadata=None, with_call=False):
return _calls.blocking_unary_unary(
self._end, self._group, self._method, timeout, with_call,
metadata, request)
def future(self, request, timeout, metadata=None):
return _calls.future_unary_unary(
self._end, self._group, self._method, timeout, metadata,
request)
def event(
self, request, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_unary_unary(
self._end, self._group, self._method, timeout, metadata,
request, receiver, abortion_callback, self._pool)
class _UnaryStreamMultiCallable(face.UnaryStreamMultiCallable):
def __init__(self, end, group, method, pool):
self._end = end
self._group = group
self._method = method
self._pool = pool
def __call__(self, request, timeout, metadata=None):
return _calls.inline_unary_stream(
self._end, self._group, self._method, timeout, metadata,
request)
def event(
self, request, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_unary_stream(
self._end, self._group, self._method, timeout, metadata,
request, receiver, abortion_callback, self._pool)
class _StreamUnaryMultiCallable(face.StreamUnaryMultiCallable):
def __init__(self, end, group, method, pool):
self._end = end
self._group = group
self._method = method
self._pool = pool
def __call__(
self, request_iterator, timeout, metadata=None,
with_call=False):
return _calls.blocking_stream_unary(
self._end, self._group, self._method, timeout, with_call,
metadata, request_iterator, self._pool)
def future(self, request_iterator, timeout, metadata=None):
return _calls.future_stream_unary(
self._end, self._group, self._method, timeout, metadata,
request_iterator, self._pool)
def event(
self, receiver, abortion_callback, timeout, metadata=None):
return _calls.event_stream_unary(
self._end, self._group, self._method, timeout, metadata,
receiver, abortion_callback, self._pool)
class _StreamStreamMultiCallable(face.StreamStreamMultiCallable):
def __init__(self, end, group, method, pool):
self._end = end
self._group = group
self._method = method
self._pool = pool
def __call__(self, request_iterator, timeout, metadata=None):
return _calls.inline_stream_stream(
self._end, self._group, self._method, timeout, metadata,
request_iterator, self._pool)
def event(
self, receiver, abortion_callback, timeout, metadata=None):
return _calls.event_stream_stream(
self._end, self._group, self._method, timeout, metadata,
receiver, abortion_callback, self._pool)
class _GenericStub(face.GenericStub):
"""An face.GenericStub implementation."""
def __init__(self, end, pool):
self._end = end
self._pool = pool
def blocking_unary_unary(
self, group, method, request, timeout, metadata=None,
with_call=None):
return _calls.blocking_unary_unary(
self._end, group, method, timeout, with_call, metadata,
request)
def future_unary_unary(
self, group, method, request, timeout, metadata=None):
return _calls.future_unary_unary(
self._end, group, method, timeout, metadata, request)
def inline_unary_stream(
self, group, method, request, timeout, metadata=None):
return _calls.inline_unary_stream(
self._end, group, method, timeout, metadata, request)
def blocking_stream_unary(
self, group, method, request_iterator, timeout, metadata=None,
with_call=None):
return _calls.blocking_stream_unary(
self._end, group, method, timeout, with_call, metadata,
request_iterator, self._pool)
def future_stream_unary(
self, group, method, request_iterator, timeout, metadata=None):
return _calls.future_stream_unary(
self._end, group, method, timeout, metadata,
request_iterator, self._pool)
def inline_stream_stream(
self, group, method, request_iterator, timeout, metadata=None):
return _calls.inline_stream_stream(
self._end, group, method, timeout, metadata,
request_iterator, self._pool)
def event_unary_unary(
self, group, method, request, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_unary_unary(
self._end, group, method, timeout, metadata, request,
receiver, abortion_callback, self._pool)
def event_unary_stream(
self, group, method, request, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_unary_stream(
self._end, group, method, timeout, metadata, request,
receiver, abortion_callback, self._pool)
def event_stream_unary(
self, group, method, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_stream_unary(
self._end, group, method, timeout, metadata, receiver,
abortion_callback, self._pool)
def event_stream_stream(
self, group, method, receiver, abortion_callback, timeout,
metadata=None):
return _calls.event_stream_stream(
self._end, group, method, timeout, metadata, receiver,
abortion_callback, self._pool)
def unary_unary(self, group, method):
return _UnaryUnaryMultiCallable(self._end, group, method, self._pool)
def unary_stream(self, group, method):
return _UnaryStreamMultiCallable(self._end, group, method, self._pool)
def stream_unary(self, group, method):
return _StreamUnaryMultiCallable(self._end, group, method, self._pool)
def stream_stream(self, group, method):
return _StreamStreamMultiCallable(self._end, group, method, self._pool)
class _DynamicStub(face.DynamicStub):
"""An face.DynamicStub implementation."""
def __init__(self, end, group, cardinalities, pool):
self._end = end
self._group = group
self._cardinalities = cardinalities
self._pool = pool
def __getattr__(self, attr):
method_cardinality = self._cardinalities.get(attr)
if method_cardinality is cardinality.Cardinality.UNARY_UNARY:
return _UnaryUnaryMultiCallable(self._end, self._group, attr, self._pool)
elif method_cardinality is cardinality.Cardinality.UNARY_STREAM:
return _UnaryStreamMultiCallable(self._end, self._group, attr, self._pool)
elif method_cardinality is cardinality.Cardinality.STREAM_UNARY:
return _StreamUnaryMultiCallable(self._end, self._group, attr, self._pool)
elif method_cardinality is cardinality.Cardinality.STREAM_STREAM:
return _StreamStreamMultiCallable(
self._end, self._group, attr, self._pool)
else:
raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr)
def _adapt_method_implementations(method_implementations, pool):
adapted_implementations = {}
for name, method_implementation in method_implementations.iteritems():
if method_implementation.style is style.Service.INLINE:
if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
adapted_implementations[name] = _service.adapt_inline_unary_unary(
method_implementation.unary_unary_inline, pool)
elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
adapted_implementations[name] = _service.adapt_inline_unary_stream(
method_implementation.unary_stream_inline, pool)
elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
adapted_implementations[name] = _service.adapt_inline_stream_unary(
method_implementation.stream_unary_inline, pool)
elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
adapted_implementations[name] = _service.adapt_inline_stream_stream(
method_implementation.stream_stream_inline, pool)
elif method_implementation.style is style.Service.EVENT:
if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
adapted_implementations[name] = _service.adapt_event_unary_unary(
method_implementation.unary_unary_event, pool)
elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
adapted_implementations[name] = _service.adapt_event_unary_stream(
method_implementation.unary_stream_event, pool)
elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
adapted_implementations[name] = _service.adapt_event_stream_unary(
method_implementation.stream_unary_event, pool)
elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
adapted_implementations[name] = _service.adapt_event_stream_stream(
method_implementation.stream_stream_event, pool)
return adapted_implementations
def servicer(method_implementations, multi_method_implementation, pool):
"""Creates a base.Servicer.
It is guaranteed that any passed face.MultiMethodImplementation will
only be called to service an RPC if there is no
face.MethodImplementation for the RPC method in the passed
method_implementations dictionary.
Args:
method_implementations: A dictionary from RPC method name to
face.MethodImplementation object to be used to service the named
RPC method.
multi_method_implementation: An face.MultiMethodImplementation to be
used to service any RPCs not serviced by the
face.MethodImplementations given in the method_implementations
dictionary, or None.
pool: A thread pool.
Returns:
A base.Servicer that services RPCs via the given implementations.
"""
adapted_implementations = _adapt_method_implementations(
method_implementations, pool)
adapted_multi_method_implementation = _service.adapt_multi_method(
multi_method_implementation, pool)
return _BaseServicer(
adapted_implementations, adapted_multi_method_implementation)
def generic_stub(end, pool):
"""Creates an face.GenericStub.
Args:
end: A base.End.
pool: A futures.ThreadPoolExecutor.
Returns:
A face.GenericStub that performs RPCs via the given base.End.
"""
return _GenericStub(end, pool)
def dynamic_stub(end, group, cardinalities, pool):
"""Creates an face.DynamicStub.
Args:
end: A base.End.
group: The group identifier for all RPCs to be made with the created
face.DynamicStub.
cardinalities: A dict from method identifier to cardinality.Cardinality
value identifying the cardinality of every RPC method to be supported by
the created face.DynamicStub.
pool: A futures.ThreadPoolExecutor.
Returns:
A face.DynamicStub that performs RPCs via the given base.End.
"""
return _DynamicStub(end, group, cardinalities, pool)

@ -47,7 +47,26 @@ from grpc.framework.foundation import abandonment # pylint: disable=unused-impo
class NoSuchMethodError(Exception):
"""Indicates that an unrecognized operation has been called."""
"""Indicates that an unrecognized operation has been called.
Attributes:
code: A code value to communicate to the other side of the operation along
with indication of operation termination. May be None.
details: A details value to communicate to the other side of the operation
along with indication of operation termination. May be None.
"""
def __init__(self, code, details):
"""Constructor.
Args:
code: A code value to communicate to the other side of the operation
along with indication of operation termination. May be None.
details: A details value to communicate to the other side of the
operation along with indication of operation termination. May be None.
"""
self.code = code
self.details = details
@enum.unique

@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tests the RPC Framework Core's implementation of the Base interface."""
"""Tests Base interface compliance of the core-over-gRPC-links stack."""
import collections
import logging

@ -0,0 +1,160 @@
# 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.
"""Tests Face compliance of the crust-over-core-over-gRPC-links stack."""
import collections
import unittest
from grpc._adapter import _intermediary_low
from grpc._links import invocation
from grpc._links import service
from grpc.framework.core import implementations as core_implementations
from grpc.framework.crust import implementations as crust_implementations
from grpc.framework.foundation import logging_pool
from grpc.framework.interfaces.links import utilities
from grpc_test import test_common
from grpc_test.framework.common import test_constants
from grpc_test.framework.interfaces.face import test_cases
from grpc_test.framework.interfaces.face import test_interfaces
from grpc_test.framework.interfaces.links import test_utilities
class _SerializationBehaviors(
collections.namedtuple(
'_SerializationBehaviors',
('request_serializers', 'request_deserializers', 'response_serializers',
'response_deserializers',))):
pass
def _serialization_behaviors_from_test_methods(test_methods):
request_serializers = {}
request_deserializers = {}
response_serializers = {}
response_deserializers = {}
for (group, method), test_method in test_methods.iteritems():
request_serializers[group, method] = test_method.serialize_request
request_deserializers[group, method] = test_method.deserialize_request
response_serializers[group, method] = test_method.serialize_response
response_deserializers[group, method] = test_method.deserialize_response
return _SerializationBehaviors(
request_serializers, request_deserializers, response_serializers,
response_deserializers)
class _Implementation(test_interfaces.Implementation):
def instantiate(
self, methods, method_implementations, multi_method_implementation):
pool = logging_pool.pool(test_constants.POOL_SIZE)
servicer = crust_implementations.servicer(
method_implementations, multi_method_implementation, pool)
serialization_behaviors = _serialization_behaviors_from_test_methods(
methods)
invocation_end_link = core_implementations.invocation_end_link()
service_end_link = core_implementations.service_end_link(
servicer, test_constants.DEFAULT_TIMEOUT,
test_constants.MAXIMUM_TIMEOUT)
service_grpc_link = service.service_link(
serialization_behaviors.request_deserializers,
serialization_behaviors.response_serializers)
port = service_grpc_link.add_port(0, None)
channel = _intermediary_low.Channel('localhost:%d' % port, None)
invocation_grpc_link = invocation.invocation_link(
channel, b'localhost',
serialization_behaviors.request_serializers,
serialization_behaviors.response_deserializers)
invocation_end_link.join_link(invocation_grpc_link)
invocation_grpc_link.join_link(invocation_end_link)
service_grpc_link.join_link(service_end_link)
service_end_link.join_link(service_grpc_link)
service_end_link.start()
invocation_end_link.start()
invocation_grpc_link.start()
service_grpc_link.start()
generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
# TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
group = next(iter(methods))[0]
# TODO(nathaniel): Add a "cardinalities_by_group" attribute to
# _digest.TestServiceDigest.
cardinalities = {
method: method_object.cardinality()
for (group, method), method_object in methods.iteritems()}
dynamic_stub = crust_implementations.dynamic_stub(
invocation_end_link, group, cardinalities, pool)
return generic_stub, {group: dynamic_stub}, (
invocation_end_link, invocation_grpc_link, service_grpc_link,
service_end_link, pool)
def destantiate(self, memo):
(invocation_end_link, invocation_grpc_link, service_grpc_link,
service_end_link, pool) = memo
invocation_end_link.stop(0).wait()
invocation_grpc_link.stop()
service_grpc_link.stop_gracefully()
service_end_link.stop(0).wait()
invocation_end_link.join_link(utilities.NULL_LINK)
invocation_grpc_link.join_link(utilities.NULL_LINK)
service_grpc_link.join_link(utilities.NULL_LINK)
service_end_link.join_link(utilities.NULL_LINK)
pool.shutdown(wait=True)
def invocation_metadata(self):
return test_common.INVOCATION_INITIAL_METADATA
def initial_metadata(self):
return test_common.SERVICE_INITIAL_METADATA
def terminal_metadata(self):
return test_common.SERVICE_TERMINAL_METADATA
def code(self):
return _intermediary_low.Code.OK
def details(self):
return test_common.DETAILS
def metadata_transmitted(self, original_metadata, transmitted_metadata):
return original_metadata is None or grpc_test_common.metadata_transmitted(
original_metadata, transmitted_metadata)
def load_tests(loader, tests, pattern):
return unittest.TestSuite(
tests=tuple(
loader.loadTestsFromTestCase(test_case_class)
for test_case_class in test_cases.test_cases(_Implementation())))
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -0,0 +1,30 @@
# 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.

@ -0,0 +1,180 @@
# 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.
"""Tests of grpc.beta._connectivity_channel."""
import threading
import time
import unittest
from grpc._adapter import _low
from grpc._adapter import _types
from grpc.beta import _connectivity_channel
from grpc_test.framework.common import test_constants
_MAPPING_FUNCTION = lambda integer: integer * 200 + 17
_MAPPING = {
state: _MAPPING_FUNCTION(state) for state in _types.ConnectivityState}
_IDLE, _CONNECTING, _READY, _TRANSIENT_FAILURE, _FATAL_FAILURE = map(
_MAPPING_FUNCTION, _types.ConnectivityState)
def _drive_completion_queue(completion_queue):
while True:
event = completion_queue.next(time.time() + 24 * 60 * 60)
if event.type == _types.EventType.QUEUE_SHUTDOWN:
break
class _Callback(object):
def __init__(self):
self._condition = threading.Condition()
self._connectivities = []
def update(self, connectivity):
with self._condition:
self._connectivities.append(connectivity)
self._condition.notify()
def connectivities(self):
with self._condition:
return tuple(self._connectivities)
def block_until_connectivities_satisfy(self, predicate):
with self._condition:
while True:
connectivities = tuple(self._connectivities)
if predicate(connectivities):
return connectivities
else:
self._condition.wait()
class ChannelConnectivityTest(unittest.TestCase):
def test_lonely_channel_connectivity(self):
low_channel = _low.Channel('localhost:12345', ())
callback = _Callback()
connectivity_channel = _connectivity_channel.ConnectivityChannel(
low_channel, _MAPPING)
connectivity_channel.subscribe(callback.update, try_to_connect=False)
first_connectivities = callback.block_until_connectivities_satisfy(bool)
connectivity_channel.subscribe(callback.update, try_to_connect=True)
second_connectivities = callback.block_until_connectivities_satisfy(
lambda connectivities: 2 <= len(connectivities))
# Wait for a connection that will never happen.
time.sleep(test_constants.SHORT_TIMEOUT)
third_connectivities = callback.connectivities()
connectivity_channel.unsubscribe(callback.update)
fourth_connectivities = callback.connectivities()
connectivity_channel.unsubscribe(callback.update)
fifth_connectivities = callback.connectivities()
self.assertSequenceEqual((_IDLE,), first_connectivities)
self.assertNotIn(_READY, second_connectivities)
self.assertNotIn(_READY, third_connectivities)
self.assertNotIn(_READY, fourth_connectivities)
self.assertNotIn(_READY, fifth_connectivities)
def test_immediately_connectable_channel_connectivity(self):
server_completion_queue = _low.CompletionQueue()
server = _low.Server(server_completion_queue, [])
port = server.add_http2_port('[::]:0')
server.start()
server_completion_queue_thread = threading.Thread(
target=_drive_completion_queue, args=(server_completion_queue,))
server_completion_queue_thread.start()
low_channel = _low.Channel('localhost:%d' % port, ())
first_callback = _Callback()
second_callback = _Callback()
connectivity_channel = _connectivity_channel.ConnectivityChannel(
low_channel, _MAPPING)
connectivity_channel.subscribe(first_callback.update, try_to_connect=False)
first_connectivities = first_callback.block_until_connectivities_satisfy(
bool)
# Wait for a connection that will never happen because try_to_connect=True
# has not yet been passed.
time.sleep(test_constants.SHORT_TIMEOUT)
second_connectivities = first_callback.connectivities()
connectivity_channel.subscribe(second_callback.update, try_to_connect=True)
third_connectivities = first_callback.block_until_connectivities_satisfy(
lambda connectivities: 2 <= len(connectivities))
fourth_connectivities = second_callback.block_until_connectivities_satisfy(
bool)
# Wait for a connection that will happen (or may already have happened).
first_callback.block_until_connectivities_satisfy(
lambda connectivities: _READY in connectivities)
second_callback.block_until_connectivities_satisfy(
lambda connectivities: _READY in connectivities)
connectivity_channel.unsubscribe(first_callback.update)
connectivity_channel.unsubscribe(second_callback.update)
server.shutdown()
server_completion_queue.shutdown()
server_completion_queue_thread.join()
self.assertSequenceEqual((_IDLE,), first_connectivities)
self.assertSequenceEqual((_IDLE,), second_connectivities)
self.assertNotIn(_TRANSIENT_FAILURE, third_connectivities)
self.assertNotIn(_FATAL_FAILURE, third_connectivities)
self.assertNotIn(_TRANSIENT_FAILURE, fourth_connectivities)
self.assertNotIn(_FATAL_FAILURE, fourth_connectivities)
def test_reachable_then_unreachable_channel_connectivity(self):
server_completion_queue = _low.CompletionQueue()
server = _low.Server(server_completion_queue, [])
port = server.add_http2_port('[::]:0')
server.start()
server_completion_queue_thread = threading.Thread(
target=_drive_completion_queue, args=(server_completion_queue,))
server_completion_queue_thread.start()
low_channel = _low.Channel('localhost:%d' % port, ())
callback = _Callback()
connectivity_channel = _connectivity_channel.ConnectivityChannel(
low_channel, _MAPPING)
connectivity_channel.subscribe(callback.update, try_to_connect=True)
callback.block_until_connectivities_satisfy(
lambda connectivities: _READY in connectivities)
# Now take down the server and confirm that channel readiness is repudiated.
server.shutdown()
callback.block_until_connectivities_satisfy(
lambda connectivities: connectivities[-1] is not _READY)
connectivity_channel.unsubscribe(callback.update)
server.shutdown()
server_completion_queue.shutdown()
server_completion_queue_thread.join()
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -0,0 +1,123 @@
# 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.
"""Tests of grpc.beta.utilities."""
import threading
import time
import unittest
from grpc._adapter import _low
from grpc._adapter import _types
from grpc.beta import beta
from grpc.beta import utilities
from grpc.framework.foundation import future
from grpc_test.framework.common import test_constants
def _drive_completion_queue(completion_queue):
while True:
event = completion_queue.next(time.time() + 24 * 60 * 60)
if event.type == _types.EventType.QUEUE_SHUTDOWN:
break
class _Callback(object):
def __init__(self):
self._condition = threading.Condition()
self._value = None
def accept_value(self, value):
with self._condition:
self._value = value
self._condition.notify_all()
def block_until_called(self):
with self._condition:
while self._value is None:
self._condition.wait()
return self._value
class ChannelConnectivityTest(unittest.TestCase):
def test_lonely_channel_connectivity(self):
channel = beta.create_insecure_channel('localhost', 12345)
callback = _Callback()
ready_future = utilities.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value)
with self.assertRaises(future.TimeoutError):
ready_future.result(test_constants.SHORT_TIMEOUT)
self.assertFalse(ready_future.cancelled())
self.assertFalse(ready_future.done())
self.assertTrue(ready_future.running())
ready_future.cancel()
value_passed_to_callback = callback.block_until_called()
self.assertIs(ready_future, value_passed_to_callback)
self.assertTrue(ready_future.cancelled())
self.assertTrue(ready_future.done())
self.assertFalse(ready_future.running())
def test_immediately_connectable_channel_connectivity(self):
server_completion_queue = _low.CompletionQueue()
server = _low.Server(server_completion_queue, [])
port = server.add_http2_port('[::]:0')
server.start()
server_completion_queue_thread = threading.Thread(
target=_drive_completion_queue, args=(server_completion_queue,))
server_completion_queue_thread.start()
channel = beta.create_insecure_channel('localhost', port)
callback = _Callback()
try:
ready_future = utilities.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value)
self.assertIsNone(
ready_future.result(test_constants.SHORT_TIMEOUT))
value_passed_to_callback = callback.block_until_called()
self.assertIs(ready_future, value_passed_to_callback)
self.assertFalse(ready_future.cancelled())
self.assertTrue(ready_future.done())
self.assertFalse(ready_future.running())
# Cancellation after maturity has no effect.
ready_future.cancel()
self.assertFalse(ready_future.cancelled())
self.assertTrue(ready_future.done())
self.assertFalse(ready_future.running())
finally:
ready_future.cancel()
server.shutdown()
server_completion_queue.shutdown()
server_completion_queue_thread.join()
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -0,0 +1,111 @@
# 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.
"""Tests Face interface compliance of the crust-over-core stack."""
import collections
import unittest
from grpc.framework.core import implementations as core_implementations
from grpc.framework.crust import implementations as crust_implementations
from grpc.framework.foundation import logging_pool
from grpc.framework.interfaces.links import utilities
from grpc_test.framework.common import test_constants
from grpc_test.framework.interfaces.face import test_cases
from grpc_test.framework.interfaces.face import test_interfaces
from grpc_test.framework.interfaces.links import test_utilities
class _Implementation(test_interfaces.Implementation):
def instantiate(
self, methods, method_implementations, multi_method_implementation):
pool = logging_pool.pool(test_constants.POOL_SIZE)
servicer = crust_implementations.servicer(
method_implementations, multi_method_implementation, pool)
service_end_link = core_implementations.service_end_link(
servicer, test_constants.DEFAULT_TIMEOUT,
test_constants.MAXIMUM_TIMEOUT)
invocation_end_link = core_implementations.invocation_end_link()
invocation_end_link.join_link(service_end_link)
service_end_link.join_link(invocation_end_link)
service_end_link.start()
invocation_end_link.start()
generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
# TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
group = next(iter(methods))[0]
# TODO(nathaniel): Add a "cardinalities_by_group" attribute to
# _digest.TestServiceDigest.
cardinalities = {
method: method_object.cardinality()
for (group, method), method_object in methods.iteritems()}
dynamic_stub = crust_implementations.dynamic_stub(
invocation_end_link, group, cardinalities, pool)
return generic_stub, {group: dynamic_stub}, (
invocation_end_link, service_end_link, pool)
def destantiate(self, memo):
invocation_end_link, service_end_link, pool = memo
invocation_end_link.stop(0).wait()
service_end_link.stop(0).wait()
invocation_end_link.join_link(utilities.NULL_LINK)
service_end_link.join_link(utilities.NULL_LINK)
pool.shutdown(wait=True)
def invocation_metadata(self):
return object()
def initial_metadata(self):
return object()
def terminal_metadata(self):
return object()
def code(self):
return object()
def details(self):
return object()
def metadata_transmitted(self, original_metadata, transmitted_metadata):
return original_metadata is transmitted_metadata
def load_tests(loader, tests, pattern):
return unittest.TestSuite(
tests=tuple(
loader.loadTestsFromTestCase(test_case_class)
for test_case_class in test_cases.test_cases(_Implementation())))
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -134,7 +134,7 @@ class _Servicer(base.Servicer):
if group != self._group or method != self._method:
controller.fail(
'%s != %s or %s != %s' % (group, self._group, method, self._method))
raise base.NoSuchMethodError()
raise base.NoSuchMethodError(None, None)
else:
operator = _Operator(
controller, controller.on_service_advance, self._pool,

@ -0,0 +1,37 @@
# 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.
"""A test constant working around issue 3069."""
# test_constants is referenced from specification in this module.
from grpc_test.framework.common import test_constants # pylint: disable=unused-import
# TODO(issue 3069): Replace uses of this constant with
# test_constants.SHORT_TIMEOUT.
REALLY_SHORT_TIMEOUT = 0.1

@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face
from grpc_test.framework.common import test_constants
from grpc_test.framework.common import test_control
from grpc_test.framework.common import test_coverage
from grpc_test.framework.interfaces.face import _3069_test_constant
from grpc_test.framework.interfaces.face import _digest
from grpc_test.framework.interfaces.face import _stock_service
from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
@ -170,7 +171,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
self._invoker.blocking(group, method)(
request, test_constants.SHORT_TIMEOUT)
request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
def testExpiredUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
@ -181,7 +182,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
response_iterator = self._invoker.blocking(group, method)(
request, test_constants.SHORT_TIMEOUT)
request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testExpiredStreamRequestUnaryResponse(self):
@ -193,7 +194,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
self._invoker.blocking(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
def testExpiredStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
@ -204,7 +205,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
response_iterator = self._invoker.blocking(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testFailedUnaryRequestUnaryResponse(self):

@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face
from grpc_test.framework.common import test_constants
from grpc_test.framework.common import test_control
from grpc_test.framework.common import test_coverage
from grpc_test.framework.interfaces.face import _3069_test_constant
from grpc_test.framework.interfaces.face import _digest
from grpc_test.framework.interfaces.face import _receiver
from grpc_test.framework.interfaces.face import _stock_service
@ -264,7 +265,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
request, receiver, receiver.abort,
_3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@ -278,7 +280,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
request, receiver, receiver.abort,
_3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@ -290,7 +293,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
receiver = _receiver.Receiver()
self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@ -303,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
for request in requests:
call_consumer.consume(request)
receiver.block_until_terminated()

@ -40,6 +40,7 @@ from grpc.framework.interfaces.face import face
from grpc_test.framework.common import test_constants
from grpc_test.framework.common import test_control
from grpc_test.framework.common import test_coverage
from grpc_test.framework.interfaces.face import _3069_test_constant
from grpc_test.framework.interfaces.face import _digest
from grpc_test.framework.interfaces.face import _stock_service
from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
@ -265,7 +266,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_future = self._invoker.future(
group, method)(request, test_constants.SHORT_TIMEOUT)
group, method)(request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
self.assertIsInstance(
response_future.exception(), face.ExpirationError)
with self.assertRaises(face.ExpirationError):
@ -279,7 +280,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_iterator = self._invoker.future(group, method)(
request, test_constants.SHORT_TIMEOUT)
request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
with self.assertRaises(face.ExpirationError):
list(response_iterator)
@ -291,7 +292,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_future = self._invoker.future(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
self.assertIsInstance(
response_future.exception(), face.ExpirationError)
with self.assertRaises(face.ExpirationError):
@ -305,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_iterator = self._invoker.future(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
with self.assertRaises(face.ExpirationError):
list(response_iterator)
@ -317,7 +318,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.fail():
response_future = self._invoker.future(group, method)(
request, test_constants.SHORT_TIMEOUT)
request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
# Because the servicer fails outside of the thread from which the
# servicer-side runtime called into it its failure is
@ -340,7 +341,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
# expiration of the RPC.
with self._control.fail(), self.assertRaises(face.ExpirationError):
response_iterator = self._invoker.future(group, method)(
request, test_constants.SHORT_TIMEOUT)
request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testFailedStreamRequestUnaryResponse(self):
@ -351,7 +352,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.fail():
response_future = self._invoker.future(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
# Because the servicer fails outside of the thread from which the
# servicer-side runtime called into it its failure is
@ -374,5 +375,5 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
# expiration of the RPC.
with self._control.fail(), self.assertRaises(face.ExpirationError):
response_iterator = self._invoker.future(group, method)(
iter(requests), test_constants.SHORT_TIMEOUT)
iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)

@ -1,4 +1,4 @@
B# Copyright 2015, Google Inc.
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

@ -35,11 +35,14 @@
#include <grpc++/support/auth_context.h>
#include <gtest/gtest.h>
#include "src/cpp/common/secure_auth_context.h"
#include "test/cpp/util/string_ref_helper.h"
extern "C" {
#include "src/core/security/security_context.h"
}
using ::grpc::testing::ToString;
namespace grpc {
namespace {
@ -84,12 +87,12 @@ TEST_F(AuthPropertyIteratorTest, GeneralTest) {
AuthProperty p1 = *iter;
iter++;
AuthProperty p2 = *iter;
EXPECT_EQ("name", p0.first);
EXPECT_EQ("chapi", p0.second);
EXPECT_EQ("name", p1.first);
EXPECT_EQ("chapo", p1.second);
EXPECT_EQ("foo", p2.first);
EXPECT_EQ("bar", p2.second);
EXPECT_EQ("name", ToString(p0.first));
EXPECT_EQ("chapi", ToString(p0.second));
EXPECT_EQ("name", ToString(p1.first));
EXPECT_EQ("chapo", ToString(p1.second));
EXPECT_EQ("foo", ToString(p2.first));
EXPECT_EQ("bar", ToString(p2.second));
++iter;
EXPECT_EQ(empty_iter, iter);
}

@ -35,11 +35,14 @@
#include <grpc++/support/auth_context.h>
#include <gtest/gtest.h>
#include "src/cpp/common/secure_auth_context.h"
#include "test/cpp/util/string_ref_helper.h"
extern "C" {
#include "src/core/security/security_context.h"
}
using grpc::testing::ToString;
namespace grpc {
namespace {
@ -63,14 +66,14 @@ TEST_F(SecureAuthContextTest, Properties) {
EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name"));
SecureAuthContext context(ctx);
std::vector<grpc::string> peer_identity = context.GetPeerIdentity();
std::vector<grpc::string_ref> peer_identity = context.GetPeerIdentity();
EXPECT_EQ(2u, peer_identity.size());
EXPECT_EQ("chapi", peer_identity[0]);
EXPECT_EQ("chapo", peer_identity[1]);
EXPECT_EQ("chapi", ToString(peer_identity[0]));
EXPECT_EQ("chapo", ToString(peer_identity[1]));
EXPECT_EQ("name", context.GetPeerIdentityPropertyName());
std::vector<grpc::string> bar = context.FindPropertyValues("foo");
std::vector<grpc::string_ref> bar = context.FindPropertyValues("foo");
EXPECT_EQ(1u, bar.size());
EXPECT_EQ("bar", bar[0]);
EXPECT_EQ("bar", ToString(bar[0]));
}
TEST_F(SecureAuthContextTest, Iterators) {
@ -88,12 +91,12 @@ TEST_F(SecureAuthContextTest, Iterators) {
AuthProperty p1 = *iter;
iter++;
AuthProperty p2 = *iter;
EXPECT_EQ("name", p0.first);
EXPECT_EQ("chapi", p0.second);
EXPECT_EQ("name", p1.first);
EXPECT_EQ("chapo", p1.second);
EXPECT_EQ("foo", p2.first);
EXPECT_EQ("bar", p2.second);
EXPECT_EQ("name", ToString(p0.first));
EXPECT_EQ("chapi", ToString(p0.second));
EXPECT_EQ("name", ToString(p1.first));
EXPECT_EQ("chapo", ToString(p1.second));
EXPECT_EQ("foo", ToString(p2.first));
EXPECT_EQ("bar", ToString(p2.second));
++iter;
EXPECT_EQ(context.end(), iter);
}

@ -81,10 +81,10 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
void CheckServerAuthContext(const ServerContext* context) {
std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
std::vector<grpc::string> ssl =
std::vector<grpc::string_ref> ssl =
auth_ctx->FindPropertyValues("transport_security_type");
EXPECT_EQ(1u, ssl.size());
EXPECT_EQ("ssl", ssl[0]);
EXPECT_EQ("ssl", ToString(ssl[0]));
EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
}
@ -840,16 +840,17 @@ TEST_F(End2endTest, ClientAuthContext) {
EXPECT_TRUE(s.ok());
std::shared_ptr<const AuthContext> auth_ctx = context.auth_context();
std::vector<grpc::string> ssl =
std::vector<grpc::string_ref> ssl =
auth_ctx->FindPropertyValues("transport_security_type");
EXPECT_EQ(1u, ssl.size());
EXPECT_EQ("ssl", ssl[0]);
EXPECT_EQ("ssl", ToString(ssl[0]));
EXPECT_EQ("x509_subject_alternative_name",
auth_ctx->GetPeerIdentityPropertyName());
EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size());
EXPECT_EQ("*.test.google.fr", auth_ctx->GetPeerIdentity()[0]);
EXPECT_EQ("waterzooi.test.google.be", auth_ctx->GetPeerIdentity()[1]);
EXPECT_EQ("*.test.youtube.com", auth_ctx->GetPeerIdentity()[2]);
EXPECT_EQ("*.test.google.fr", ToString(auth_ctx->GetPeerIdentity()[0]));
EXPECT_EQ("waterzooi.test.google.be",
ToString(auth_ctx->GetPeerIdentity()[1]));
EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2]));
}
// Make the response larger than the flow control window.

@ -100,8 +100,8 @@ TEST_F(StringRefTest, Assignment) {
TEST_F(StringRefTest, Iterator) {
string_ref s(kTestString);
size_t i = 0;
for (char c : s) {
EXPECT_EQ(kTestString[i++], c);
for (auto it = s.cbegin(); it != s.cend(); ++it) {
EXPECT_EQ(kTestString[i++], *it);
}
EXPECT_EQ(strlen(kTestString), i);
}

@ -37,6 +37,7 @@ cd $(dirname $0)/../..
root=`pwd`
export GRPC_LIB_SUBDIR=libs/$CONFIG
export CFLAGS="-Wno-parentheses-equality"
# build php
cd src/php

@ -174,7 +174,6 @@ class Job(object):
for k, v in add_env.iteritems():
env[k] = v
self._start = time.time()
print spec.cmdline
self._process = subprocess.Popen(args=spec.cmdline,
stderr=subprocess.STDOUT,
stdout=self._tempfile,

@ -45,6 +45,8 @@ source "python"$PYVER"_virtual_environment"/bin/activate
# py.test (or find another tool or *something*) that's acceptable to the rest of
# the team...
"python"$PYVER -m grpc_test._core_over_links_base_interface_test
"python"$PYVER -m grpc_test._crust_over_core_over_links_face_interface_test
"python"$PYVER -m grpc_test.framework._crust_over_core_face_interface_test
"python"$PYVER -m grpc_test.framework.core._base_interface_test
"python"$PYVER $GRPCIO_TEST/setup.py test -a "-n8 --cov=grpc --junitxml=./report.xml --timeout=300"

@ -70,13 +70,14 @@ def platform_string():
# SimpleConfig: just compile with CONFIG=config, and run the binary to test
class SimpleConfig(object):
def __init__(self, config, environ=None):
def __init__(self, config, environ=None, timeout_seconds=5*60):
if environ is None:
environ = {}
self.build_config = config
self.allow_hashing = (config != 'gcov')
self.environ = environ
self.environ['CONFIG'] = config
self.timeout_seconds = timeout_seconds
def job_spec(self, cmdline, hash_targets, shortname=None, environ={}):
"""Construct a jobset.JobSpec for a test under this config
@ -96,6 +97,7 @@ class SimpleConfig(object):
return jobset.JobSpec(cmdline=cmdline,
shortname=shortname,
environ=actual_environ,
timeout_seconds=self.timeout_seconds,
hash_targets=hash_targets
if self.allow_hashing else None)
@ -354,11 +356,11 @@ class Build(object):
_CONFIGS = {
'dbg': SimpleConfig('dbg'),
'opt': SimpleConfig('opt'),
'tsan': SimpleConfig('tsan', environ={
'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
'msan': SimpleConfig('msan'),
'msan': SimpleConfig('msan', timeout_seconds=7*60),
'ubsan': SimpleConfig('ubsan'),
'asan': SimpleConfig('asan', environ={
'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
'LSAN_OPTIONS': 'report_objects=1'}),
'asan-noleaks': SimpleConfig('asan', environ={

@ -1077,8 +1077,11 @@
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc++"
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"language": "c++",
@ -1582,8 +1585,11 @@
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc++"
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"language": "c++",

@ -623,10 +623,10 @@ async_end2end_test: async_end2end_test.exe
echo Running async_end2end_test
$(OUT_DIR)\async_end2end_test.exe
auth_property_iterator_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR)
auth_property_iterator_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR)
echo Building auth_property_iterator_test
$(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\auth_property_iterator_test.cc
$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj
$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj
auth_property_iterator_test: auth_property_iterator_test.exe
echo Running auth_property_iterator_test
$(OUT_DIR)\auth_property_iterator_test.exe
@ -759,10 +759,10 @@ reconnect_interop_server: reconnect_interop_server.exe
echo Running reconnect_interop_server
$(OUT_DIR)\reconnect_interop_server.exe
secure_auth_context_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR)
secure_auth_context_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR)
echo Building secure_auth_context_test
$(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\secure_auth_context_test.cc
$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj
$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj
secure_auth_context_test: secure_auth_context_test.exe
echo Running secure_auth_context_test
$(OUT_DIR)\secure_auth_context_test.exe

Loading…
Cancel
Save