Merge remote-tracking branch 'upstream/master'

Resolve a conflict between adding write buffer hint
and the change of API
Conflicts:
 src/cpp/server/async_server_context.cc
pull/388/head
Vijay Pai 10 years ago
commit 280744ec64
  1. 5
      .gitignore
  2. 265
      Makefile
  3. 102
      build.json
  4. 26
      examples/tips/README
  5. 2
      examples/tips/empty.proto
  6. 2
      examples/tips/label.proto
  7. 94
      examples/tips/main.cc
  8. 46
      examples/tips/publisher.cc
  9. 23
      examples/tips/publisher.h
  10. 69
      examples/tips/publisher_test.cc
  11. 2
      examples/tips/pubsub.proto
  12. 118
      examples/tips/subscriber.cc
  13. 38
      examples/tips/subscriber.h
  14. 157
      examples/tips/subscriber_test.cc
  15. 47
      include/grpc/grpc.h
  16. 6
      include/grpc/support/port_platform.h
  17. 13
      include/grpc/support/thd.h
  18. 42
      include/grpc/support/thd_posix.h
  19. 2
      src/core/httpcli/format_request.c
  20. 8
      src/core/iomgr/iomgr.c
  21. 3
      src/core/iomgr/pollset_kick.c
  22. 7
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  23. 14
      src/core/iomgr/pollset_posix.c
  24. 6
      src/core/iomgr/pollset_posix.h
  25. 2
      src/core/iomgr/wakeup_fd_eventfd.c
  26. 9
      src/core/iomgr/wakeup_fd_nospecial.c
  27. 8
      src/core/iomgr/wakeup_fd_pipe.c
  28. 2
      src/core/iomgr/wakeup_fd_pipe.h
  29. 14
      src/core/iomgr/wakeup_fd_posix.c
  30. 31
      src/core/iomgr/wakeup_fd_posix.h
  31. 35
      src/core/support/cpu_linux.c
  32. 2
      src/core/support/log_posix.c
  33. 8
      src/core/support/thd_posix.c
  34. 8
      src/core/support/thd_win32.c
  35. 38
      src/core/surface/call.c
  36. 6
      src/core/surface/channel.c
  37. 3
      src/core/surface/server.c
  38. 22
      src/core/tsi/ssl_transport_security.c
  39. 16
      src/cpp/client/channel.cc
  40. 2
      src/cpp/server/async_server.cc
  41. 11
      src/cpp/server/async_server_context.cc
  42. 2
      src/cpp/server/server.cc
  43. 12
      src/cpp/stream/stream_context.cc
  44. 2
      src/csharp/.gitignore
  45. 22
      src/csharp/README.md
  46. 113
      src/csharp/ext/grpc_csharp_ext.c
  47. 2
      src/node/.gitignore
  48. 26
      src/node/ext/call.cc
  49. 2
      src/node/ext/server.cc
  50. 27
      src/php/README.md
  51. 142
      src/php/ext/grpc/call.c
  52. 1
      src/php/ext/grpc/call.h
  53. 6
      src/php/ext/grpc/server.c
  54. 2
      src/php/lib/Grpc/AbstractSurfaceActiveCall.php
  55. 7
      src/php/lib/Grpc/ActiveCall.php
  56. 2
      src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php
  57. 20
      src/php/tests/generated_code/GeneratedCodeTest.php
  58. 55
      src/php/tests/interop/interop_client.php
  59. 9
      src/php/tests/unit_tests/CallTest.php
  60. 96
      src/php/tests/unit_tests/EndToEndTest.php
  61. 94
      src/php/tests/unit_tests/SecureEndToEndTest.php
  62. 2
      src/php/tests/unit_tests/TimevalTest.php
  63. 6
      src/php/tests/util/port_picker.php
  64. 23
      src/python/src/_adapter/_call.c
  65. 11
      src/python/src/_adapter/_links_test.py
  66. 2
      src/python/src/_adapter/_lonely_rear_link_test.py
  67. 2
      src/python/src/_adapter/_server.c
  68. 3
      src/python/src/_adapter/fore.py
  69. 49
      src/python/src/_framework/base/interfaces.py
  70. 44
      src/python/src/_framework/base/interfaces_test.py
  71. 25
      src/python/src/_framework/base/packets/_ends.py
  72. 2
      src/python/src/_framework/base/packets/_ingestion.py
  73. 5
      src/python/src/_framework/base/packets/_interfaces.py
  74. 82
      src/python/src/_framework/base/packets/_termination.py
  75. 34
      src/python/src/_framework/base/packets/_transmission.py
  76. 7
      src/python/src/_framework/base/packets/packets.py
  77. 15
      src/python/src/_framework/base/util.py
  78. 11
      src/python/src/_framework/face/_calls.py
  79. 28
      src/python/src/_framework/face/_control.py
  80. 43
      src/python/src/_framework/face/interfaces.py
  81. 24
      src/python/src/_framework/face/testing/event_invocation_synchronous_event_service_test_case.py
  82. 10
      src/ruby/Rakefile
  83. 44
      src/ruby/bin/apis/google/protobuf/empty.rb
  84. 278
      src/ruby/bin/apis/pubsub_demo.rb
  85. 174
      src/ruby/bin/apis/tech/pubsub/proto/pubsub.rb
  86. 103
      src/ruby/bin/apis/tech/pubsub/proto/pubsub_services.rb
  87. 180
      src/ruby/bin/interop/interop_client.rb
  88. 5
      src/ruby/bin/interop/test/cpp/interop/messages.rb
  89. 0
      src/ruby/bin/math.rb
  90. 0
      src/ruby/bin/math_services.rb
  91. 22
      src/ruby/ext/grpc/rb_call.c
  92. 7
      src/ruby/ext/grpc/rb_channel.c
  93. 2
      src/ruby/ext/grpc/rb_server.c
  94. 10
      src/ruby/grpc.gemspec
  95. 2
      src/ruby/lib/grpc.rb
  96. 69
      src/ruby/lib/grpc/auth/compute_engine.rb
  97. 68
      src/ruby/lib/grpc/auth/service_account.rb
  98. 67
      src/ruby/lib/grpc/auth/signet.rb
  99. 163
      src/ruby/spec/auth/apply_auth_examples.rb
  100. 108
      src/ruby/spec/auth/compute_engine_spec.rb
  101. Some files were not shown because too many files have changed in this diff Show More

5
.gitignore vendored

@ -17,6 +17,11 @@ coverage
# python compiled objects
*.pyc
#eclipse project files
.cproject
.project
.settings
# cache for run_tests.py
.run_tests_cache

File diff suppressed because one or more lines are too long

@ -220,8 +220,6 @@
"include/grpc/support/sync_posix.h",
"include/grpc/support/sync_win32.h",
"include/grpc/support/thd.h",
"include/grpc/support/thd_posix.h",
"include/grpc/support/thd_win32.h",
"include/grpc/support/time.h",
"include/grpc/support/time_posix.h",
"include/grpc/support/time_win32.h",
@ -433,13 +431,26 @@
"examples/tips/label.proto",
"examples/tips/empty.proto",
"examples/tips/pubsub.proto",
"examples/tips/client.cc"
"examples/tips/publisher.cc",
"examples/tips/subscriber.cc"
],
"deps": [
"grpc++",
"grpc",
"gpr"
]
},
{
"name": "grpc_csharp_ext",
"build": "all",
"language": "c",
"deps": [
"gpr",
"grpc"
],
"src": [
"src/csharp/ext/grpc_csharp_ext.c"
]
}
],
"targets": [
@ -1568,31 +1579,32 @@
"run": false
},
{
"name": "qps_client",
"name": "tips_client",
"build": "test",
"language": "c++",
"src": [
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/client.cc"
"examples/tips/main.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
],
"run": false
},
{
"name": "qps_server",
"name": "tips_publisher_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/server.cc"
"examples/tips/publisher_test.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
@ -1602,30 +1614,32 @@
]
},
{
"name": "ruby_plugin",
"build": "protoc",
"name": "tips_subscriber_test",
"build": "test",
"language": "c++",
"headers": [
"src/compiler/cpp_generator.h",
"src/compiler/cpp_generator_helpers-inl.h",
"src/compiler/cpp_generator_map-inl.h",
"src/compiler/cpp_generator_string-inl.h"
],
"src": [
"src/compiler/ruby_generator.cc",
"src/compiler/ruby_plugin.cc"
"examples/tips/subscriber_test.cc"
],
"deps": [],
"secure": false
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "status_test",
"name": "qps_client",
"build": "test",
"language": "c++",
"src": [
"test/cpp/util/status_test.cc"
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/client.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
@ -1634,11 +1648,12 @@
]
},
{
"name": "sync_client_async_server_test",
"name": "qps_server",
"build": "test",
"language": "c++",
"src": [
"test/cpp/end2end/sync_client_async_server_test.cc"
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/server.cc"
],
"deps": [
"grpc++_test_util",
@ -1650,11 +1665,28 @@
]
},
{
"name": "thread_pool_test",
"name": "ruby_plugin",
"build": "protoc",
"language": "c++",
"headers": [
"src/compiler/cpp_generator.h",
"src/compiler/cpp_generator_helpers-inl.h",
"src/compiler/cpp_generator_map-inl.h",
"src/compiler/cpp_generator_string-inl.h"
],
"src": [
"src/compiler/ruby_generator.cc",
"src/compiler/ruby_plugin.cc"
],
"deps": [],
"secure": false
},
{
"name": "status_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/server/thread_pool_test.cc"
"test/cpp/util/status_test.cc"
],
"deps": [
"grpc_test_util",
@ -1665,33 +1697,29 @@
]
},
{
"name": "tips_client",
"name": "sync_client_async_server_test",
"build": "test",
"language": "c++",
"src": [
"examples/tips/client_main.cc"
"test/cpp/end2end/sync_client_async_server_test.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
],
"run": false
]
},
{
"name": "tips_client_test",
"name": "thread_pool_test",
"build": "test",
"language": "c++",
"src": [
"examples/tips/client_test.cc"
"test/cpp/server/thread_pool_test.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",

@ -0,0 +1,26 @@
C++ Client implementation for Cloud Pub/Sub service (TIPS)
(https://developers.google.com/apis-explorer/#p/pubsub/v1beta1/).
"Google Cloud Pub/Sub" API needs to be enabled at
https://console.developers.google.com/project to open the access for a client.
Select the project name, select the "APIs" under "APIs & auth", and turn
on "Google Cloud Pub/Sub" API.
To run the client from Google Compute Engine (GCE), the GCE instance needs to
be created with scope "https://www.googleapis.com/auth/cloud-platform" as below:
gcloud compute instances create instance-name
--image debian-7 --scopes https://www.googleapis.com/auth/cloud-platform
To run the client from GCE:
make tips_client
bins/opt/tips_client --project_id="your project id"
A service account credential is required to run the client from other
environments, which can be generated as a JSON key file from
https://console.developers.google.com/project/. To run the client with a service
account credential:
bins/opt/tips_client
--project_id="your project id"
--service_account_key_file="absolute path to the JSON key file"

@ -1,3 +1,5 @@
// This file will be moved to a new location.
syntax = "proto2";
package proto2;

@ -1,3 +1,5 @@
// This file will be moved to a new location.
// Labels provide a way to associate user-defined metadata with various
// objects. Labels may be used to organize objects into non-hierarchical
// groups; think metadata tags attached to mp3s.

@ -46,18 +46,30 @@
#include <grpc++/credentials.h>
#include <grpc++/status.h>
#include "examples/tips/client.h"
#include "examples/tips/publisher.h"
#include "examples/tips/subscriber.h"
#include "test/cpp/util/create_test_channel.h"
DEFINE_int32(server_port, 443, "Server port.");
DEFINE_string(server_host,
"pubsub-staging.googleapis.com", "Server host to connect to");
DEFINE_string(project_id, "", "GCE project id such as stoked-keyword-656");
DEFINE_string(service_account_key_file, "",
"Path to service account json key file.");
DEFINE_string(oauth_scope, "", "Scope for OAuth tokens.");
DEFINE_string(oauth_scope,
"https://www.googleapis.com/auth/cloud-platform",
"Scope for OAuth tokens.");
namespace {
const char kTopic[] = "testtopics";
const char kSubscriptionName[] = "testsubscription";
const char kMessageData[] = "Test Data";
} // namespace
grpc::string GetServiceAccountJsonKey() {
static grpc::string json_key;
grpc::string json_key;
if (json_key.empty()) {
std::ifstream json_key_file(FLAGS_service_account_key_file);
std::stringstream key_stream;
@ -72,10 +84,7 @@ int main(int argc, char** argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
gpr_log(GPR_INFO, "Start TIPS client");
const int host_port_buf_size = 1024;
char host_port[host_port_buf_size];
snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
FLAGS_server_port);
std::ostringstream ss;
std::unique_ptr<grpc::Credentials> creds;
if (FLAGS_service_account_key_file != "") {
@ -86,28 +95,83 @@ int main(int argc, char** argv) {
creds = grpc::CredentialsFactory::ComputeEngineCredentials();
}
ss << FLAGS_server_host << ":" << FLAGS_server_port;
std::shared_ptr<grpc::ChannelInterface> channel(
grpc::CreateTestChannel(
host_port,
ss.str(),
FLAGS_server_host,
true, // enable SSL
true, // use prod roots
creds));
grpc::examples::tips::Client client(channel);
grpc::examples::tips::Publisher publisher(channel);
grpc::examples::tips::Subscriber subscriber(channel);
GPR_ASSERT(FLAGS_project_id != "");
ss.str("");
ss << "/topics/" << FLAGS_project_id << "/" << kTopic;
grpc::string topic = ss.str();
ss.str("");
ss << FLAGS_project_id << "/" << kSubscriptionName;
grpc::string subscription_name = ss.str();
// Clean up test topic and subcription if they exist before.
grpc::string subscription_topic;
if (subscriber.GetSubscription(
subscription_name, &subscription_topic).IsOk()) {
subscriber.DeleteSubscription(subscription_name);
}
if (publisher.GetTopic(topic).IsOk()) publisher.DeleteTopic(topic);
grpc::Status s = publisher.CreateTopic(topic);
gpr_log(GPR_INFO, "Create topic returns code %d, %s",
s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
grpc::Status s = client.CreateTopic("/topics/stoked-keyword-656/testtopics");
gpr_log(GPR_INFO, "return code %d, %s", s.code(), s.details().c_str());
s = publisher.GetTopic(topic);
gpr_log(GPR_INFO, "Get topic returns code %d, %s",
s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
s = client.GetTopic("/topics/stoked-keyword-656/testtopics");
gpr_log(GPR_INFO, "return code %d, %s", s.code(), s.details().c_str());
std::vector<grpc::string> topics;
s = publisher.ListTopics(FLAGS_project_id, &topics);
gpr_log(GPR_INFO, "List topic returns code %d, %s",
s.code(), s.details().c_str());
bool topic_found = false;
for (unsigned int i = 0; i < topics.size(); i++) {
if (topics[i] == topic) topic_found = true;
gpr_log(GPR_INFO, "topic: %s", topics[i].c_str());
}
GPR_ASSERT(s.IsOk());
GPR_ASSERT(topic_found);
s = subscriber.CreateSubscription(topic, subscription_name);
gpr_log(GPR_INFO, "create subscrption returns code %d, %s",
s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
s = publisher.Publish(topic, kMessageData);
gpr_log(GPR_INFO, "Publish %s returns code %d, %s",
kMessageData, s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
grpc::string data;
s = subscriber.Pull(subscription_name, &data);
gpr_log(GPR_INFO, "Pull %s", data.c_str());
s = subscriber.DeleteSubscription(subscription_name);
gpr_log(GPR_INFO, "Delete subscription returns code %d, %s",
s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
s = client.DeleteTopic("/topics/stoked-keyword-656/testtopics");
gpr_log(GPR_INFO, "return code %d, %s", s.code(), s.details().c_str());
s = publisher.DeleteTopic(topic);
gpr_log(GPR_INFO, "Delete topic returns code %d, %s",
s.code(), s.details().c_str());
GPR_ASSERT(s.IsOk());
subscriber.Shutdown();
publisher.Shutdown();
channel.reset();
grpc_shutdown();
return 0;

@ -31,9 +31,11 @@
*
*/
#include <sstream>
#include <grpc++/client_context.h>
#include "examples/tips/client.h"
#include "examples/tips/publisher.h"
using tech::pubsub::Topic;
using tech::pubsub::DeleteTopicRequest;
@ -41,16 +43,22 @@ using tech::pubsub::GetTopicRequest;
using tech::pubsub::PublisherService;
using tech::pubsub::ListTopicsRequest;
using tech::pubsub::ListTopicsResponse;
using tech::pubsub::PublishRequest;
using tech::pubsub::PubsubMessage;
namespace grpc {
namespace examples {
namespace tips {
Client::Client(std::shared_ptr<ChannelInterface> channel)
Publisher::Publisher(std::shared_ptr<ChannelInterface> channel)
: stub_(PublisherService::NewStub(channel)) {
}
Status Client::CreateTopic(grpc::string topic) {
void Publisher::Shutdown() {
stub_.reset();
}
Status Publisher::CreateTopic(const grpc::string& topic) {
Topic request;
Topic response;
request.set_name(topic);
@ -59,15 +67,28 @@ Status Client::CreateTopic(grpc::string topic) {
return stub_->CreateTopic(&context, request, &response);
}
Status Client::ListTopics() {
Status Publisher::ListTopics(const grpc::string& project_id,
std::vector<grpc::string>* topics) {
ListTopicsRequest request;
ListTopicsResponse response;
ClientContext context;
return stub_->ListTopics(&context, request, &response);
std::ostringstream ss;
ss << "cloud.googleapis.com/project in (/projects/" << project_id << ")";
request.set_query(ss.str());
Status s = stub_->ListTopics(&context, request, &response);
tech::pubsub::Topic topic;
for (int i = 0; i < response.topic_size(); i++) {
topic = response.topic(i);
topics->push_back(topic.name());
}
return s;
}
Status Client::GetTopic(grpc::string topic) {
Status Publisher::GetTopic(const grpc::string& topic) {
GetTopicRequest request;
Topic response;
ClientContext context;
@ -77,7 +98,7 @@ Status Client::GetTopic(grpc::string topic) {
return stub_->GetTopic(&context, request, &response);
}
Status Client::DeleteTopic(grpc::string topic) {
Status Publisher::DeleteTopic(const grpc::string& topic) {
DeleteTopicRequest request;
proto2::Empty response;
ClientContext context;
@ -87,6 +108,17 @@ Status Client::DeleteTopic(grpc::string topic) {
return stub_->DeleteTopic(&context, request, &response);
}
Status Publisher::Publish(const grpc::string& topic, const grpc::string& data) {
PublishRequest request;
proto2::Empty response;
ClientContext context;
request.mutable_message()->set_data(data);
request.set_topic(topic);
return stub_->Publish(&context, request, &response);
}
} // namespace tips
} // namespace examples
} // namespace grpc

@ -31,8 +31,8 @@
*
*/
#ifndef __GRPCPP_EXAMPLES_TIPS_CLIENT_H_
#define __GRPCPP_EXAMPLES_TIPS_CLIENT_H_
#ifndef __GRPCPP_EXAMPLES_TIPS_PUBLISHER_H_
#define __GRPCPP_EXAMPLES_TIPS_PUBLISHER_H_
#include <grpc++/channel_interface.h>
#include <grpc++/status.h>
@ -43,13 +43,18 @@ namespace grpc {
namespace examples {
namespace tips {
class Client {
class Publisher {
public:
Client(std::shared_ptr<grpc::ChannelInterface> channel);
Status CreateTopic(grpc::string topic);
Status GetTopic(grpc::string topic);
Status DeleteTopic(grpc::string topic);
Status ListTopics();
Publisher(std::shared_ptr<ChannelInterface> channel);
void Shutdown();
Status CreateTopic(const grpc::string& topic);
Status GetTopic(const grpc::string& topic);
Status DeleteTopic(const grpc::string& topic);
Status ListTopics(const grpc::string& project_id,
std::vector<grpc::string>* topics);
Status Publish(const grpc::string& topic, const grpc::string& data);
private:
std::unique_ptr<tech::pubsub::PublisherService::Stub> stub_;
@ -59,4 +64,4 @@ class Client {
} // namespace examples
} // namespace grpc
#endif // __GRPCPP_EXAMPLES_TIPS_CLIENT_H_
#endif // __GRPCPP_EXAMPLES_TIPS_PUBLISHER_H_

@ -41,7 +41,7 @@
#include <grpc++/status.h>
#include <gtest/gtest.h>
#include "examples/tips/client.h"
#include "examples/tips/publisher.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
@ -51,9 +51,11 @@ namespace grpc {
namespace testing {
namespace {
const char kProjectId[] = "project id";
const char kTopic[] = "test topic";
const char kMessageData[] = "test message data";
class PublishServiceImpl : public tech::pubsub::PublisherService::Service {
class PublisherServiceImpl : public tech::pubsub::PublisherService::Service {
public:
Status CreateTopic(::grpc::ServerContext* context,
const ::tech::pubsub::Topic* request,
@ -61,34 +63,81 @@ class PublishServiceImpl : public tech::pubsub::PublisherService::Service {
EXPECT_EQ(request->name(), kTopic);
return Status::OK;
}
Status Publish(ServerContext* context,
const ::tech::pubsub::PublishRequest* request,
::proto2::Empty* response) override {
EXPECT_EQ(request->message().data(), kMessageData);
return Status::OK;
}
Status GetTopic(ServerContext* context,
const ::tech::pubsub::GetTopicRequest* request,
::tech::pubsub::Topic* response) override {
EXPECT_EQ(request->topic(), kTopic);
return Status::OK;
}
Status ListTopics(ServerContext* context,
const ::tech::pubsub::ListTopicsRequest* request,
::tech::pubsub::ListTopicsResponse* response) override {
std::ostringstream ss;
ss << "cloud.googleapis.com/project in (/projects/" << kProjectId << ")";
EXPECT_EQ(request->query(), ss.str());
response->add_topic()->set_name(kTopic);
return Status::OK;
}
Status DeleteTopic(ServerContext* context,
const ::tech::pubsub::DeleteTopicRequest* request,
::proto2::Empty* response) override {
EXPECT_EQ(request->topic(), kTopic);
return Status::OK;
}
};
class End2endTest : public ::testing::Test {
class PublisherTest : public ::testing::Test {
protected:
// Setup a server and a client for PublisherService.
void SetUp() override {
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
// Setup server
ServerBuilder builder;
builder.AddPort(server_address_.str());
builder.RegisterService(service_.service());
server_ = builder.BuildAndStart();
channel_ = CreateChannel(server_address_.str(), ChannelArguments());
publisher_.reset(new grpc::examples::tips::Publisher(channel_));
}
void TearDown() override { server_->Shutdown(); }
void TearDown() override {
server_->Shutdown();
publisher_->Shutdown();
}
std::unique_ptr<Server> server_;
std::ostringstream server_address_;
PublishServiceImpl service_;
std::unique_ptr<Server> server_;
PublisherServiceImpl service_;
std::shared_ptr<ChannelInterface> channel_;
std::unique_ptr<grpc::examples::tips::Publisher> publisher_;
};
TEST_F(End2endTest, CreateTopic) {
grpc::examples::tips::Client client(channel_);
client.CreateTopic(kTopic);
TEST_F(PublisherTest, TestPublisher) {
EXPECT_TRUE(publisher_->CreateTopic(kTopic).IsOk());
EXPECT_TRUE(publisher_->Publish(kTopic, kMessageData).IsOk());
EXPECT_TRUE(publisher_->GetTopic(kTopic).IsOk());
std::vector<grpc::string> topics;
EXPECT_TRUE(publisher_->ListTopics(kProjectId, &topics).IsOk());
EXPECT_EQ(topics.size(), 1);
EXPECT_EQ(topics[0], kTopic);
}
} // namespace

@ -1,3 +1,5 @@
// This file will be moved to a new location.
// Specification of the Pubsub API.
syntax = "proto2";

@ -0,0 +1,118 @@
/*
*
* Copyright 2014, 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.
*
*/
#include <grpc++/client_context.h>
#include "examples/tips/subscriber.h"
using tech::pubsub::Topic;
using tech::pubsub::DeleteTopicRequest;
using tech::pubsub::GetTopicRequest;
using tech::pubsub::SubscriberService;
using tech::pubsub::ListTopicsRequest;
using tech::pubsub::ListTopicsResponse;
using tech::pubsub::PublishRequest;
using tech::pubsub::PubsubMessage;
namespace grpc {
namespace examples {
namespace tips {
Subscriber::Subscriber(std::shared_ptr<ChannelInterface> channel)
: stub_(SubscriberService::NewStub(channel)) {
}
void Subscriber::Shutdown() {
stub_.reset();
}
Status Subscriber::CreateSubscription(const grpc::string& topic,
const grpc::string& name) {
tech::pubsub::Subscription request;
tech::pubsub::Subscription response;
ClientContext context;
request.set_topic(topic);
request.set_name(name);
return stub_->CreateSubscription(&context, request, &response);
}
Status Subscriber::GetSubscription(const grpc::string& name,
grpc::string* topic) {
tech::pubsub::GetSubscriptionRequest request;
tech::pubsub::Subscription response;
ClientContext context;
request.set_subscription(name);
Status s = stub_->GetSubscription(&context, request, &response);
*topic = response.topic();
return s;
}
Status Subscriber::DeleteSubscription(const grpc::string& name) {
tech::pubsub::DeleteSubscriptionRequest request;
proto2::Empty response;
ClientContext context;
request.set_subscription(name);
return stub_->DeleteSubscription(&context, request, &response);
}
Status Subscriber::Pull(const grpc::string& name, grpc::string* data) {
tech::pubsub::PullRequest request;
tech::pubsub::PullResponse response;
ClientContext context;
request.set_subscription(name);
Status s = stub_->Pull(&context, request, &response);
if (s.IsOk()) {
tech::pubsub::PubsubEvent event = response.pubsub_event();
if (event.has_message()) {
*data = event.message().data();
}
tech::pubsub::AcknowledgeRequest ack;
proto2::Empty empty;
ClientContext ack_context;
ack.set_subscription(name);
ack.add_ack_id(response.ack_id());
stub_->Acknowledge(&ack_context, ack, &empty);
}
return s;
}
} // namespace tips
} // namespace examples
} // namespace grpc

@ -31,14 +31,38 @@
*
*/
#ifndef __GRPC_SUPPORT_THD_WIN32_H__
#define __GRPC_SUPPORT_THD_WIN32_H__
#ifndef __GRPCPP_EXAMPLES_TIPS_SUBSCRIBER_H_
#define __GRPCPP_EXAMPLES_TIPS_SUBSCRIBER_H_
/* Win32 variant of gpr_thd_platform.h */
#include <grpc++/channel_interface.h>
#include <grpc++/status.h>
#include <windows.h>
#include <grpc/support/atm.h>
#include "examples/tips/pubsub.pb.h"
typedef int gpr_thd_id;
namespace grpc {
namespace examples {
namespace tips {
#endif /* __GRPC_SUPPORT_THD_WIN32_H__ */
class Subscriber {
public:
Subscriber(std::shared_ptr<ChannelInterface> channel);
void Shutdown();
Status CreateSubscription(const grpc::string& topic,
const grpc::string& name);
Status GetSubscription(const grpc::string& name, grpc::string* topic);
Status DeleteSubscription(const grpc::string& name);
Status Pull(const grpc::string& name, grpc::string* data);
private:
std::unique_ptr<tech::pubsub::SubscriberService::Stub> stub_;
};
} // namespace tips
} // namespace examples
} // namespace grpc
#endif // __GRPCPP_EXAMPLES_TIPS_SUBSCRIBER_H_

@ -0,0 +1,157 @@
/*
*
* Copyright 2014, 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.
*
*/
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/status.h>
#include <gtest/gtest.h>
#include "examples/tips/subscriber.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
namespace grpc {
namespace testing {
namespace {
const char kTopic[] = "test topic";
const char kSubscriptionName[] = "subscription name";
const char kData[] = "Message data";
class SubscriberServiceImpl : public tech::pubsub::SubscriberService::Service {
public:
Status CreateSubscription(ServerContext* context,
const tech::pubsub::Subscription* request,
tech::pubsub::Subscription* response) override {
EXPECT_EQ(request->topic(), kTopic);
EXPECT_EQ(request->name(), kSubscriptionName);
return Status::OK;
}
Status GetSubscription(ServerContext* context,
const tech::pubsub::GetSubscriptionRequest* request,
tech::pubsub::Subscription* response) override {
EXPECT_EQ(request->subscription(), kSubscriptionName);
response->set_topic(kTopic);
return Status::OK;
}
Status DeleteSubscription(
ServerContext* context,
const tech::pubsub::DeleteSubscriptionRequest* request,
proto2::Empty* response) override {
EXPECT_EQ(request->subscription(), kSubscriptionName);
return Status::OK;
}
Status Pull(ServerContext* context,
const tech::pubsub::PullRequest* request,
tech::pubsub::PullResponse* response) override {
EXPECT_EQ(request->subscription(), kSubscriptionName);
response->set_ack_id("1");
response->mutable_pubsub_event()->mutable_message()->set_data(kData);
return Status::OK;
}
Status Acknowledge(ServerContext* context,
const tech::pubsub::AcknowledgeRequest* request,
proto2::Empty* response) override {
return Status::OK;
}
};
class SubscriberTest : public ::testing::Test {
protected:
// Setup a server and a client for SubscriberService.
void SetUp() override {
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
ServerBuilder builder;
builder.AddPort(server_address_.str());
builder.RegisterService(service_.service());
server_ = builder.BuildAndStart();
channel_ = CreateChannel(server_address_.str(), ChannelArguments());
subscriber_.reset(new grpc::examples::tips::Subscriber(channel_));
}
void TearDown() override {
server_->Shutdown();
subscriber_->Shutdown();
}
std::ostringstream server_address_;
std::unique_ptr<Server> server_;
SubscriberServiceImpl service_;
std::shared_ptr<ChannelInterface> channel_;
std::unique_ptr<grpc::examples::tips::Subscriber> subscriber_;
};
TEST_F(SubscriberTest, TestSubscriber) {
EXPECT_TRUE(subscriber_->CreateSubscription(kTopic,
kSubscriptionName).IsOk());
grpc::string topic;
EXPECT_TRUE(subscriber_->GetSubscription(kSubscriptionName,
&topic).IsOk());
EXPECT_EQ(topic, kTopic);
grpc::string data;
EXPECT_TRUE(subscriber_->Pull(kSubscriptionName,
&data).IsOk());
EXPECT_TRUE(subscriber_->DeleteSubscription(kSubscriptionName).IsOk());
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
gpr_log(GPR_INFO, "Start test ...");
int result = RUN_ALL_TESTS();
grpc_shutdown();
return result;
}

@ -275,8 +275,9 @@ void grpc_completion_queue_destroy(grpc_completion_queue *cq);
/* Create a call given a grpc_channel, in order to call 'method'. The request
is not sent until grpc_call_invoke is called. All completions are sent to
'completion_queue'. */
grpc_call *grpc_channel_create_call(grpc_channel *channel, const char *method,
const char *host, gpr_timespec deadline);
grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
const char *method, const char *host,
gpr_timespec deadline);
/* Create a client channel */
grpc_channel *grpc_channel_create(const char *target,
@ -307,8 +308,9 @@ void grpc_channel_destroy(grpc_channel *channel);
REQUIRES: grpc_call_start_invoke/grpc_call_server_end_initial_metadata have
not been called on this call.
Produces no events. */
grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
gpr_uint32 flags);
grpc_call_error grpc_call_add_metadata_old(grpc_call *call,
grpc_metadata *metadata,
gpr_uint32 flags);
/* Invoke the RPC. Starts sending metadata and request headers on the wire.
flags is a bit-field combination of the write flags defined above.
@ -319,9 +321,9 @@ grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag, void *finished_tag,
gpr_uint32 flags);
grpc_call_error grpc_call_invoke_old(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag,
void *finished_tag, gpr_uint32 flags);
/* Accept an incoming RPC, binding a completion queue to it.
To be called before sending or receiving messages.
@ -330,9 +332,9 @@ grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
grpc_call_error grpc_call_server_accept(grpc_call *call,
grpc_completion_queue *cq,
void *finished_tag);
grpc_call_error grpc_call_server_accept_old(grpc_call *call,
grpc_completion_queue *cq,
void *finished_tag);
/* Start sending metadata.
To be called before sending messages.
@ -340,8 +342,8 @@ grpc_call_error grpc_call_server_accept(grpc_call *call,
REQUIRES: Can be called at most once per call.
Can only be called on the server.
Must be called after grpc_call_server_accept */
grpc_call_error grpc_call_server_end_initial_metadata(grpc_call *call,
gpr_uint32 flags);
grpc_call_error grpc_call_server_end_initial_metadata_old(grpc_call *call,
gpr_uint32 flags);
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread. */
@ -370,9 +372,9 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
grpc_call_server_end_of_initial_metadata must have been called
successfully.
Produces a GRPC_WRITE_ACCEPTED event. */
grpc_call_error grpc_call_start_write(grpc_call *call,
grpc_byte_buffer *byte_buffer, void *tag,
gpr_uint32 flags);
grpc_call_error grpc_call_start_write_old(grpc_call *call,
grpc_byte_buffer *byte_buffer,
void *tag, gpr_uint32 flags);
/* Queue a status for writing.
REQUIRES: No other writes are pending on the call.
@ -380,17 +382,17 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
call prior to calling this.
Only callable on the server.
Produces a GRPC_FINISH_ACCEPTED event when the status is sent. */
grpc_call_error grpc_call_start_write_status(grpc_call *call,
grpc_status_code status_code,
const char *status_message,
void *tag);
grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
grpc_status_code status_code,
const char *status_message,
void *tag);
/* No more messages to send.
REQUIRES: No other writes are pending on the call.
Only callable on the client.
Produces a GRPC_FINISH_ACCEPTED event when all bytes for the call have passed
outgoing flow control. */
grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag);
grpc_call_error grpc_call_writes_done_old(grpc_call *call, void *tag);
/* Initiate a read on a call. Output event contains a byte buffer with the
result of the read.
@ -402,7 +404,7 @@ grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag);
On the server:
grpc_call_server_accept must be called before calling this.
Produces a single GRPC_READ event. */
grpc_call_error grpc_call_start_read(grpc_call *call, void *tag);
grpc_call_error grpc_call_start_read_old(grpc_call *call, void *tag);
/* Destroy a call. */
void grpc_call_destroy(grpc_call *call);
@ -414,7 +416,8 @@ void grpc_call_destroy(grpc_call *call);
tag_cancel.
REQUIRES: Server must not have been shutdown.
NOTE: calling this is the only way to obtain GRPC_SERVER_RPC_NEW events. */
grpc_call_error grpc_server_request_call(grpc_server *server, void *tag_new);
grpc_call_error grpc_server_request_call_old(grpc_server *server,
void *tag_new);
/* Create a server */
grpc_server *grpc_server_create(grpc_completion_queue *cq,

@ -56,6 +56,8 @@
#define GPR_CPU_LINUX 1
#define GPR_GCC_SYNC 1
#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
#define GPR_POSIX_WAKEUP_FD 1
#define GPR_LINUX_EVENTFD 1
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1
@ -68,7 +70,7 @@
#define GPR_GCC_ATOMIC 1
#define GPR_LINUX 1
#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
#define GPR_POSIX_HAS_SPECIAL_WAKEUP_FD 1
#define GPR_POSIX_WAKEUP_FD 1
#define GPR_LINUX_EVENTFD 1
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
@ -86,6 +88,8 @@
#define GPR_GCC_ATOMIC 1
#define GPR_POSIX_LOG 1
#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
#define GPR_POSIX_WAKEUP_FD 1
#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1

@ -44,18 +44,12 @@
#include <grpc/support/port_platform.h>
#if defined(GPR_POSIX_SYNC)
#include <grpc/support/thd_posix.h>
#elif defined(GPR_WIN32)
#include <grpc/support/thd_win32.h>
#else
#error could not determine platform for thd
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef gpr_uint64 gpr_thd_id;
/* Thread creation options. */
typedef struct {
int flags; /* Flags below can be set here. Default value 0. */
@ -72,6 +66,9 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
/* Return a gpr_thd_options struct with all fields set to defaults. */
gpr_thd_options gpr_thd_options_default(void);
/* Returns the identifier of the current thread. */
gpr_thd_id gpr_thd_currentid(void);
#ifdef __cplusplus
}
#endif

@ -1,42 +0,0 @@
/*
*
* Copyright 2014, 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.
*
*/
#ifndef __GRPC_SUPPORT_THD_POSIX_H__
#define __GRPC_SUPPORT_THD_POSIX_H__
/* Posix variant of gpr_thd_platform.h. */
#include <pthread.h>
typedef pthread_t gpr_thd_id;
#endif /* __GRPC_SUPPORT_THD_POSIX_H__ */

@ -105,6 +105,8 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
}
gpr_strvec_add(&out, gpr_strdup("\r\n"));
tmp = gpr_strvec_flatten(&out, &out_len);
gpr_strvec_destroy(&out);
if (body_bytes) {
tmp = gpr_realloc(tmp, out_len + body_size);
memcpy(tmp + out_len, body_bytes, body_size);

@ -51,6 +51,7 @@ typedef struct delayed_callback {
static gpr_mu g_mu;
static gpr_cv g_cv;
static gpr_cv g_rcv;
static delayed_callback *g_cbs_head = NULL;
static delayed_callback *g_cbs_tail = NULL;
static int g_shutdown;
@ -86,6 +87,7 @@ void grpc_iomgr_init(void) {
gpr_thd_id id;
gpr_mu_init(&g_mu);
gpr_cv_init(&g_cv);
gpr_cv_init(&g_rcv);
grpc_alarm_list_init(gpr_now());
g_refs = 0;
grpc_iomgr_platform_init();
@ -115,7 +117,7 @@ void grpc_iomgr_shutdown(void) {
gpr_mu_lock(&g_mu);
}
if (g_refs) {
if (gpr_cv_wait(&g_cv, &g_mu, shutdown_deadline) && g_cbs_head == NULL) {
if (gpr_cv_wait(&g_rcv, &g_mu, shutdown_deadline) && g_cbs_head == NULL) {
gpr_log(GPR_DEBUG,
"Failed to free %d iomgr objects before shutdown deadline: "
"memory leaks are likely",
@ -126,12 +128,14 @@ void grpc_iomgr_shutdown(void) {
}
gpr_mu_unlock(&g_mu);
grpc_kick_poller();
gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
grpc_iomgr_platform_shutdown();
grpc_alarm_list_shutdown();
gpr_mu_destroy(&g_mu);
gpr_cv_destroy(&g_cv);
gpr_cv_destroy(&g_rcv);
}
void grpc_iomgr_ref(void) {
@ -143,7 +147,7 @@ void grpc_iomgr_ref(void) {
void grpc_iomgr_unref(void) {
gpr_mu_lock(&g_mu);
if (0 == --g_refs) {
gpr_cv_signal(&g_cv);
gpr_cv_signal(&g_rcv);
}
gpr_mu_unlock(&g_mu);
}

@ -138,15 +138,18 @@ void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state) {
}
void grpc_pollset_kick_global_init_fallback_fd(void) {
gpr_mu_init(&fd_freelist_mu);
grpc_wakeup_fd_global_init_force_fallback();
}
void grpc_pollset_kick_global_init(void) {
gpr_mu_init(&fd_freelist_mu);
grpc_wakeup_fd_global_init();
}
void grpc_pollset_kick_global_destroy(void) {
grpc_wakeup_fd_global_destroy();
gpr_mu_destroy(&fd_freelist_mu);
}

@ -147,8 +147,6 @@ static int multipoll_with_poll_pollset_maybe_work(
grpc_fd_unref(h->fds[i]);
} else {
h->fds[nf++] = h->fds[i];
h->pfds[np].events =
grpc_fd_begin_poll(h->fds[i], pollset, POLLIN, POLLOUT);
h->selfds[np] = h->fds[i];
h->pfds[np].fd = h->fds[i]->fd;
h->pfds[np].revents = 0;
@ -168,6 +166,11 @@ static int multipoll_with_poll_pollset_maybe_work(
pollset->counter = 1;
gpr_mu_unlock(&pollset->mu);
for (i = 1; i < np; i++) {
h->pfds[i].events =
grpc_fd_begin_poll(h->selfds[i], pollset, POLLIN, POLLOUT);
}
r = poll(h->pfds, h->pfd_count, timeout);
if (r < 0) {
if (errno != EINTR) {

@ -75,11 +75,14 @@ static void backup_poller(void *p) {
}
void grpc_pollset_kick(grpc_pollset *p) {
if (!p->counter) return;
grpc_pollset_kick_kick(&p->kick_state);
if (p->counter) {
grpc_pollset_kick_kick(&p->kick_state);
}
}
void grpc_pollset_force_kick(grpc_pollset *p) { grpc_pollset_kick(p); }
void grpc_pollset_force_kick(grpc_pollset *p) {
grpc_pollset_kick_kick(&p->kick_state);
}
/* global state management */
@ -244,11 +247,12 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = fd->fd;
pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT);
pfd[1].revents = 0;
pollset->counter = 1;
gpr_mu_unlock(&pollset->mu);
pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT);
r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout);
if (r < 0) {
if (errno != EINTR) {
@ -269,9 +273,9 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
}
grpc_pollset_kick_post_poll(&pollset->kick_state);
grpc_fd_end_poll(fd, pollset);
gpr_mu_lock(&pollset->mu);
grpc_fd_end_poll(fd, pollset);
pollset->counter = 0;
gpr_cv_broadcast(&pollset->cv);
return 1;

@ -78,7 +78,11 @@ void grpc_pollset_add_fd(grpc_pollset *pollset, struct grpc_fd *fd);
poll after an fd is orphaned) */
void grpc_pollset_del_fd(grpc_pollset *pollset, struct grpc_fd *fd);
/* Force any current pollers to break polling */
/* Force any current pollers to break polling: it's the callers responsibility
to ensure that the pollset indeed needs to be kicked - no verification that
the pollset is actually performing polling work is done. At worst this will
result in spurious wakeups if performed at the wrong moment.
Does not touch pollset->mu. */
void grpc_pollset_force_kick(grpc_pollset *pollset);
/* Returns the fd to listen on for kicks */
int grpc_kick_read_fd(grpc_pollset *p);

@ -74,7 +74,7 @@ static int eventfd_check_availability(void) {
return 1;
}
const grpc_wakeup_fd_vtable specialized_wakeup_fd_vtable = {
const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy,
eventfd_check_availability
};

@ -38,16 +38,17 @@
#include <grpc/support/port_platform.h>
#ifndef GPR_POSIX_HAS_SPECIAL_WAKEUP_FD
#ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD
#include "src/core/iomgr/wakeup_fd.h"
#include "src/core/iomgr/wakeup_fd_posix.h"
#include <stddef.h>
static int check_availability_invalid(void) {
return 0;
}
const grpc_wakeup_fd_vtable specialized_wakeup_fd_vtable = {
const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
NULL, NULL, NULL, NULL, check_availability_invalid
};
#endif /* GPR_POSIX_HAS_SPECIAL_WAKEUP */
#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */

@ -31,7 +31,10 @@
*
*/
/* TODO(klempner): Allow this code to be disabled. */
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_WAKEUP_FD
#include "src/core/iomgr/wakeup_fd_posix.h"
#include <errno.h>
@ -87,7 +90,8 @@ static int pipe_check_availability(void) {
return 1;
}
const grpc_wakeup_fd_vtable pipe_wakeup_fd_vtable = {
const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = {
pipe_create, pipe_consume, pipe_wakeup, pipe_destroy, pipe_check_availability
};
#endif /* GPR_POSIX_WAKUP_FD */

@ -36,6 +36,6 @@
#include "src/core/iomgr/wakeup_fd_posix.h"
extern grpc_wakeup_fd_vtable pipe_wakeup_fd_vtable;
extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
#endif /* __GRPC_INTERNAL_IOMGR_WAKEUP_FD_PIPE_H_ */

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_WAKEUP_FD
#include "src/core/iomgr/wakeup_fd_posix.h"
#include "src/core/iomgr/wakeup_fd_pipe.h"
#include <stddef.h>
@ -38,15 +42,15 @@
static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL;
void grpc_wakeup_fd_global_init(void) {
if (specialized_wakeup_fd_vtable.check_availability()) {
wakeup_fd_vtable = &specialized_wakeup_fd_vtable;
if (grpc_specialized_wakeup_fd_vtable.check_availability()) {
wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable;
} else {
wakeup_fd_vtable = &pipe_wakeup_fd_vtable;
wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
}
}
void grpc_wakeup_fd_global_init_force_fallback(void) {
wakeup_fd_vtable = &pipe_wakeup_fd_vtable;
wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
}
void grpc_wakeup_fd_global_destroy(void) {
@ -68,3 +72,5 @@ void grpc_wakeup_fd_wakeup(grpc_wakeup_fd_info *fd_info) {
void grpc_wakeup_fd_destroy(grpc_wakeup_fd_info *fd_info) {
wakeup_fd_vtable->destroy(fd_info);
}
#endif /* GPR_POSIX_WAKEUP_FD */

@ -62,29 +62,14 @@
#ifndef __GRPC_INTERNAL_IOMGR_WAKEUP_FD_POSIX_H_
#define __GRPC_INTERNAL_IOMGR_WAKEUP_FD_POSIX_H_
typedef struct grpc_wakeup_fd_info grpc_wakeup_fd_info;
void grpc_wakeup_fd_global_init(void);
void grpc_wakeup_fd_global_destroy(void);
void grpc_wakeup_fd_create(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_wakeup(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_destroy(grpc_wakeup_fd_info *fd_info);
#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
/* Force using the fallback implementation. This is intended for testing
* purposes only.*/
void grpc_wakeup_fd_global_init_force_fallback(void);
/* Private structures; don't access their fields directly outside of wakeup fd
* code. */
struct grpc_wakeup_fd_info {
int read_fd;
int write_fd;
};
typedef struct grpc_wakeup_fd_info grpc_wakeup_fd_info;
typedef struct grpc_wakeup_fd_vtable {
void (*create)(grpc_wakeup_fd_info *fd_info);
@ -95,8 +80,20 @@ typedef struct grpc_wakeup_fd_vtable {
int (*check_availability)(void);
} grpc_wakeup_fd_vtable;
struct grpc_wakeup_fd_info {
int read_fd;
int write_fd;
};
#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
void grpc_wakeup_fd_create(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_wakeup(grpc_wakeup_fd_info *fd_info);
void grpc_wakeup_fd_destroy(grpc_wakeup_fd_info *fd_info);
/* Defined in some specialized implementation's .c file, or by
* wakeup_fd_nospecial.c if no such implementation exists. */
extern const grpc_wakeup_fd_vtable specialized_wakeup_fd_vtable;
extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable;
#endif /* __GRPC_INTERNAL_IOMGR_WAKEUP_FD_POSIX_H_ */

@ -31,44 +31,17 @@
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif /* _GNU_SOURCE */
#include <grpc/support/port_platform.h>
#ifdef GPR_CPU_LINUX
#include "src/core/support/cpu.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define GRPC_GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#define GRPC_USE_GNU
#endif
#ifndef __USE_MISC
#define __USE_MISC
#define GRPC_USE_MISC
#endif
#include <sched.h>
#ifdef GRPC_GNU_SOURCE
#undef _GNU_SOURCE
#undef GRPC_GNU_SOURCE
#endif
#ifdef GRPC_USE_GNU
#undef __USE_GNU
#undef GRPC_USE_GNU
#endif
#ifdef GRPC_USE_MISC
#undef __USE_MISC
#undef GRPC_USE_MISC
#endif
#include <errno.h>
#include <unistd.h>
#include <string.h>

@ -64,7 +64,7 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
va_end(args);
if (ret < 0) {
message = NULL;
} else if (ret <= sizeof(buf) - 1) {
} else if ((size_t)ret <= sizeof(buf) - 1) {
message = buf;
} else {
message = allocated = gpr_malloc(ret + 1);

@ -62,17 +62,19 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
const gpr_thd_options *options) {
int thread_started;
pthread_attr_t attr;
pthread_t p;
struct thd_arg *a = gpr_malloc(sizeof(*a));
a->body = thd_body;
a->arg = arg;
GPR_ASSERT(pthread_attr_init(&attr) == 0);
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
thread_started = (pthread_create(t, &attr, &thread_body, a) == 0);
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!thread_started) {
gpr_free(a);
}
*t = (gpr_thd_id)p;
return thread_started;
}
@ -82,4 +84,8 @@ gpr_thd_options gpr_thd_options_default(void) {
return options;
}
gpr_thd_id gpr_thd_currentid(void) {
return (gpr_thd_id)pthread_self();
}
#endif /* GPR_POSIX_SYNC */

@ -58,16 +58,18 @@ static DWORD WINAPI thread_body(void *v) {
int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
const gpr_thd_options *options) {
HANDLE handle;
DWORD thread_id;
struct thd_arg *a = gpr_malloc(sizeof(*a));
a->body = thd_body;
a->arg = arg;
*t = 0;
handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, NULL);
handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, &thread_id);
if (handle == NULL) {
gpr_free(a);
} else {
CloseHandle(handle); /* threads are "detached" */
}
*t = (gpr_thd_id)thread_id;
return handle != NULL;
}
@ -77,4 +79,8 @@ gpr_thd_options gpr_thd_options_default(void) {
return options;
}
gpr_thd_id gpr_thd_currentid(void) {
return (gpr_thd_id)GetCurrentThreadId();
}
#endif /* GPR_WIN32 */

@ -348,8 +348,9 @@ void grpc_call_add_mdelem(grpc_call *call, grpc_mdelem *mdelem,
elem->filter->call_op(elem, NULL, &op);
}
grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
gpr_uint32 flags) {
grpc_call_error grpc_call_add_metadata_old(grpc_call *call,
grpc_metadata *metadata,
gpr_uint32 flags) {
grpc_mdelem *mdelem;
if (call->is_client) {
@ -455,9 +456,9 @@ static void call_started(void *user_data, grpc_op_error error) {
grpc_call_internal_unref(call);
}
grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag, void *finished_tag,
gpr_uint32 flags) {
grpc_call_error grpc_call_invoke_old(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag,
void *finished_tag, gpr_uint32 flags) {
grpc_call_element *elem;
grpc_call_op op;
@ -527,9 +528,9 @@ grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
return GRPC_CALL_OK;
}
grpc_call_error grpc_call_server_accept(grpc_call *call,
grpc_completion_queue *cq,
void *finished_tag) {
grpc_call_error grpc_call_server_accept_old(grpc_call *call,
grpc_completion_queue *cq,
void *finished_tag) {
/* validate preconditions */
if (call->is_client) {
gpr_log(GPR_ERROR, "can only call %s on servers", __FUNCTION__);
@ -563,8 +564,8 @@ grpc_call_error grpc_call_server_accept(grpc_call *call,
return GRPC_CALL_OK;
}
grpc_call_error grpc_call_server_end_initial_metadata(grpc_call *call,
gpr_uint32 flags) {
grpc_call_error grpc_call_server_end_initial_metadata_old(grpc_call *call,
gpr_uint32 flags) {
grpc_call_element *elem;
grpc_call_op op;
@ -634,7 +635,7 @@ static void request_more_data(grpc_call *call) {
elem->filter->call_op(elem, NULL, &op);
}
grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
grpc_call_error grpc_call_start_read_old(grpc_call *call, void *tag) {
gpr_uint8 request_more = 0;
switch (call->state) {
@ -677,9 +678,9 @@ grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
return GRPC_CALL_OK;
}
grpc_call_error grpc_call_start_write(grpc_call *call,
grpc_byte_buffer *byte_buffer, void *tag,
gpr_uint32 flags) {
grpc_call_error grpc_call_start_write_old(grpc_call *call,
grpc_byte_buffer *byte_buffer,
void *tag, gpr_uint32 flags) {
grpc_call_element *elem;
grpc_call_op op;
@ -732,7 +733,7 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
return GRPC_CALL_OK;
}
grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
grpc_call_error grpc_call_writes_done_old(grpc_call *call, void *tag) {
grpc_call_element *elem;
grpc_call_op op;
@ -780,9 +781,10 @@ grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
return GRPC_CALL_OK;
}
grpc_call_error grpc_call_start_write_status(grpc_call *call,
grpc_status_code status,
const char *details, void *tag) {
grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
grpc_status_code status,
const char *details,
void *tag) {
grpc_call_element *elem;
grpc_call_op op;

@ -74,9 +74,9 @@ grpc_channel *grpc_channel_create_from_filters(
static void do_nothing(void *ignored, grpc_op_error error) {}
grpc_call *grpc_channel_create_call(grpc_channel *channel, const char *method,
const char *host,
gpr_timespec absolute_deadline) {
grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
const char *method, const char *host,
gpr_timespec absolute_deadline) {
grpc_call *call;
grpc_mdelem *path_mdelem;
grpc_mdelem *authority_mdelem;

@ -625,7 +625,8 @@ void grpc_server_add_listener(grpc_server *server, void *arg,
server->listeners = l;
}
grpc_call_error grpc_server_request_call(grpc_server *server, void *tag_new) {
grpc_call_error grpc_server_request_call_old(grpc_server *server,
void *tag_new) {
call_data *calld;
grpc_cq_begin_op(server->cq, NULL, GRPC_SERVER_RPC_NEW);

@ -37,6 +37,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "src/core/tsi/transport_security.h"
@ -103,11 +104,32 @@ typedef struct {
/* --- Library Initialization. ---*/
static gpr_once init_openssl_once = GPR_ONCE_INIT;
static gpr_mu *openssl_mutexes = NULL;
static void openssl_locking_cb(int mode, int type, const char* file, int line) {
if (mode & CRYPTO_LOCK) {
gpr_mu_lock(&openssl_mutexes[type]);
} else {
gpr_mu_unlock(&openssl_mutexes[type]);
}
}
static unsigned long openssl_thread_id_cb(void) {
return (unsigned long)gpr_thd_currentid();
}
static void init_openssl(void) {
int i;
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
openssl_mutexes = malloc(CRYPTO_num_locks() * sizeof(gpr_mu));
GPR_ASSERT(openssl_mutexes != NULL);
for (i = 0; i < CRYPTO_num_locks(); i++) {
gpr_mu_init(&openssl_mutexes[i]);
}
CRYPTO_set_locking_callback(openssl_locking_cb);
CRYPTO_set_id_callback(openssl_thread_id_cb);
}
/* --- Ssl utils. ---*/

@ -99,7 +99,7 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
const google::protobuf::Message &request,
google::protobuf::Message *result) {
Status status;
grpc_call *call = grpc_channel_create_call(
grpc_call *call = grpc_channel_create_call_old(
c_channel_, method.name(), target_.c_str(), context->RawDeadline());
context->set_call(call);
grpc_event *ev;
@ -114,8 +114,8 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
// add_metadata from context
//
// invoke
GPR_ASSERT(grpc_call_invoke(call, cq, metadata_read_tag, finished_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_invoke_old(call, cq, metadata_read_tag, finished_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
// write request
grpc_byte_buffer *write_buffer = nullptr;
bool success = SerializeProto(request, &write_buffer);
@ -126,8 +126,8 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
GetFinalStatus(cq, finished_tag, nullptr);
return status;
}
GPR_ASSERT(grpc_call_start_write(call, write_buffer, write_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_start_write_old(call, write_buffer, write_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
grpc_byte_buffer_destroy(write_buffer);
ev = grpc_completion_queue_pluck(cq, write_tag, gpr_inf_future);
@ -138,7 +138,7 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
return status;
}
// writes done
GPR_ASSERT(grpc_call_writes_done(call, halfclose_tag) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_writes_done_old(call, halfclose_tag) == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq, halfclose_tag, gpr_inf_future);
grpc_event_finish(ev);
// start read metadata
@ -146,7 +146,7 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
ev = grpc_completion_queue_pluck(cq, metadata_read_tag, gpr_inf_future);
grpc_event_finish(ev);
// start read
GPR_ASSERT(grpc_call_start_read(call, read_tag) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_start_read_old(call, read_tag) == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq, read_tag, gpr_inf_future);
if (ev->data.read) {
if (!DeserializeProto(ev->data.read, result)) {
@ -167,7 +167,7 @@ StreamContextInterface *Channel::CreateStream(
const RpcMethod &method, ClientContext *context,
const google::protobuf::Message *request,
google::protobuf::Message *result) {
grpc_call *call = grpc_channel_create_call(
grpc_call *call = grpc_channel_create_call_old(
c_channel_, method.name(), target_.c_str(), context->RawDeadline());
context->set_call(call);
grpc_completion_queue *cq = grpc_completion_queue_create();

@ -72,7 +72,7 @@ void AsyncServer::RequestOneRpc() {
return;
}
lock.unlock();
grpc_call_error err = grpc_server_request_call(server_, nullptr);
grpc_call_error err = grpc_server_request_call_old(server_, nullptr);
GPR_ASSERT(err == GRPC_CALL_OK);
}

@ -53,14 +53,15 @@ AsyncServerContext::AsyncServerContext(
AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
void AsyncServerContext::Accept(grpc_completion_queue *cq) {
GPR_ASSERT(grpc_call_server_accept(call_, cq, this) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_end_initial_metadata(call_, GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_accept_old(call_, cq, this) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_end_initial_metadata_old(call_, GRPC_WRITE_BUFFER_HINT) ==
GRPC_CALL_OK);
}
bool AsyncServerContext::StartRead(google::protobuf::Message *request) {
GPR_ASSERT(request);
request_ = request;
grpc_call_error err = grpc_call_start_read(call_, this);
grpc_call_error err = grpc_call_start_read_old(call_, this);
return err == GRPC_CALL_OK;
}
@ -70,13 +71,13 @@ bool AsyncServerContext::StartWrite(const google::protobuf::Message &response,
if (!SerializeProto(response, &buffer)) {
return false;
}
grpc_call_error err = grpc_call_start_write(call_, buffer, this, flags);
grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
grpc_byte_buffer_destroy(buffer);
return err == GRPC_CALL_OK;
}
bool AsyncServerContext::StartWriteStatus(const Status &status) {
grpc_call_error err = grpc_call_start_write_status(
grpc_call_error err = grpc_call_start_write_status_old(
call_, static_cast<grpc_status_code>(status.code()),
status.details().empty() ? nullptr
: const_cast<char *>(status.details().c_str()),

@ -111,7 +111,7 @@ void Server::Start() {
void Server::AllowOneRpc() {
GPR_ASSERT(started_);
grpc_call_error err = grpc_server_request_call(server_, nullptr);
grpc_call_error err = grpc_server_request_call_old(server_, nullptr);
GPR_ASSERT(err == GRPC_CALL_OK);
}

@ -80,22 +80,22 @@ void StreamContext::Start(bool buffered) {
if (is_client_) {
// TODO(yangg) handle metadata send path
int flag = buffered ? GRPC_WRITE_BUFFER_HINT : 0;
grpc_call_error error = grpc_call_invoke(
grpc_call_error error = grpc_call_invoke_old(
call(), cq(), client_metadata_read_tag(), finished_tag(), flag);
GPR_ASSERT(GRPC_CALL_OK == error);
} else {
// TODO(yangg) metadata needs to be added before accept
// TODO(yangg) correctly set flag to accept
GPR_ASSERT(grpc_call_server_accept(call(), cq(), finished_tag()) ==
GPR_ASSERT(grpc_call_server_accept_old(call(), cq(), finished_tag()) ==
GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_end_initial_metadata(call(), 0) ==
GPR_ASSERT(grpc_call_server_end_initial_metadata_old(call(), 0) ==
GRPC_CALL_OK);
}
}
bool StreamContext::Read(google::protobuf::Message *msg) {
// TODO(yangg) check peer_halfclosed_ here for possible early return.
grpc_call_error err = grpc_call_start_read(call(), read_tag());
grpc_call_error err = grpc_call_start_read_old(call(), read_tag());
GPR_ASSERT(err == GRPC_CALL_OK);
grpc_event *read_ev =
grpc_completion_queue_pluck(cq(), read_tag(), gpr_inf_future);
@ -129,7 +129,7 @@ bool StreamContext::Write(const google::protobuf::Message *msg, bool is_last) {
}
int flag = is_last ? GRPC_WRITE_BUFFER_HINT : 0;
grpc_call_error err =
grpc_call_start_write(call(), out_buf, write_tag(), flag);
grpc_call_start_write_old(call(), out_buf, write_tag(), flag);
grpc_byte_buffer_destroy(out_buf);
GPR_ASSERT(err == GRPC_CALL_OK);
@ -140,7 +140,7 @@ bool StreamContext::Write(const google::protobuf::Message *msg, bool is_last) {
grpc_event_finish(ev);
}
if (ret && is_last) {
grpc_call_error err = grpc_call_writes_done(call(), halfclose_tag());
grpc_call_error err = grpc_call_writes_done_old(call(), halfclose_tag());
GPR_ASSERT(err == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq(), halfclose_tag(), gpr_inf_future);
GPR_ASSERT(ev->type == GRPC_FINISH_ACCEPTED);

@ -0,0 +1,2 @@
*.userprefs
test-results

@ -0,0 +1,22 @@
gRPC C#
=======
A C# implementation of gRPC, Google's RPC library.
EXPERIMENTAL ONLY
-----------------
**This gRPC C# implementation is work-in-progress and is not expected to work yet.**
- The implementation is a wrapper around gRPC C core library
- Code only runs under mono currently, building gGRPC C core library under Windows
is in progress.
- It is very possible that some parts of the code will be heavily refactored or
completely rewritten.
CONTENTS
--------
- ext:
The extension library that wraps C API to be more digestible by C#.

@ -0,0 +1,113 @@
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <string.h>
grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len);
grpc_byte_buffer *bb = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);
return bb;
}
void grpc_call_start_write_from_copied_buffer(grpc_call *call,
const char *buffer, size_t len,
void *tag, gpr_uint32 flags) {
grpc_byte_buffer *byte_buffer = string_to_byte_buffer(buffer, len);
GPR_ASSERT(grpc_call_start_write_old(call, byte_buffer, tag, flags) ==
GRPC_CALL_OK);
grpc_byte_buffer_destroy(byte_buffer);
}
grpc_completion_type grpc_event_type(const grpc_event *event) {
return event->type;
}
grpc_op_error grpc_event_write_accepted(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_WRITE_ACCEPTED);
return event->data.invoke_accepted;
}
grpc_op_error grpc_event_finish_accepted(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISH_ACCEPTED);
return event->data.finish_accepted;
}
grpc_status_code grpc_event_finished_status(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISHED);
return event->data.finished.status;
}
const char *grpc_event_finished_details(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_FINISHED);
return event->data.finished.details;
}
gpr_intptr grpc_event_read_length(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_READ);
if (!event->data.read) {
return -1;
}
return grpc_byte_buffer_length(event->data.read);
}
/*
* Copies data from read event to a buffer. Fatal error occurs if
* buffer is too small.
*/
void grpc_event_read_copy_to_buffer(const grpc_event *event, char *buffer,
size_t buffer_len) {
grpc_byte_buffer_reader *reader;
gpr_slice slice;
size_t offset = 0;
GPR_ASSERT(event->type == GRPC_READ);
reader = grpc_byte_buffer_reader_create(event->data.read);
GPR_ASSERT(event->data.read);
while (grpc_byte_buffer_reader_next(reader, &slice)) {
size_t len = GPR_SLICE_LENGTH(slice);
GPR_ASSERT(offset + len <= buffer_len);
memcpy(buffer + offset, GPR_SLICE_START_PTR(slice),
GPR_SLICE_LENGTH(slice));
offset += len;
gpr_slice_unref(slice);
}
grpc_byte_buffer_reader_destroy(reader);
}
grpc_call *grpc_event_call(const grpc_event *event) {
/* we only allow this for newly incoming server calls. */
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
return event->call;
}
const char *grpc_event_server_rpc_new_method(const grpc_event *event) {
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
return event->data.server_rpc_new.method;
}
grpc_completion_type grpc_completion_queue_next_with_callback(
grpc_completion_queue *cq) {
grpc_event *ev;
grpc_completion_type t;
void (*callback)(grpc_event *);
ev = grpc_completion_queue_next(cq, gpr_inf_future);
t = ev->type;
if (ev->tag) {
/* call the callback in ev->tag */
/* C forbids to cast object pointers to function pointers, so
* we cast to intptr first.
*/
callback = (void (*)(grpc_event *))(gpr_intptr)ev->tag;
(*callback)(ev);
}
grpc_event_finish(ev);
/* return completion type to allow some handling for events that have no
* tag - such as GRPC_QUEUE_SHUTDOWN
*/
return t;
}

@ -0,0 +1,2 @@
build
node_modules

@ -152,9 +152,9 @@ NAN_METHOD(Call::New) {
NanUtf8String method(args[1]);
double deadline = args[2]->NumberValue();
grpc_channel *wrapped_channel = channel->GetWrappedChannel();
grpc_call *wrapped_call =
grpc_channel_create_call(wrapped_channel, *method, channel->GetHost(),
MillisecondsToTimespec(deadline));
grpc_call *wrapped_call = grpc_channel_create_call_old(
wrapped_channel, *method, channel->GetHost(),
MillisecondsToTimespec(deadline));
call = new Call(wrapped_call);
args.This()->SetHiddenValue(String::NewSymbol("channel_"),
channel_object);
@ -195,7 +195,7 @@ NAN_METHOD(Call::AddMetadata) {
if (Buffer::HasInstance(value)) {
metadata.value = Buffer::Data(value);
metadata.value_length = Buffer::Length(value);
error = grpc_call_add_metadata(call->wrapped_call, &metadata, 0);
error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
} else if (value->IsString()) {
Handle<String> string_value = value->ToString();
NanUtf8String utf8_value(string_value);
@ -203,7 +203,7 @@ NAN_METHOD(Call::AddMetadata) {
metadata.value_length = string_value->Length();
gpr_log(GPR_DEBUG, "adding metadata: %s, %s, %d", metadata.key,
metadata.value, metadata.value_length);
error = grpc_call_add_metadata(call->wrapped_call, &metadata, 0);
error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
} else {
return NanThrowTypeError(
"addMetadata values must be strings or buffers");
@ -232,7 +232,7 @@ NAN_METHOD(Call::Invoke) {
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
unsigned int flags = args[3]->Uint32Value();
grpc_call_error error = grpc_call_invoke(
grpc_call_error error = grpc_call_invoke_old(
call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags);
if (error == GRPC_CALL_OK) {
@ -253,7 +253,7 @@ NAN_METHOD(Call::ServerAccept) {
return NanThrowTypeError("accept's first argument must be a function");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
grpc_call_error error = grpc_call_server_accept(
grpc_call_error error = grpc_call_server_accept_old(
call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
CreateTag(args[0], args.This()));
if (error == GRPC_CALL_OK) {
@ -277,7 +277,7 @@ NAN_METHOD(Call::ServerEndInitialMetadata) {
Call *call = ObjectWrap::Unwrap<Call>(args.This());
unsigned int flags = args[1]->Uint32Value();
grpc_call_error error =
grpc_call_server_end_initial_metadata(call->wrapped_call, flags);
grpc_call_server_end_initial_metadata_old(call->wrapped_call, flags);
if (error != GRPC_CALL_OK) {
return NanThrowError("serverEndInitialMetadata failed", error);
}
@ -315,7 +315,7 @@ NAN_METHOD(Call::StartWrite) {
Call *call = ObjectWrap::Unwrap<Call>(args.This());
grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]);
unsigned int flags = args[2]->Uint32Value();
grpc_call_error error = grpc_call_start_write(
grpc_call_error error = grpc_call_start_write_old(
call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags);
if (error == GRPC_CALL_OK) {
CompletionQueueAsyncWorker::Next();
@ -345,7 +345,7 @@ NAN_METHOD(Call::StartWriteStatus) {
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
NanUtf8String details(args[1]);
grpc_call_error error = grpc_call_start_write_status(
grpc_call_error error = grpc_call_start_write_status_old(
call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details,
CreateTag(args[2], args.This()));
if (error == GRPC_CALL_OK) {
@ -365,7 +365,7 @@ NAN_METHOD(Call::WritesDone) {
return NanThrowTypeError("writesDone's first argument must be a function");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
grpc_call_error error = grpc_call_writes_done(
grpc_call_error error = grpc_call_writes_done_old(
call->wrapped_call, CreateTag(args[0], args.This()));
if (error == GRPC_CALL_OK) {
CompletionQueueAsyncWorker::Next();
@ -384,8 +384,8 @@ NAN_METHOD(Call::StartRead) {
return NanThrowTypeError("startRead's first argument must be a function");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
grpc_call_error error =
grpc_call_start_read(call->wrapped_call, CreateTag(args[0], args.This()));
grpc_call_error error = grpc_call_start_read_old(
call->wrapped_call, CreateTag(args[0], args.This()));
if (error == GRPC_CALL_OK) {
CompletionQueueAsyncWorker::Next();
} else {

@ -175,7 +175,7 @@ NAN_METHOD(Server::RequestCall) {
return NanThrowTypeError("requestCall can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
grpc_call_error error = grpc_server_request_call(
grpc_call_error error = grpc_server_request_call_old(
server->wrapped_server, CreateTag(args[0], NanNull()));
if (error == GRPC_CALL_OK) {
CompletionQueueAsyncWorker::Next();

@ -7,31 +7,25 @@ Directory structure is as generated by the PHP utility
## ENVIRONMENT
To build a PHP environment that works with this extension, download and extract
PHP 5.5 (5.6 may also work), configure it, and install it:
Install `php5` and `php5-dev`.
```bash
apt-get install libxml2 libxml2-dev
curl http://php.net/get/php-5.5.16.tar.gz
tar -xf php-5.5.16.tar.gz
cd php-5.5.16
./configure --with-zlib=/usr --with-libxml-dir=ext/libxml --with-openssl=/usr/local/ssl
make
make install
```
To run the tests, additionally install `php5-readline` and `phpunit`.
Alternatively, build and install PHP 5.5 or later from source with standard
configuration options.
To also download and install the patched protoc and PHP code generator:
To also download and install protoc and the PHP code generator.
```bash
apt-get install -y procps
curl -sSL https://get.rvm.io | sudo bash -s stable --ruby
git clone sso://team/one-platform-grpc-team/protobuf
git clone git@github.com:google/protobuf.git
cd protobuf
./configure
make
make install
git clone sso://team/one-platform-grpc-team/grpc-php-protobuf-php
cd grpc-php-protobuf-php
git clone git@github.com:murgatroid99/Protobuf-PHP.git
cd Protobuf-PHP
rake pear:package version=1.0
pear install Protobuf-1.0.tgz
```
@ -52,5 +46,4 @@ This repo now has PHPUnit tests, which can by run by executing
There is also a generated code test (`./bin/run_gen_code_test.sh`), which tests
the stub `./tests/generated_code/math.php` against a running localhost server
serving the math service. That stub is generated from
`./tests/generated_code/math.proto` with the head of the repo
`sso://team/one-platform-grpc-team/grpc-php-protobuf-php`.
`./tests/generated_code/math.proto`.

@ -85,73 +85,25 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
memcpy(str_val, elem->value, elem->value_length);
if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
SUCCESS) {
switch (Z_TYPE_P(*data)) {
case IS_STRING:
MAKE_STD_ZVAL(inner_array);
array_init(inner_array);
add_next_index_zval(inner_array, *data);
add_assoc_zval(array, str_key, inner_array);
break;
case IS_ARRAY:
inner_array = *data;
break;
default:
zend_throw_exception(zend_exception_get_default(),
"Metadata hash somehow contains wrong types.",
1 TSRMLS_CC);
if (Z_TYPE_P(*data) != IS_ARRAY) {
zend_throw_exception(zend_exception_get_default(),
"Metadata hash somehow contains wrong types.",
1 TSRMLS_CC);
efree(str_key);
efree(str_val);
return NULL;
}
add_next_index_stringl(inner_array, str_val, elem->value_length, false);
add_next_index_stringl(*data, str_val, elem->value_length, false);
} else {
add_assoc_stringl(array, str_key, str_val, elem->value_length, false);
MAKE_STD_ZVAL(inner_array);
array_init(inner_array);
add_next_index_stringl(inner_array, str_val, elem->value_length, false);
add_assoc_zval(array, str_key, inner_array);
}
}
return array;
}
int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC, int num_args,
va_list args,
zend_hash_key *hash_key) {
grpc_call_error error_code;
zval **data = (zval **)elem;
grpc_metadata metadata;
grpc_call *call = va_arg(args, grpc_call *);
gpr_uint32 flags = va_arg(args, gpr_uint32);
const char *key;
HashTable *inner_hash;
/* We assume that either two args were passed, and we are in the recursive
case (and the second argument is the key), or one arg was passed and
hash_key is the string key. */
if (num_args > 2) {
key = va_arg(args, const char *);
} else {
/* TODO(mlumish): If possible, check that hash_key is a string */
key = hash_key->arKey;
}
switch (Z_TYPE_P(*data)) {
case IS_STRING:
metadata.key = (char *)key;
metadata.value = Z_STRVAL_P(*data);
metadata.value_length = Z_STRLEN_P(*data);
error_code = grpc_call_add_metadata(call, &metadata, 0u);
MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
break;
case IS_ARRAY:
inner_hash = Z_ARRVAL_P(*data);
zend_hash_apply_with_arguments(inner_hash TSRMLS_CC,
php_grpc_call_add_metadata_array_walk, 3,
call, flags, key);
break;
default:
zend_throw_exception(zend_exception_get_default(),
"Metadata hash somehow contains wrong types.",
1 TSRMLS_CC);
}
return ZEND_HASH_APPLY_KEEP;
}
/**
* Constructs a new instance of the Call class.
* @param Channel $channel The channel to associate the call with. Must not be
@ -188,8 +140,8 @@ PHP_METHOD(Call, __construct) {
wrapped_grpc_timeval *deadline =
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
call->wrapped = grpc_channel_create_call(channel->wrapped, method,
channel->target, deadline->wrapped);
call->wrapped = grpc_channel_create_call_old(
channel->wrapped, method, channel->target, deadline->wrapped);
}
/**
@ -204,8 +156,18 @@ PHP_METHOD(Call, __construct) {
PHP_METHOD(Call, add_metadata) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_metadata metadata;
grpc_call_error error_code;
zval *array;
zval **inner_array;
zval **value;
HashTable *array_hash;
HashPosition array_pointer;
HashTable *inner_array_hash;
HashPosition inner_array_pointer;
char *key;
uint key_len;
ulong index;
long flags = 0;
/* "a|l" == 1 array, 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) ==
@ -216,9 +178,41 @@ PHP_METHOD(Call, add_metadata) {
return;
}
array_hash = Z_ARRVAL_P(array);
zend_hash_apply_with_arguments(array_hash TSRMLS_CC,
php_grpc_call_add_metadata_array_walk, 2,
call->wrapped, (gpr_uint32)flags);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata keys must be strings", 1 TSRMLS_CC);
return;
}
if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata values must be arrays",
1 TSRMLS_CC);
return;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
&inner_array_pointer);
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
&inner_array_pointer) == SUCCESS;
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
if (Z_TYPE_P(*value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata values must be arrays of strings",
1 TSRMLS_CC);
return;
}
metadata.key = key;
metadata.value = Z_STRVAL_P(*value);
metadata.value_length = Z_STRLEN_P(*value);
error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u);
MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
}
}
}
/**
@ -252,8 +246,8 @@ PHP_METHOD(Call, invoke) {
wrapped_grpc_completion_queue *queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(
queue_obj TSRMLS_CC);
error_code = grpc_call_invoke(call->wrapped, queue->wrapped, (void *)tag1,
(void *)tag2, (gpr_uint32)flags);
error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1,
(void *)tag2, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(invoke, error_code);
}
@ -287,7 +281,7 @@ PHP_METHOD(Call, server_accept) {
(wrapped_grpc_completion_queue *)zend_object_store_get_object(
queue_obj TSRMLS_CC);
error_code =
grpc_call_server_accept(call->wrapped, queue->wrapped, (void *)tag);
grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(server_accept, error_code);
}
@ -303,7 +297,7 @@ PHP_METHOD(Call, server_end_initial_metadata) {
}
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
error_code = grpc_call_server_end_initial_metadata(call->wrapped, flags);
error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags);
MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
}
@ -342,9 +336,9 @@ PHP_METHOD(Call, start_write) {
1 TSRMLS_CC);
return;
}
error_code = grpc_call_start_write(call->wrapped,
string_to_byte_buffer(buffer, buffer_len),
(void *)tag, (gpr_uint32)flags);
error_code = grpc_call_start_write_old(
call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag,
(gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(start_write, error_code);
}
@ -372,9 +366,9 @@ PHP_METHOD(Call, start_write_status) {
"start_write_status expects a long, a string, and a long", 1 TSRMLS_CC);
return;
}
error_code =
grpc_call_start_write_status(call->wrapped, (grpc_status_code)status_code,
status_details, (void *)tag);
error_code = grpc_call_start_write_status_old(call->wrapped,
(grpc_status_code)status_code,
status_details, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
}
@ -393,7 +387,7 @@ PHP_METHOD(Call, writes_done) {
"writes_done expects a long", 1 TSRMLS_CC);
return;
}
error_code = grpc_call_writes_done(call->wrapped, (void *)tag);
error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(writes_done, error_code);
}
@ -414,7 +408,7 @@ PHP_METHOD(Call, start_read) {
"start_read expects a long", 1 TSRMLS_CC);
return;
}
error_code = grpc_call_start_read(call->wrapped, (void *)tag);
error_code = grpc_call_start_read_old(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_read, error_code);
}

@ -19,6 +19,7 @@
zend_throw_exception(spl_ce_LogicException, \
#func_name " was called incorrectly", \
(long)error_code TSRMLS_CC); \
return; \
} \
} while (0)

@ -125,7 +125,7 @@ PHP_METHOD(Server, request_call) {
"request_call expects a long", 1 TSRMLS_CC);
return;
}
error_code = grpc_server_request_call(server->wrapped, (void *)tag_new);
error_code = grpc_server_request_call_old(server->wrapped, (void *)tag_new);
MAYBE_THROW_CALL_ERROR(request_call, error_code);
}
@ -146,7 +146,7 @@ PHP_METHOD(Server, add_http2_port) {
"add_http2_port expects a string", 1 TSRMLS_CC);
return;
}
RETURN_BOOL(grpc_server_add_http2_port(server->wrapped, addr));
RETURN_LONG(grpc_server_add_http2_port(server->wrapped, addr));
}
PHP_METHOD(Server, add_secure_http2_port) {
@ -161,7 +161,7 @@ PHP_METHOD(Server, add_secure_http2_port) {
"add_http2_port expects a string", 1 TSRMLS_CC);
return;
}
RETURN_BOOL(grpc_server_add_secure_http2_port(server->wrapped, addr));
RETURN_LONG(grpc_server_add_secure_http2_port(server->wrapped, addr));
}
/**

@ -44,7 +44,7 @@ abstract class AbstractSurfaceActiveCall {
protected function _read() {
$response = $this->active_call->read();
if ($response == null) {
if ($response === null) {
return null;
}
return call_user_func($this->deserialize, $response);

@ -66,12 +66,7 @@ class ActiveCall {
* @param ByteBuffer $data The data to write
*/
public function write($data) {
if($this->call->start_write($data,
WRITE_ACCEPTED,
$this->flags) != OP_OK) {
// TODO(mlumish): more useful error
throw new \Exception("Cannot call write after writesDone");
}
$this->call->start_write($data, WRITE_ACCEPTED, $this->flags);
$this->completion_queue->pluck(WRITE_ACCEPTED, Timeval::inf_future());
}

@ -31,7 +31,7 @@ class ServerStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
* @return An iterator of response values
*/
public function responses() {
while(($response = $this->_read()) != null) {
while(($response = $this->_read()) !== null) {
yield $response;
}
}

@ -17,9 +17,9 @@ class GeneratedCodeTest extends PHPUnit_Framework_TestCase {
$div_arg->setDividend(7);
$div_arg->setDivisor(4);
list($response, $status) = self::$client->Div($div_arg)->wait();
$this->assertEquals(1, $response->getQuotient());
$this->assertEquals(3, $response->getRemainder());
$this->assertEquals(\Grpc\STATUS_OK, $status->code);
$this->assertSame(1, $response->getQuotient());
$this->assertSame(3, $response->getRemainder());
$this->assertSame(\Grpc\STATUS_OK, $status->code);
}
public function testServerStreaming() {
@ -31,9 +31,9 @@ class GeneratedCodeTest extends PHPUnit_Framework_TestCase {
return $num->getNum();
};
$values = array_map($extract_num, $result_array);
$this->assertEquals([1, 1, 2, 3, 5, 8, 13], $values);
$this->assertSame([1, 1, 2, 3, 5, 8, 13], $values);
$status = $call->getStatus();
$this->assertEquals(\Grpc\STATUS_OK, $status->code);
$this->assertSame(\Grpc\STATUS_OK, $status->code);
}
public function testClientStreaming() {
@ -46,8 +46,8 @@ class GeneratedCodeTest extends PHPUnit_Framework_TestCase {
};
$call = self::$client->Sum($num_iter());
list($response, $status) = $call->wait();
$this->assertEquals(21, $response->getNum());
$this->assertEquals(\Grpc\STATUS_OK, $status->code);
$this->assertSame(21, $response->getNum());
$this->assertSame(\Grpc\STATUS_OK, $status->code);
}
public function testBidiStreaming() {
@ -58,11 +58,11 @@ class GeneratedCodeTest extends PHPUnit_Framework_TestCase {
$div_arg->setDivisor(2);
$call->write($div_arg);
$response = $call->read();
$this->assertEquals($i, $response->getQuotient());
$this->assertEquals(1, $response->getRemainder());
$this->assertSame($i, $response->getQuotient());
$this->assertSame(1, $response->getRemainder());
}
$call->writesDone();
$status = $call->getStatus();
$this->assertEquals(\Grpc\STATUS_OK, $status->code);
$this->assertSame(\Grpc\STATUS_OK, $status->code);
}
}

@ -26,8 +26,8 @@ function hardAssert($value, $error_message) {
*/
function emptyUnary($stub) {
list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait();
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result != null, 'Call completed with a null response');
hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result !== null, 'Call completed with a null response');
}
/**
@ -49,14 +49,14 @@ function largeUnary($stub) {
$request->setPayload($payload);
list($result, $status) = $stub->UnaryCall($request)->wait();
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result != null, 'Call returned a null response');
hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result !== null, 'Call returned a null response');
$payload = $result->getPayload();
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE,
hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
'Payload had the wrong type');
hardAssert(strlen($payload->getBody()) == $response_len,
hardAssert(strlen($payload->getBody()) === $response_len,
'Payload had the wrong length');
hardAssert($payload->getBody() == str_repeat("\0", $response_len),
hardAssert($payload->getBody() === str_repeat("\0", $response_len),
'Payload had the wrong content');
}
@ -78,8 +78,8 @@ function clientStreaming($stub) {
}, $request_lengths);
list($result, $status) = $stub->StreamingInputCall($requests)->wait();
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result->getAggregatedPayloadSize() == 74922,
hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result->getAggregatedPayloadSize() === 74922,
'aggregated_payload_size was incorrect');
}
@ -100,15 +100,15 @@ function serverStreaming($stub) {
}
$call = $stub->StreamingOutputCall($request);
hardAssert($call->getStatus()->code == Grpc\STATUS_OK,
hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
'Call did not complete successfully');
$i = 0;
foreach($call->responses() as $value) {
hardAssert($i < 4, 'Too many responses');
$payload = $value->getPayload();
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE,
hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
'Payload ' . $i . ' had the wrong type');
hardAssert(strlen($payload->getBody()) == $sizes[$i],
hardAssert(strlen($payload->getBody()) === $sizes[$i],
'Response ' . $i . ' had the wrong length');
}
}
@ -136,19 +136,38 @@ function pingPong($stub) {
$call->write($request);
$response = $call->read();
hardAssert($response != null, 'Server returned too few responses');
hardAssert($response !== null, 'Server returned too few responses');
$payload = $response->getPayload();
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE,
hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
'Payload ' . $i . ' had the wrong type');
hardAssert(strlen($payload->getBody()) == $response_lengths[$i],
hardAssert(strlen($payload->getBody()) === $response_lengths[$i],
'Payload ' . $i . ' had the wrong length');
}
$call->writesDone();
hardAssert($call->read() == null, 'Server returned too many responses');
hardAssert($call->getStatus()->code == Grpc\STATUS_OK,
hardAssert($call->read() === null, 'Server returned too many responses');
hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
'Call did not complete successfully');
}
function cancelAfterFirstResponse($stub) {
$call = $stub->FullDuplexCall();
$request = new grpc\testing\StreamingOutputCallRequest();
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE);
$response_parameters = new grpc\testing\ResponseParameters();
$response_parameters->setSize(31415);
$request->addResponseParameters($response_parameters);
$payload = new grpc\testing\Payload();
$payload->setBody(str_repeat("\0", 27182));
$request->setPayload($payload);
$call->write($request);
$response = $call->read();
$call->cancel();
hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED,
'Call status was not CANCELLED');
}
$args = getopt('', array('server_host:', 'server_port:', 'test_case:'));
if (!array_key_exists('server_host', $args) ||
!array_key_exists('server_port', $args) ||
@ -187,4 +206,6 @@ switch($args['test_case']) {
case 'ping_pong':
pingPong($stub);
break;
case 'cancel_after_first_response':
cancelAfterFirstResponse($stub);
}

@ -1,16 +1,17 @@
<?php
class CallTest extends PHPUnit_Framework_TestCase{
static $server;
static $port;
public static function setUpBeforeClass() {
$cq = new Grpc\CompletionQueue();
self::$server = new Grpc\Server($cq, []);
self::$server->add_http2_port('localhost:9001');
self::$port = self::$server->add_http2_port('0.0.0.0:0');
}
public function setUp() {
$this->cq = new Grpc\CompletionQueue();
$this->channel = new Grpc\Channel('localhost:9001', []);
$this->channel = new Grpc\Channel('localhost:' . self::$port, []);
$this->call = new Grpc\Call($this->channel,
'/foo',
Grpc\Timeval::inf_future());
@ -46,7 +47,7 @@ class CallTest extends PHPUnit_Framework_TestCase{
}
public function testAddSingleMetadata() {
$this->call->add_metadata(['key' => 'value'], 0);
$this->call->add_metadata(['key' => ['value']], 0);
/* Dummy assert: Checks that the previous call completed without error */
$this->assertTrue(true);
}
@ -59,7 +60,7 @@ class CallTest extends PHPUnit_Framework_TestCase{
public function testAddSingleAndMultiValueMetadata() {
$this->call->add_metadata(
['key1' => 'value1',
['key1' => ['value1'],
'key2' => ['value2', 'value3']], 0);
/* Dummy assert: Checks that the previous call completed without error */
$this->assertTrue(true);

@ -1,13 +1,11 @@
<?php
require __DIR__ . '/../util/port_picker.php';
class EndToEndTest extends PHPUnit_Framework_TestCase{
public function setUp() {
$this->client_queue = new Grpc\CompletionQueue();
$this->server_queue = new Grpc\CompletionQueue();
$this->server = new Grpc\Server($this->server_queue, []);
$address = '127.0.0.1:' . getNewPort();
$this->server->add_http2_port($address);
$this->channel = new Grpc\Channel($address, []);
$port = $this->server->add_http2_port('0.0.0.0:0');
$this->channel = new Grpc\Channel('localhost:' . $port, []);
}
public function tearDown() {
@ -24,62 +22,52 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->invoke($this->client_queue,
$tag,
$tag));
$call->invoke($this->client_queue, $tag, $tag);
$server_tag = 2;
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// check that a server rpc new was received
$this->server->start();
$this->server->request_call($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
$this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
$server_call = $event->call;
$this->assertNotNull($server_call);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_accept($this->server_queue,
$server_tag));
$server_call->server_accept($this->server_queue, $server_tag);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_end_initial_metadata());
$server_call->server_end_initial_metadata();
// the server sends the status
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write_status(Grpc\STATUS_OK,
$status_text,
$server_tag));
$server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the client gets CLIENT_METADATA_READ
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
$this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
// the client gets FINISHED
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
$this->assertEquals(Grpc\STATUS_OK, $status->code);
$this->assertEquals($status_text, $status->details);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
// and the server gets FINISHED
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
unset($call);
@ -96,10 +84,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->invoke($this->client_queue,
$tag,
$tag));
$call->invoke($this->client_queue, $tag, $tag);
$server_tag = 2;
@ -107,76 +92,69 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$call->start_write($req_text, $tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
$this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
// check that a server rpc new was received
$this->server->start();
$this->server->request_call($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
$this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
$server_call = $event->call;
$this->assertNotNull($server_call);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_accept($this->server_queue,
$server_tag));
$server_call->server_accept($this->server_queue, $server_tag);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_end_initial_metadata());
$server_call->server_end_initial_metadata();
// start the server read
$server_call->start_read($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\READ, $event->type);
$this->assertEquals($req_text, $event->data);
$this->assertSame(Grpc\READ, $event->type);
$this->assertSame($req_text, $event->data);
// the server replies
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write($reply_text, $server_tag));
$server_call->start_write($reply_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
$this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
// the client reads the metadata
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
$this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
// the client reads the reply
$call->start_read($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\READ, $event->type);
$this->assertEquals($reply_text, $event->data);
$this->assertSame(Grpc\READ, $event->type);
$this->assertSame($reply_text, $event->data);
// the client sends writes done
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the server sends the status
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write_status(GRPC\STATUS_OK,
$status_text,
$server_tag));
$server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the client gets FINISHED
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
$this->assertEquals(Grpc\STATUS_OK, $status->code);
$this->assertEquals($status_text, $status->details);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
// and the server gets FINISHED
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
unset($call);
unset($server_call);

@ -11,10 +11,9 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
file_get_contents(dirname(__FILE__) . '/../data/server1.pem'));
$this->server = new Grpc\Server($this->server_queue,
['credentials' => $server_credentials]);
$address = '127.0.0.1:' . getNewPort();
$this->server->add_secure_http2_port($address);
$port = $this->server->add_secure_http2_port('0.0.0.0:0');
$this->channel = new Grpc\Channel(
$address,
'localhost:' . $port,
[
'grpc.ssl_target_name_override' => 'foo.test.google.com',
'credentials' => $credentials
@ -36,59 +35,50 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->invoke($this->client_queue,
$tag,
$tag));
$call->invoke($this->client_queue, $tag, $tag);
$server_tag = 2;
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// check that a server rpc new was received
$this->server->request_call($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
$this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
$server_call = $event->call;
$this->assertNotNull($server_call);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_accept($this->server_queue,
$server_tag));
$server_call->server_accept($this->server_queue, $server_tag);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_end_initial_metadata());
$server_call->server_end_initial_metadata();
// the server sends the status
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write_status(Grpc\STATUS_OK,
$status_text,
$server_tag));
$server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the client gets CLIENT_METADATA_READ
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
$this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
// the client gets FINISHED
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
$this->assertEquals(Grpc\STATUS_OK, $status->code);
$this->assertEquals($status_text, $status->details);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
// and the server gets FINISHED
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
unset($call);
@ -106,10 +96,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->invoke($this->client_queue,
$tag,
$tag));
$call->invoke($this->client_queue, $tag, $tag);
$server_tag = 2;
@ -117,75 +104,68 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$call->start_write($req_text, $tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
$this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
// check that a server rpc new was received
$this->server->request_call($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
$this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
$server_call = $event->call;
$this->assertNotNull($server_call);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_accept($this->server_queue,
$server_tag));
$server_call->server_accept($this->server_queue, $server_tag);
$this->assertEquals(Grpc\CALL_OK,
$server_call->server_end_initial_metadata());
$server_call->server_end_initial_metadata();
// start the server read
$server_call->start_read($server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\READ, $event->type);
$this->assertEquals($req_text, $event->data);
$this->assertSame(Grpc\READ, $event->type);
$this->assertSame($req_text, $event->data);
// the server replies
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write($reply_text, $server_tag));
$server_call->start_write($reply_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
$this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
// the client reads the metadata
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
$this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
// the client reads the reply
$call->start_read($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\READ, $event->type);
$this->assertEquals($reply_text, $event->data);
$this->assertSame(Grpc\READ, $event->type);
$this->assertSame($reply_text, $event->data);
// the client sends writes done
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the server sends the status
$this->assertEquals(Grpc\CALL_OK,
$server_call->start_write_status(GRPC\STATUS_OK,
$status_text,
$server_tag));
$server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
$event = $this->server_queue->next($deadline);
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertEquals(Grpc\OP_OK, $event->data);
$this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
$this->assertSame(Grpc\OP_OK, $event->data);
// the client gets FINISHED
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
$status = $event->data;
$this->assertEquals(Grpc\STATUS_OK, $status->code);
$this->assertEquals($status_text, $status->details);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
// and the server gets FINISHED
$event = $this->server_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\FINISHED, $event->type);
$this->assertSame(Grpc\FINISHED, $event->type);
unset($call);
unset($server_call);

@ -2,7 +2,7 @@
class TimevalTest extends PHPUnit_Framework_TestCase{
public function testCompareSame() {
$zero = Grpc\Timeval::zero();
$this->assertEquals(0, Grpc\Timeval::compare($zero, $zero));
$this->assertSame(0, Grpc\Timeval::compare($zero, $zero));
}
public function testPastIsLessThanZero() {

@ -1,6 +0,0 @@
<?php
function getNewPort() {
static $port = 10000;
$port += 1;
return $port;
}

@ -56,9 +56,9 @@ static int pygrpc_call_init(Call *self, PyObject *args, PyObject *kwds) {
/* TODO(nathaniel): Hoist the gpr_timespec <-> PyFloat arithmetic into its own
* function with its own test coverage.
*/
self->c_call =
grpc_channel_create_call(((Channel *)channel)->c_channel, method, host,
gpr_time_from_nanos(deadline * GPR_NS_PER_SEC));
self->c_call = grpc_channel_create_call_old(
((Channel *)channel)->c_channel, method, host,
gpr_time_from_nanos(deadline * GPR_NS_PER_SEC));
return 0;
}
@ -82,7 +82,7 @@ static const PyObject *pygrpc_call_invoke(Call *self, PyObject *args) {
return NULL;
}
call_error = grpc_call_invoke(
call_error = grpc_call_invoke_old(
self->c_call, ((CompletionQueue *)completion_queue)->c_completion_queue,
(void *)metadata_tag, (void *)finish_tag, 0);
@ -111,7 +111,8 @@ static const PyObject *pygrpc_call_write(Call *self, PyObject *args) {
byte_buffer = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);
call_error = grpc_call_start_write(self->c_call, byte_buffer, (void *)tag, 0);
call_error =
grpc_call_start_write_old(self->c_call, byte_buffer, (void *)tag, 0);
grpc_byte_buffer_destroy(byte_buffer);
@ -131,7 +132,7 @@ static const PyObject *pygrpc_call_complete(Call *self, PyObject *args) {
return NULL;
}
call_error = grpc_call_writes_done(self->c_call, (void *)tag);
call_error = grpc_call_writes_done_old(self->c_call, (void *)tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {
@ -151,7 +152,7 @@ static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) {
return NULL;
}
call_error = grpc_call_server_accept(
call_error = grpc_call_server_accept_old(
self->c_call, ((CompletionQueue *)completion_queue)->c_completion_queue,
(void *)tag);
result = pygrpc_translate_call_error(call_error);
@ -166,7 +167,7 @@ static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) {
static const PyObject *pygrpc_call_premetadata(Call *self, PyObject *args) {
/* TODO(b/18702680): Actually support metadata. */
return pygrpc_translate_call_error(
grpc_call_server_end_initial_metadata(self->c_call, 0));
grpc_call_server_end_initial_metadata_old(self->c_call, 0));
}
static const PyObject *pygrpc_call_read(Call *self, PyObject *args) {
@ -178,7 +179,7 @@ static const PyObject *pygrpc_call_read(Call *self, PyObject *args) {
return NULL;
}
call_error = grpc_call_start_read(self->c_call, (void *)tag);
call_error = grpc_call_start_read_old(self->c_call, (void *)tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {
@ -208,8 +209,8 @@ static const PyObject *pygrpc_call_status(Call *self, PyObject *args) {
Py_DECREF(code);
Py_DECREF(details);
call_error = grpc_call_start_write_status(self->c_call, c_code, c_message,
(void *)tag);
call_error = grpc_call_start_write_status_old(self->c_call, c_code, c_message,
(void *)tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {

@ -80,8 +80,8 @@ class RoundTripTest(unittest.TestCase):
rear_link.start()
front_to_back_ticket = tickets.FrontToBackPacket(
test_operation_id, 0, tickets.Kind.ENTIRE, test_method, interfaces.FULL,
None, None, _TIMEOUT)
test_operation_id, 0, tickets.Kind.ENTIRE, test_method,
interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
with test_fore_link.condition:
@ -133,8 +133,9 @@ class RoundTripTest(unittest.TestCase):
rear_link.start()
front_to_back_ticket = tickets.FrontToBackPacket(
test_operation_id, 0, tickets.Kind.ENTIRE, test_method, interfaces.FULL,
None, test_front_to_back_datum, _TIMEOUT)
test_operation_id, 0, tickets.Kind.ENTIRE, test_method,
interfaces.ServicedSubscription.Kind.FULL, None,
test_front_to_back_datum, _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
with test_fore_link.condition:
@ -196,7 +197,7 @@ class RoundTripTest(unittest.TestCase):
commencement_ticket = tickets.FrontToBackPacket(
test_operation_id, 0, tickets.Kind.COMMENCEMENT, test_method,
interfaces.FULL, None, None, _TIMEOUT)
interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
fore_sequence_number = 1
rear_link.accept_front_to_back_ticket(commencement_ticket)
for request in scenario.requests():

@ -69,7 +69,7 @@ class LonelyRearLinkTest(unittest.TestCase):
front_to_back_ticket = packets.FrontToBackPacket(
test_operation_id, 0, front_to_back_ticket_kind, test_method,
interfaces.FULL, None, None, _TIMEOUT)
interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
with fore_link.condition:

@ -88,7 +88,7 @@ static const PyObject *pygrpc_server_service(Server *self, PyObject *args) {
return NULL;
}
call_error = grpc_server_request_call(self->c_server, (void *)tag);
call_error = grpc_server_request_call_old(self->c_server, (void *)tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {

@ -116,7 +116,8 @@ class ForeLink(ticket_interfaces.ForeLink):
self._response_serializers[method])
ticket = tickets.FrontToBackPacket(
call, 0, tickets.Kind.COMMENCEMENT, method, interfaces.FULL, None, None,
call, 0, tickets.Kind.COMMENCEMENT, method,
interfaces.ServicedSubscription.Kind.FULL, None, None,
service_acceptance.deadline - time.time())
self._rear_link.accept_front_to_back_ticket(ticket)

@ -29,27 +29,24 @@
"""Interfaces defined and used by the base layer of RPC Framework."""
# TODO(nathaniel): Use Python's new enum library for enumerated types rather
# than constants merely placed close together.
import abc
import enum
# stream is referenced from specification in this module.
from _framework.foundation import stream # pylint: disable=unused-import
# Operation outcomes.
COMPLETED = 'completed'
CANCELLED = 'cancelled'
EXPIRED = 'expired'
RECEPTION_FAILURE = 'reception failure'
TRANSMISSION_FAILURE = 'transmission failure'
SERVICER_FAILURE = 'servicer failure'
SERVICED_FAILURE = 'serviced failure'
# Subscription categories.
FULL = 'full'
TERMINATION_ONLY = 'termination only'
NONE = 'none'
@enum.unique
class Outcome(enum.Enum):
"""Operation outcomes."""
COMPLETED = 'completed'
CANCELLED = 'cancelled'
EXPIRED = 'expired'
RECEPTION_FAILURE = 'reception failure'
TRANSMISSION_FAILURE = 'transmission failure'
SERVICER_FAILURE = 'servicer failure'
SERVICED_FAILURE = 'serviced failure'
class OperationContext(object):
@ -70,9 +67,7 @@ class OperationContext(object):
"""Adds a function to be called upon operation termination.
Args:
callback: A callable that will be passed one of COMPLETED, CANCELLED,
EXPIRED, RECEPTION_FAILURE, TRANSMISSION_FAILURE, SERVICER_FAILURE, or
SERVICED_FAILURE.
callback: A callable that will be passed an Outcome value.
"""
raise NotImplementedError()
@ -167,11 +162,20 @@ class ServicedSubscription(object):
"""A sum type representing a serviced's interest in an operation.
Attributes:
category: One of FULL, TERMINATION_ONLY, or NONE.
ingestor: A ServicedIngestor. Must be present if category is FULL.
kind: A Kind value.
ingestor: A ServicedIngestor. Must be present if kind is Kind.FULL. Must
be None if kind is Kind.TERMINATION_ONLY or Kind.NONE.
"""
__metaclass__ = abc.ABCMeta
@enum.unique
class Kind(enum.Enum):
"""Kinds of subscription."""
FULL = 'full'
TERMINATION_ONLY = 'termination only'
NONE = 'none'
class End(object):
"""Common type for entry-point objects on both sides of an operation."""
@ -182,9 +186,8 @@ class End(object):
"""Reports the number of terminated operations broken down by outcome.
Returns:
A dictionary from operation outcome constant (COMPLETED, CANCELLED,
EXPIRED, and so on) to an integer representing the number of operations
that terminated with that outcome.
A dictionary from Outcome value to an integer identifying the number
of operations that terminated with that outcome.
"""
raise NotImplementedError()

@ -49,13 +49,13 @@ TRIGGERED_FAILURE = 'triggered failure'
WAIT_ON_CONDITION = 'wait on condition'
EMPTY_OUTCOME_DICT = {
interfaces.COMPLETED: 0,
interfaces.CANCELLED: 0,
interfaces.EXPIRED: 0,
interfaces.RECEPTION_FAILURE: 0,
interfaces.TRANSMISSION_FAILURE: 0,
interfaces.SERVICER_FAILURE: 0,
interfaces.SERVICED_FAILURE: 0,
interfaces.Outcome.COMPLETED: 0,
interfaces.Outcome.CANCELLED: 0,
interfaces.Outcome.EXPIRED: 0,
interfaces.Outcome.RECEPTION_FAILURE: 0,
interfaces.Outcome.TRANSMISSION_FAILURE: 0,
interfaces.Outcome.SERVICER_FAILURE: 0,
interfaces.Outcome.SERVICED_FAILURE: 0,
}
@ -169,7 +169,8 @@ class FrontAndBackTest(object):
SYNCHRONOUS_ECHO, None, True, SMALL_TIMEOUT,
util.none_serviced_subscription(), 'test trace ID')
util.wait_for_idle(self.front)
self.assertEqual(1, self.front.operation_stats()[interfaces.COMPLETED])
self.assertEqual(
1, self.front.operation_stats()[interfaces.Outcome.COMPLETED])
# Assuming nothing really pathological (such as pauses on the order of
# SMALL_TIMEOUT interfering with this test) there are a two different ways
@ -183,7 +184,7 @@ class FrontAndBackTest(object):
first_back_possibility = EMPTY_OUTCOME_DICT
# (2) The packet arrived at the back and the back completed the operation.
second_back_possibility = dict(EMPTY_OUTCOME_DICT)
second_back_possibility[interfaces.COMPLETED] = 1
second_back_possibility[interfaces.Outcome.COMPLETED] = 1
self.assertIn(
back_operation_stats, (first_back_possibility, second_back_possibility))
# It's true that if the packet had arrived at the back and the back had
@ -204,8 +205,10 @@ class FrontAndBackTest(object):
util.wait_for_idle(self.front)
util.wait_for_idle(self.back)
self.assertEqual(1, self.front.operation_stats()[interfaces.COMPLETED])
self.assertEqual(1, self.back.operation_stats()[interfaces.COMPLETED])
self.assertEqual(
1, self.front.operation_stats()[interfaces.Outcome.COMPLETED])
self.assertEqual(
1, self.back.operation_stats()[interfaces.Outcome.COMPLETED])
self.assertListEqual([(test_payload, True)], test_consumer.calls)
def testBidirectionalStreamingEcho(self):
@ -226,8 +229,10 @@ class FrontAndBackTest(object):
util.wait_for_idle(self.front)
util.wait_for_idle(self.back)
self.assertEqual(1, self.front.operation_stats()[interfaces.COMPLETED])
self.assertEqual(1, self.back.operation_stats()[interfaces.COMPLETED])
self.assertEqual(
1, self.front.operation_stats()[interfaces.Outcome.COMPLETED])
self.assertEqual(
1, self.back.operation_stats()[interfaces.Outcome.COMPLETED])
self.assertListEqual(test_payloads, test_consumer.values())
def testCancellation(self):
@ -242,7 +247,8 @@ class FrontAndBackTest(object):
operation.cancel()
util.wait_for_idle(self.front)
self.assertEqual(1, self.front.operation_stats()[interfaces.CANCELLED])
self.assertEqual(
1, self.front.operation_stats()[interfaces.Outcome.CANCELLED])
util.wait_for_idle(self.back)
self.assertListEqual([], test_consumer.calls)
@ -260,7 +266,7 @@ class FrontAndBackTest(object):
# The back started processing based on the first packet and then stopped
# upon receiving the cancellation packet.
second_back_possibility = dict(EMPTY_OUTCOME_DICT)
second_back_possibility[interfaces.CANCELLED] = 1
second_back_possibility[interfaces.Outcome.CANCELLED] = 1
self.assertIn(
back_operation_stats, (first_back_possibility, second_back_possibility))
@ -292,8 +298,10 @@ class FrontAndBackTest(object):
duration = termination_time_cell[0] - start_time
self.assertLessEqual(timeout, duration)
self.assertLess(duration, timeout + allowance)
self.assertEqual(interfaces.EXPIRED, outcome_cell[0])
self.assertEqual(interfaces.Outcome.EXPIRED, outcome_cell[0])
util.wait_for_idle(self.front)
self.assertEqual(1, self.front.operation_stats()[interfaces.EXPIRED])
self.assertEqual(
1, self.front.operation_stats()[interfaces.Outcome.EXPIRED])
util.wait_for_idle(self.back)
self.assertLessEqual(1, self.back.operation_stats()[interfaces.EXPIRED])
self.assertLessEqual(
1, self.back.operation_stats()[interfaces.Outcome.EXPIRED])

@ -51,13 +51,13 @@ from _framework.foundation import callable_util
_IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
_OPERATION_OUTCOMES = (
base_interfaces.COMPLETED,
base_interfaces.CANCELLED,
base_interfaces.EXPIRED,
base_interfaces.RECEPTION_FAILURE,
base_interfaces.TRANSMISSION_FAILURE,
base_interfaces.SERVICER_FAILURE,
base_interfaces.SERVICED_FAILURE,
base_interfaces.Outcome.COMPLETED,
base_interfaces.Outcome.CANCELLED,
base_interfaces.Outcome.EXPIRED,
base_interfaces.Outcome.RECEPTION_FAILURE,
base_interfaces.Outcome.TRANSMISSION_FAILURE,
base_interfaces.Outcome.SERVICER_FAILURE,
base_interfaces.Outcome.SERVICED_FAILURE,
)
@ -193,10 +193,10 @@ def _front_operate(
lock = threading.Lock()
with lock:
termination_manager = _termination.front_termination_manager(
work_pool, utility_pool, termination_action, subscription.category)
work_pool, utility_pool, termination_action, subscription.kind)
transmission_manager = _transmission.front_transmission_manager(
lock, transmission_pool, callback, operation_id, name,
subscription.category, trace_id, timeout, termination_manager)
subscription.kind, trace_id, timeout, termination_manager)
operation_context = _context.OperationContext(
lock, operation_id, packets.Kind.SERVICED_FAILURE,
termination_manager, transmission_manager)
@ -225,9 +225,10 @@ def _front_operate(
transmission_manager.inmit(payload, complete)
returned_reception_manager = (
None if subscription.category == base_interfaces.NONE
else reception_manager)
if subscription.kind is base_interfaces.ServicedSubscription.Kind.NONE:
returned_reception_manager = None
else:
returned_reception_manager = reception_manager
return _FrontManagement(
returned_reception_manager, emission_manager, operation_context,

@ -111,7 +111,7 @@ class _FrontConsumerCreator(_ConsumerCreator):
def create_consumer(self, requirement):
"""See _ConsumerCreator.create_consumer for specification."""
if self._subscription.category == interfaces.FULL:
if self._subscription.kind is interfaces.ServicedSubscription.Kind.FULL:
try:
return _ConsumerCreation(
self._subscription.ingestor.consumer(self._operation_context),

@ -58,10 +58,7 @@ class TerminationManager(object):
immediately.
Args:
callback: A callable that will be passed one of base_interfaces.COMPLETED,
base_interfaces.CANCELLED, base_interfaces.EXPIRED,
base_interfaces.RECEPTION_FAILURE, base_interfaces.TRANSMISSION_FAILURE,
base_interfaces.SERVICER_FAILURE, or base_interfaces.SERVICED_FAILURE.
callback: A callable that will be passed a base_interfaces.Outcome value.
"""
raise NotImplementedError()

@ -29,6 +29,8 @@
"""State and behavior for operation termination."""
import enum
from _framework.base import interfaces
from _framework.base.packets import _constants
from _framework.base.packets import _interfaces
@ -37,26 +39,32 @@ from _framework.foundation import callable_util
_CALLBACK_EXCEPTION_LOG_MESSAGE = 'Exception calling termination callback!'
# TODO(nathaniel): enum module.
_EMISSION = 'emission'
_TRANSMISSION = 'transmission'
_INGESTION = 'ingestion'
_FRONT_NOT_LISTENING_REQUIREMENTS = (_TRANSMISSION,)
_BACK_NOT_LISTENING_REQUIREMENTS = (_EMISSION, _INGESTION,)
_LISTENING_REQUIREMENTS = (_TRANSMISSION, _INGESTION,)
_KINDS_TO_OUTCOMES = {
packets.Kind.COMPLETION: interfaces.COMPLETED,
packets.Kind.CANCELLATION: interfaces.CANCELLED,
packets.Kind.EXPIRATION: interfaces.EXPIRED,
packets.Kind.RECEPTION_FAILURE: interfaces.RECEPTION_FAILURE,
packets.Kind.TRANSMISSION_FAILURE: interfaces.TRANSMISSION_FAILURE,
packets.Kind.SERVICER_FAILURE: interfaces.SERVICER_FAILURE,
packets.Kind.SERVICED_FAILURE: interfaces.SERVICED_FAILURE,
packets.Kind.COMPLETION: interfaces.Outcome.COMPLETED,
packets.Kind.CANCELLATION: interfaces.Outcome.CANCELLED,
packets.Kind.EXPIRATION: interfaces.Outcome.EXPIRED,
packets.Kind.RECEPTION_FAILURE: interfaces.Outcome.RECEPTION_FAILURE,
packets.Kind.TRANSMISSION_FAILURE: interfaces.Outcome.TRANSMISSION_FAILURE,
packets.Kind.SERVICER_FAILURE: interfaces.Outcome.SERVICER_FAILURE,
packets.Kind.SERVICED_FAILURE: interfaces.Outcome.SERVICED_FAILURE,
}
@enum.unique
class _Requirement(enum.Enum):
"""Symbols indicating events required for termination."""
EMISSION = 'emission'
TRANSMISSION = 'transmission'
INGESTION = 'ingestion'
_FRONT_NOT_LISTENING_REQUIREMENTS = (_Requirement.TRANSMISSION,)
_BACK_NOT_LISTENING_REQUIREMENTS = (
_Requirement.EMISSION, _Requirement.INGESTION,)
_LISTENING_REQUIREMENTS = (
_Requirement.TRANSMISSION, _Requirement.INGESTION,)
class _TerminationManager(_interfaces.TerminationManager):
"""An implementation of _interfaces.TerminationManager."""
@ -68,9 +76,8 @@ class _TerminationManager(_interfaces.TerminationManager):
work_pool: A thread pool in which customer work will be done.
utility_pool: A thread pool in which work utility work will be done.
action: An action to call on operation termination.
requirements: A combination of _EMISSION, _TRANSMISSION, and _INGESTION
identifying what must finish for the operation to be considered
completed.
requirements: A combination of _Requirement values identifying what
must finish for the operation to be considered completed.
local_failure: A packets.Kind specifying what constitutes local failure of
customer work.
"""
@ -137,21 +144,21 @@ class _TerminationManager(_interfaces.TerminationManager):
def emission_complete(self):
"""See superclass method for specification."""
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_EMISSION)
self._outstanding_requirements.discard(_Requirement.EMISSION)
if not self._outstanding_requirements:
self._terminate(packets.Kind.COMPLETION)
def transmission_complete(self):
"""See superclass method for specification."""
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_TRANSMISSION)
self._outstanding_requirements.discard(_Requirement.TRANSMISSION)
if not self._outstanding_requirements:
self._terminate(packets.Kind.COMPLETION)
def ingestion_complete(self):
"""See superclass method for specification."""
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_INGESTION)
self._outstanding_requirements.discard(_Requirement.INGESTION)
if not self._outstanding_requirements:
self._terminate(packets.Kind.COMPLETION)
@ -163,39 +170,46 @@ class _TerminationManager(_interfaces.TerminationManager):
self._terminate(kind)
def front_termination_manager(work_pool, utility_pool, action, subscription):
def front_termination_manager(
work_pool, utility_pool, action, subscription_kind):
"""Creates a TerminationManager appropriate for front-side use.
Args:
work_pool: A thread pool in which customer work will be done.
utility_pool: A thread pool in which work utility work will be done.
action: An action to call on operation termination.
subscription: One of interfaces.FULL, interfaces.termination_only, or
interfaces.NONE.
subscription_kind: An interfaces.ServicedSubscription.Kind value.
Returns:
A TerminationManager appropriate for front-side use.
"""
if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
requirements = _FRONT_NOT_LISTENING_REQUIREMENTS
else:
requirements = _LISTENING_REQUIREMENTS
return _TerminationManager(
work_pool, utility_pool, action,
_FRONT_NOT_LISTENING_REQUIREMENTS if subscription == interfaces.NONE else
_LISTENING_REQUIREMENTS, packets.Kind.SERVICED_FAILURE)
work_pool, utility_pool, action, requirements,
packets.Kind.SERVICED_FAILURE)
def back_termination_manager(work_pool, utility_pool, action, subscription):
def back_termination_manager(work_pool, utility_pool, action, subscription_kind):
"""Creates a TerminationManager appropriate for back-side use.
Args:
work_pool: A thread pool in which customer work will be done.
utility_pool: A thread pool in which work utility work will be done.
action: An action to call on operation termination.
subscription: One of interfaces.FULL, interfaces.termination_only, or
interfaces.NONE.
subscription_kind: An interfaces.ServicedSubscription.Kind value.
Returns:
A TerminationManager appropriate for back-side use.
"""
if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
requirements = _BACK_NOT_LISTENING_REQUIREMENTS
else:
requirements = _LISTENING_REQUIREMENTS
return _TerminationManager(
work_pool, utility_pool, action,
_BACK_NOT_LISTENING_REQUIREMENTS if subscription == interfaces.NONE else
_LISTENING_REQUIREMENTS, packets.Kind.SERVICER_FAILURE)
work_pool, utility_pool, action, requirements,
packets.Kind.SERVICER_FAILURE)

@ -91,20 +91,19 @@ class _Packetizer(object):
class _FrontPacketizer(_Packetizer):
"""Front-side packet-creating behavior."""
def __init__(self, name, subscription, trace_id, timeout):
def __init__(self, name, subscription_kind, trace_id, timeout):
"""Constructor.
Args:
name: The name of the operation.
subscription: One of interfaces.FULL, interfaces.TERMINATION_ONLY, or
interfaces.NONE describing the interest the front has in packets sent
from the back.
subscription_kind: An interfaces.ServicedSubscription.Kind value
describing the interest the front has in packets sent from the back.
trace_id: A uuid.UUID identifying a set of related operations to which
this operation belongs.
timeout: A length of time in seconds to allow for the entire operation.
"""
self._name = name
self._subscription = subscription
self._subscription_kind = subscription_kind
self._trace_id = trace_id
self._timeout = timeout
@ -114,13 +113,13 @@ class _FrontPacketizer(_Packetizer):
return packets.FrontToBackPacket(
operation_id, sequence_number,
packets.Kind.COMPLETION if complete else packets.Kind.CONTINUATION,
self._name, self._subscription, self._trace_id, payload,
self._name, self._subscription_kind, self._trace_id, payload,
self._timeout)
else:
return packets.FrontToBackPacket(
operation_id, 0,
packets.Kind.ENTIRE if complete else packets.Kind.COMMENCEMENT,
self._name, self._subscription, self._trace_id, payload,
self._name, self._subscription_kind, self._trace_id, payload,
self._timeout)
def packetize_abortion(self, operation_id, sequence_number, kind):
@ -335,8 +334,8 @@ class _TransmittingTransmissionManager(TransmissionManager):
def front_transmission_manager(
lock, pool, callback, operation_id, name, subscription, trace_id, timeout,
termination_manager):
lock, pool, callback, operation_id, name, subscription_kind, trace_id,
timeout, termination_manager):
"""Creates a TransmissionManager appropriate for front-side use.
Args:
@ -347,9 +346,8 @@ def front_transmission_manager(
of the operation.
operation_id: The operation's ID.
name: The name of the operation.
subscription: One of interfaces.FULL, interfaces.TERMINATION_ONLY, or
interfaces.NONE describing the interest the front has in packets sent
from the back.
subscription_kind: An interfaces.ServicedSubscription.Kind value
describing the interest the front has in packets sent from the back.
trace_id: A uuid.UUID identifying a set of related operations to which
this operation belongs.
timeout: A length of time in seconds to allow for the entire operation.
@ -361,12 +359,13 @@ def front_transmission_manager(
"""
return _TransmittingTransmissionManager(
lock, pool, callback, operation_id, _FrontPacketizer(
name, subscription, trace_id, timeout),
name, subscription_kind, trace_id, timeout),
termination_manager)
def back_transmission_manager(
lock, pool, callback, operation_id, termination_manager, subscription):
lock, pool, callback, operation_id, termination_manager,
subscription_kind):
"""Creates a TransmissionManager appropriate for back-side use.
Args:
@ -378,14 +377,13 @@ def back_transmission_manager(
operation_id: The operation's ID.
termination_manager: The _interfaces.TerminationManager associated with
this operation.
subscription: One of interfaces.FULL, interfaces.TERMINATION_ONLY, or
interfaces.NONE describing the interest the front has in packets sent from
the back.
subscription_kind: An interfaces.ServicedSubscription.Kind value
describing the interest the front has in packets sent from the back.
Returns:
A TransmissionManager appropriate for back-side use.
"""
if subscription == interfaces.NONE:
if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
return _EmptyTransmissionManager()
else:
return _TransmittingTransmissionManager(

@ -71,10 +71,9 @@ class FrontToBackPacket(
Kind.RECEPTION_FAILURE, or Kind.TRANSMISSION_FAILURE.
name: The name of an operation. Must be present if kind is Kind.COMMENCEMENT
or Kind.ENTIRE. Must be None for any other kind.
subscription: One of interfaces.FULL, interfaces.TERMINATION_ONLY, or
interfaces.NONE describing the interest the front has in packets sent from
the back. Must be present if kind is Kind.COMMENCEMENT or Kind.ENTIRE.
Must be None for any other kind.
subscription: An interfaces.ServicedSubscription.Kind value describing the
interest the front has in packets sent from the back. Must be present if
kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind.
trace_id: A uuid.UUID identifying a set of related operations to which this
operation belongs. May be None.
payload: A customer payload object. Must be present if kind is

@ -36,13 +36,14 @@ from _framework.base import interfaces
class _ServicedSubscription(
collections.namedtuple('_ServicedSubscription', ['category', 'ingestor']),
collections.namedtuple('_ServicedSubscription', ['kind', 'ingestor']),
interfaces.ServicedSubscription):
"""See interfaces.ServicedSubscription for specification."""
_NONE_SUBSCRIPTION = _ServicedSubscription(interfaces.NONE, None)
_NONE_SUBSCRIPTION = _ServicedSubscription(
interfaces.ServicedSubscription.Kind.NONE, None)
_TERMINATION_ONLY_SUBSCRIPTION = _ServicedSubscription(
interfaces.TERMINATION_ONLY, None)
interfaces.ServicedSubscription.Kind.TERMINATION_ONLY, None)
def none_serviced_subscription():
@ -72,12 +73,14 @@ def full_serviced_subscription(ingestor):
"""Creates a "full" interfaces.ServicedSubscription object.
Args:
ingestor: A ServicedIngestor.
ingestor: An interfaces.ServicedIngestor.
Returns:
A ServicedSubscription object indicating a full subscription.
An interfaces.ServicedSubscription object indicating a full
subscription.
"""
return _ServicedSubscription(interfaces.FULL, ingestor)
return _ServicedSubscription(
interfaces.ServicedSubscription.Kind.FULL, ingestor)
def wait_for_idle(end):

@ -94,7 +94,7 @@ class _OperationCancellableIterator(interfaces.CancellableIterator):
def cancel(self):
self._operation.cancel()
self._rendezvous.set_outcome(base_interfaces.CANCELLED)
self._rendezvous.set_outcome(base_interfaces.Outcome.CANCELLED)
class _OperationFuture(future.Future):
@ -150,15 +150,12 @@ class _OperationFuture(future.Future):
"""Indicates to this object that the operation has terminated.
Args:
operation_outcome: One of base_interfaces.COMPLETED,
base_interfaces.CANCELLED, base_interfaces.EXPIRED,
base_interfaces.RECEPTION_FAILURE, base_interfaces.TRANSMISSION_FAILURE,
base_interfaces.SERVICED_FAILURE, or base_interfaces.SERVICER_FAILURE
indicating the categorical outcome of the operation.
operation_outcome: A base_interfaces.Outcome value indicating the
outcome of the operation.
"""
with self._condition:
if (self._outcome is None and
operation_outcome != base_interfaces.COMPLETED):
operation_outcome is not base_interfaces.Outcome.COMPLETED):
self._outcome = future.raised(
_control.abortion_outcome_to_exception(operation_outcome))
self._condition.notify_all()

@ -40,13 +40,17 @@ from _framework.foundation import stream
INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Face) Internal Error! :-('
_OPERATION_OUTCOME_TO_RPC_ABORTION = {
base_interfaces.CANCELLED: interfaces.CANCELLED,
base_interfaces.EXPIRED: interfaces.EXPIRED,
base_interfaces.RECEPTION_FAILURE: interfaces.NETWORK_FAILURE,
base_interfaces.TRANSMISSION_FAILURE: interfaces.NETWORK_FAILURE,
base_interfaces.SERVICED_FAILURE: interfaces.SERVICED_FAILURE,
base_interfaces.SERVICER_FAILURE: interfaces.SERVICER_FAILURE,
}
base_interfaces.Outcome.CANCELLED: interfaces.Abortion.CANCELLED,
base_interfaces.Outcome.EXPIRED: interfaces.Abortion.EXPIRED,
base_interfaces.Outcome.RECEPTION_FAILURE:
interfaces.Abortion.NETWORK_FAILURE,
base_interfaces.Outcome.TRANSMISSION_FAILURE:
interfaces.Abortion.NETWORK_FAILURE,
base_interfaces.Outcome.SERVICED_FAILURE:
interfaces.Abortion.SERVICED_FAILURE,
base_interfaces.Outcome.SERVICER_FAILURE:
interfaces.Abortion.SERVICER_FAILURE,
}
def _as_operation_termination_callback(rpc_abortion_callback):
@ -59,13 +63,13 @@ def _as_operation_termination_callback(rpc_abortion_callback):
def _abortion_outcome_to_exception(abortion_outcome):
if abortion_outcome == base_interfaces.CANCELLED:
if abortion_outcome == base_interfaces.Outcome.CANCELLED:
return exceptions.CancellationError()
elif abortion_outcome == base_interfaces.EXPIRED:
elif abortion_outcome == base_interfaces.Outcome.EXPIRED:
return exceptions.ExpirationError()
elif abortion_outcome == base_interfaces.SERVICER_FAILURE:
elif abortion_outcome == base_interfaces.Outcome.SERVICER_FAILURE:
return exceptions.ServicerError()
elif abortion_outcome == base_interfaces.SERVICED_FAILURE:
elif abortion_outcome == base_interfaces.Outcome.SERVICED_FAILURE:
return exceptions.ServicedError()
else:
return exceptions.NetworkError()
@ -133,7 +137,7 @@ class Rendezvous(stream.Consumer):
def set_outcome(self, outcome):
with self._condition:
if outcome != base_interfaces.COMPLETED:
if outcome is not base_interfaces.Outcome.COMPLETED:
self._abortion = outcome
self._condition.notify()

@ -30,6 +30,7 @@
"""Interfaces for the face layer of RPC Framework."""
import abc
import enum
# exceptions, abandonment, and future are referenced from specification in this
# module.
@ -58,14 +59,15 @@ class CancellableIterator(object):
raise NotImplementedError()
# Constants that categorize RPC abortion.
# TODO(nathaniel): Learn and use Python's enum library for this de facto
# enumerated type
CANCELLED = 'abortion: cancelled'
EXPIRED = 'abortion: expired'
NETWORK_FAILURE = 'abortion: network failure'
SERVICED_FAILURE = 'abortion: serviced failure'
SERVICER_FAILURE = 'abortion: servicer failure'
@enum.unique
class Abortion(enum.Enum):
"""Categories of RPC abortion."""
CANCELLED = 'cancelled'
EXPIRED = 'expired'
NETWORK_FAILURE = 'network failure'
SERVICED_FAILURE = 'serviced failure'
SERVICER_FAILURE = 'servicer failure'
class RpcContext(object):
@ -93,9 +95,8 @@ class RpcContext(object):
"""Registers a callback to be called if the RPC is aborted.
Args:
abortion_callback: A callable to be called and passed one of CANCELLED,
EXPIRED, NETWORK_FAILURE, SERVICED_FAILURE, or SERVICER_FAILURE in the
event of RPC abortion.
abortion_callback: A callable to be called and passed an Abortion value
in the event of RPC abortion.
"""
raise NotImplementedError()
@ -474,9 +475,8 @@ class Stub(object):
request: The request value for the RPC.
response_callback: A callback to be called to accept the response value
of the RPC.
abortion_callback: A callback to be called to accept one of CANCELLED,
EXPIRED, NETWORK_FAILURE, or SERVICER_FAILURE in the event of RPC
abortion.
abortion_callback: A callback to be called and passed an Abortion value
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
@ -494,9 +494,8 @@ class Stub(object):
request: The request value for the RPC.
response_consumer: A stream.Consumer to be called to accept the response
values of the RPC.
abortion_callback: A callback to be called to accept one of CANCELLED,
EXPIRED, NETWORK_FAILURE, or SERVICER_FAILURE in the event of RPC
abortion.
abortion_callback: A callback to be called and passed an Abortion value
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
@ -513,9 +512,8 @@ class Stub(object):
name: The RPC method name.
response_callback: A callback to be called to accept the response value
of the RPC.
abortion_callback: A callback to be called to accept one of CANCELLED,
EXPIRED, NETWORK_FAILURE, or SERVICER_FAILURE in the event of RPC
abortion.
abortion_callback: A callback to be called and passed an Abortion value
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
@ -533,9 +531,8 @@ class Stub(object):
name: The RPC method name.
response_consumer: A stream.Consumer to be called to accept the response
values of the RPC.
abortion_callback: A callback to be called to accept one of CANCELLED,
EXPIRED, NETWORK_FAILURE, or SERVICER_FAILURE in the event of RPC
abortion.
abortion_callback: A callback to be called and passed an Abortion value
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
Returns:

@ -176,7 +176,7 @@ class EventInvocationSynchronousEventServiceTestCase(
name, request, callback.complete, callback.abort, _TIMEOUT)
callback.block_until_terminated()
self.assertEqual(interfaces.EXPIRED, callback.abortion())
self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
def testExpiredUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -190,7 +190,7 @@ class EventInvocationSynchronousEventServiceTestCase(
name, request, callback, callback.abort, _TIMEOUT)
callback.block_until_terminated()
self.assertEqual(interfaces.EXPIRED, callback.abortion())
self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
def testExpiredStreamRequestUnaryResponse(self):
for name, test_messages_sequence in (
@ -202,7 +202,7 @@ class EventInvocationSynchronousEventServiceTestCase(
name, callback.complete, callback.abort, _TIMEOUT)
callback.block_until_terminated()
self.assertEqual(interfaces.EXPIRED, callback.abortion())
self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
def testExpiredStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -217,7 +217,7 @@ class EventInvocationSynchronousEventServiceTestCase(
request_consumer.consume(request)
callback.block_until_terminated()
self.assertEqual(interfaces.EXPIRED, callback.abortion())
self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
def testFailedUnaryRequestUnaryResponse(self):
for name, test_messages_sequence in (
@ -231,7 +231,7 @@ class EventInvocationSynchronousEventServiceTestCase(
name, request, callback.complete, callback.abort, _TIMEOUT)
callback.block_until_terminated()
self.assertEqual(interfaces.SERVICER_FAILURE, callback.abortion())
self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion())
def testFailedUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -245,7 +245,7 @@ class EventInvocationSynchronousEventServiceTestCase(
name, request, callback, callback.abort, _TIMEOUT)
callback.block_until_terminated()
self.assertEqual(interfaces.SERVICER_FAILURE, callback.abortion())
self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion())
def testFailedStreamRequestUnaryResponse(self):
for name, test_messages_sequence in (
@ -262,7 +262,7 @@ class EventInvocationSynchronousEventServiceTestCase(
request_consumer.terminate()
callback.block_until_terminated()
self.assertEqual(interfaces.SERVICER_FAILURE, callback.abortion())
self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion())
def testFailedStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -279,7 +279,7 @@ class EventInvocationSynchronousEventServiceTestCase(
request_consumer.terminate()
callback.block_until_terminated()
self.assertEqual(interfaces.SERVICER_FAILURE, callback.abortion())
self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion())
def testParallelInvocations(self):
for name, test_messages_sequence in (
@ -321,7 +321,7 @@ class EventInvocationSynchronousEventServiceTestCase(
call.cancel()
callback.block_until_terminated()
self.assertEqual(interfaces.CANCELLED, callback.abortion())
self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
def testCancelledUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -335,7 +335,7 @@ class EventInvocationSynchronousEventServiceTestCase(
call.cancel()
callback.block_until_terminated()
self.assertEqual(interfaces.CANCELLED, callback.abortion())
self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
def testCancelledStreamRequestUnaryResponse(self):
for name, test_messages_sequence in (
@ -351,7 +351,7 @@ class EventInvocationSynchronousEventServiceTestCase(
call.cancel()
callback.block_until_terminated()
self.assertEqual(interfaces.CANCELLED, callback.abortion())
self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
def testCancelledStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
@ -364,4 +364,4 @@ class EventInvocationSynchronousEventServiceTestCase(
call.cancel()
callback.block_until_terminated()
self.assertEqual(interfaces.CANCELLED, callback.abortion())
self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())

@ -35,18 +35,20 @@ namespace :spec do
t.pattern = spec_files
t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
t.rspec_opts = suite[:tags].map{ |t| "--tag #{t}" }.join(' ') if suite[:tags]
if suite[:tags]
t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ')
end
end
end
end
end
desc 'Run compiles the extension, runs all the tests'
desc 'Compiles the extension then runs all the tests'
task :all
task default: :all
task 'spec:suite:wrapper' => :compile
task 'spec:suite:wrapper' => [:compile, :rubocop]
task 'spec:suite:idiomatic' => 'spec:suite:wrapper'
task 'spec:suite:bidi' => 'spec:suite:wrapper'
task 'spec:suite:server' => 'spec:suite:wrapper'
task :all => ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server']
task all: ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server']

@ -0,0 +1,44 @@
# Copyright 2014, 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.
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: google/protobuf/empty.proto
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "google.protobuf.Empty" do
end
end
module Google
module Protobuf
Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass
end
end

@ -0,0 +1,278 @@
#!/usr/bin/env ruby
# Copyright 2014, 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.
# pubsub_demo demos accesses the Google PubSub API via its gRPC interface
#
# TODO: update the Usage once the usable auth gem is available
# $ SSL_CERT_FILE=<path/to/ssl/certs> \
# path/to/pubsub_demo.rb \
# --service_account_key_file=<path_to_service_account> \
# [--action=<chosen_demo_action> ]
#
# There are options related to the chosen action, see #parse_args below.
# - the possible actions are given by the method names of NamedAction class
# - the default action is list_some_topics
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
require 'optparse'
require 'grpc'
require 'google/protobuf'
require 'google/protobuf/empty'
require 'tech/pubsub/proto/pubsub'
require 'tech/pubsub/proto/pubsub_services'
# loads the certificates used to access the test server securely.
def load_prod_cert
fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
p "loading prod certs from #{ENV['SSL_CERT_FILE']}"
File.open(ENV['SSL_CERT_FILE']).read
end
# creates a SSL Credentials from the production certificates.
def ssl_creds
GRPC::Core::Credentials.new(load_prod_cert)
end
# Builds the metadata authentication update proc.
#
# TODO: replace this once the ruby usable auth repo is available.
def auth_proc(opts)
if GRPC::Auth::GCECredentials.on_gce?
return GRPC::Auth::GCECredentials.new.updater_proc
end
fd = StringIO.new(File.read(opts.oauth_key_file))
GRPC::Auth::ServiceAccountCredentials.new(opts.oauth_scope, fd).updater_proc
end
# Creates a stub for accessing the publisher service.
def publisher_stub(opts)
address = "#{opts.host}:#{opts.port}"
stub_clz = Tech::Pubsub::PublisherService::Stub # shorter
logger.info("... access PublisherService at #{address}")
stub_clz.new(address,
creds: ssl_creds, update_metadata: auth_proc(opts),
GRPC::Core::Channel::SSL_TARGET => opts.host)
end
# Creates a stub for accessing the subscriber service.
def subscriber_stub(opts)
address = "#{opts.host}:#{opts.port}"
stub_clz = Tech::Pubsub::SubscriberService::Stub # shorter
logger.info("... access SubscriberService at #{address}")
stub_clz.new(address,
creds: ssl_creds, update_metadata: auth_proc(opts),
GRPC::Core::Channel::SSL_TARGET => opts.host)
end
# defines methods corresponding to each interop test case.
class NamedActions
include Tech::Pubsub
# Initializes NamedActions
#
# @param pub [Stub] a stub for accessing the publisher service
# @param sub [Stub] a stub for accessing the publisher service
# @param args [Args] provides access to the command line
def initialize(pub, sub, args)
@pub = pub
@sub = sub
@args = args
end
# Removes the test topic if it exists
def remove_topic
name = test_topic_name
p "... removing Topic #{name}"
@pub.delete_topic(DeleteTopicRequest.new(topic: name))
p "removed Topic: #{name} OK"
rescue GRPC::BadStatus => e
p "Could not delete a topics: rpc failed with '#{e}'"
end
# Creates a test topic
def create_topic
name = test_topic_name
p "... creating Topic #{name}"
resp = @pub.create_topic(Topic.new(name: name))
p "created Topic: #{resp.name} OK"
rescue GRPC::BadStatus => e
p "Could not create a topics: rpc failed with '#{e}'"
end
# Lists topics in the project
def list_some_topics
p 'Listing topics'
p '-------------_'
list_project_topics.topic.each { |t| p t.name }
rescue GRPC::BadStatus => e
p "Could not list topics: rpc failed with '#{e}'"
end
# Checks if a topics exists in a project
def check_exists
name = test_topic_name
p "... checking for topic #{name}"
exists = topic_exists?(name)
p "#{name} is a topic" if exists
p "#{name} is not a topic" unless exists
rescue GRPC::BadStatus => e
p "Could not check for a topics: rpc failed with '#{e}'"
end
# Publishes some messages
def random_pub_sub
topic_name, sub_name = test_topic_name, test_sub_name
create_topic_if_needed(topic_name)
@sub.create_subscription(Subscription.new(name: sub_name,
topic: topic_name))
msg_count = rand(10..30)
msg_count.times do |x|
msg = PubsubMessage.new(data: "message #{x}")
@pub.publish(PublishRequest.new(topic: topic_name, message: msg))
end
p "Sent #{msg_count} messages to #{topic_name}, checking for them now."
batch = @sub.pull_batch(PullBatchRequest.new(subscription: sub_name,
max_events: msg_count))
ack_ids = batch.pull_responses.map { |x| x.ack_id }
p "Got #{ack_ids.size} messages; acknowledging them.."
@sub.acknowledge(AcknowledgeRequest.new(subscription: sub_name,
ack_id: ack_ids))
p "Test messages were acknowledged OK, deleting the subscription"
del_req = DeleteSubscriptionRequest.new(subscription: sub_name)
@sub.delete_subscription(del_req)
rescue GRPC::BadStatus => e
p "Could not do random pub sub: rpc failed with '#{e}'"
end
private
# test_topic_name is the topic name to use in this test.
def test_topic_name
unless @args.topic_name.nil?
return "/topics/#{@args.project_id}/#{@args.topic_name}"
end
now_text = Time.now.utc.strftime('%Y%m%d%H%M%S%L')
"/topics/#{@args.project_id}/#{ENV['USER']}-#{now_text}"
end
# test_sub_name is the subscription name to use in this test.
def test_sub_name
unless @args.sub_name.nil?
return "/subscriptions/#{@args.project_id}/#{@args.sub_name}"
end
now_text = Time.now.utc.strftime('%Y%m%d%H%M%S%L')
"/subscriptions/#{@args.project_id}/#{ENV['USER']}-#{now_text}"
end
# determines if the topic name exists
def topic_exists?(name)
topics = list_project_topics.topic.map { |t| t.name }
topics.include?(name)
end
def create_topic_if_needed(name)
return if topic_exists?(name)
@pub.create_topic(Topic.new(name: name))
end
def list_project_topics
q = "cloud.googleapis.com/project in (/projects/#{@args.project_id})"
@pub.list_topics(ListTopicsRequest.new(query: q))
end
end
# Args is used to hold the command line info.
Args = Struct.new(:host, :oauth_scope, :oauth_key_file, :port, :action,
:project_id, :topic_name, :sub_name)
# validates the the command line options, returning them as an Arg.
def parse_args
args = Args.new('pubsub-staging.googleapis.com',
'https://www.googleapis.com/auth/pubsub',
nil, 443, 'list_some_topics', 'stoked-keyword-656')
OptionParser.new do |opts|
opts.on('--oauth_scope scope',
'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
args.host = v
end
opts.on('--server_port SERVER_PORT', 'server port') do |v|
args.port = v
end
opts.on('--service_account_key_file PATH',
'Path to the service account json key file') do |v|
args.oauth_key_file = v
end
# instance_methods(false) gives only the methods defined in that class.
scenes = NamedActions.instance_methods(false).map { |t| t.to_s }
scene_list = scenes.join(',')
opts.on("--action CODE", scenes, {}, 'pick a demo action',
" (#{scene_list})") do |v|
args.action = v
end
# Set the remaining values.
%w(project_id topic_name sub_name).each do |o|
opts.on("--#{o} VALUE", "#{o}") do |v|
args[o] = v
end
end
end.parse!
_check_args(args)
end
def _check_args(args)
%w(host port action).each do |a|
if args[a].nil?
raise OptionParser::MissingArgument.new("please specify --#{a}")
end
end
if args['oauth_key_file'].nil? || args['oauth_scope'].nil?
fail(OptionParser::MissingArgument,
'please specify both of --service_account_key_file and --oauth_scope')
end
args
end
def main
args = parse_args
pub, sub = publisher_stub(args), subscriber_stub(args)
NamedActions.new(pub, sub, args).method(args.action).call
end
main

@ -0,0 +1,174 @@
# Copyright 2014, 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.
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: tech/pubsub/proto/pubsub.proto
require 'google/protobuf'
require 'google/protobuf/empty'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "tech.pubsub.Topic" do
optional :name, :string, 1
end
add_message "tech.pubsub.PubsubMessage" do
optional :data, :string, 1
optional :message_id, :string, 3
end
add_message "tech.pubsub.GetTopicRequest" do
optional :topic, :string, 1
end
add_message "tech.pubsub.PublishRequest" do
optional :topic, :string, 1
optional :message, :message, 2, "tech.pubsub.PubsubMessage"
end
add_message "tech.pubsub.PublishBatchRequest" do
optional :topic, :string, 1
repeated :messages, :message, 2, "tech.pubsub.PubsubMessage"
end
add_message "tech.pubsub.PublishBatchResponse" do
repeated :message_ids, :string, 1
end
add_message "tech.pubsub.ListTopicsRequest" do
optional :query, :string, 1
optional :max_results, :int32, 2
optional :page_token, :string, 3
end
add_message "tech.pubsub.ListTopicsResponse" do
repeated :topic, :message, 1, "tech.pubsub.Topic"
optional :next_page_token, :string, 2
end
add_message "tech.pubsub.DeleteTopicRequest" do
optional :topic, :string, 1
end
add_message "tech.pubsub.Subscription" do
optional :name, :string, 1
optional :topic, :string, 2
optional :query, :string, 3
optional :truncation_policy, :message, 4, "tech.pubsub.Subscription.TruncationPolicy"
optional :push_config, :message, 5, "tech.pubsub.PushConfig"
optional :ack_deadline_seconds, :int32, 6
optional :garbage_collect_seconds, :int64, 7
end
add_message "tech.pubsub.Subscription.TruncationPolicy" do
optional :max_bytes, :int64, 1
optional :max_age_seconds, :int64, 2
end
add_message "tech.pubsub.PushConfig" do
optional :push_endpoint, :string, 1
end
add_message "tech.pubsub.PubsubEvent" do
optional :subscription, :string, 1
optional :message, :message, 2, "tech.pubsub.PubsubMessage"
optional :truncated, :bool, 3
optional :deleted, :bool, 4
end
add_message "tech.pubsub.GetSubscriptionRequest" do
optional :subscription, :string, 1
end
add_message "tech.pubsub.ListSubscriptionsRequest" do
optional :query, :string, 1
optional :max_results, :int32, 3
optional :page_token, :string, 4
end
add_message "tech.pubsub.ListSubscriptionsResponse" do
repeated :subscription, :message, 1, "tech.pubsub.Subscription"
optional :next_page_token, :string, 2
end
add_message "tech.pubsub.TruncateSubscriptionRequest" do
optional :subscription, :string, 1
end
add_message "tech.pubsub.DeleteSubscriptionRequest" do
optional :subscription, :string, 1
end
add_message "tech.pubsub.ModifyPushConfigRequest" do
optional :subscription, :string, 1
optional :push_config, :message, 2, "tech.pubsub.PushConfig"
end
add_message "tech.pubsub.PullRequest" do
optional :subscription, :string, 1
optional :return_immediately, :bool, 2
end
add_message "tech.pubsub.PullResponse" do
optional :ack_id, :string, 1
optional :pubsub_event, :message, 2, "tech.pubsub.PubsubEvent"
end
add_message "tech.pubsub.PullBatchRequest" do
optional :subscription, :string, 1
optional :return_immediately, :bool, 2
optional :max_events, :int32, 3
end
add_message "tech.pubsub.PullBatchResponse" do
repeated :pull_responses, :message, 2, "tech.pubsub.PullResponse"
end
add_message "tech.pubsub.ModifyAckDeadlineRequest" do
optional :subscription, :string, 1
optional :ack_id, :string, 2
optional :ack_deadline_seconds, :int32, 3
end
add_message "tech.pubsub.AcknowledgeRequest" do
optional :subscription, :string, 1
repeated :ack_id, :string, 2
end
add_message "tech.pubsub.NackRequest" do
optional :subscription, :string, 1
repeated :ack_id, :string, 2
end
end
module Tech
module Pubsub
Topic = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Topic").msgclass
PubsubMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PubsubMessage").msgclass
GetTopicRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.GetTopicRequest").msgclass
PublishRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishRequest").msgclass
PublishBatchRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishBatchRequest").msgclass
PublishBatchResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishBatchResponse").msgclass
ListTopicsRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListTopicsRequest").msgclass
ListTopicsResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListTopicsResponse").msgclass
DeleteTopicRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.DeleteTopicRequest").msgclass
Subscription = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Subscription").msgclass
Subscription::TruncationPolicy = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Subscription.TruncationPolicy").msgclass
PushConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PushConfig").msgclass
PubsubEvent = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PubsubEvent").msgclass
GetSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.GetSubscriptionRequest").msgclass
ListSubscriptionsRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListSubscriptionsRequest").msgclass
ListSubscriptionsResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListSubscriptionsResponse").msgclass
TruncateSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.TruncateSubscriptionRequest").msgclass
DeleteSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.DeleteSubscriptionRequest").msgclass
ModifyPushConfigRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ModifyPushConfigRequest").msgclass
PullRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullRequest").msgclass
PullResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullResponse").msgclass
PullBatchRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullBatchRequest").msgclass
PullBatchResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullBatchResponse").msgclass
ModifyAckDeadlineRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ModifyAckDeadlineRequest").msgclass
AcknowledgeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.AcknowledgeRequest").msgclass
NackRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.NackRequest").msgclass
end
end

@ -0,0 +1,103 @@
# Copyright 2014, 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.
# Generated by the protocol buffer compiler. DO NOT EDIT!
# Source: tech/pubsub/proto/pubsub.proto for package 'tech.pubsub'
require 'grpc'
require 'google/protobuf/empty'
require 'tech/pubsub/proto/pubsub'
module Tech
module Pubsub
module PublisherService
# TODO: add proto service documentation here
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'tech.pubsub.PublisherService'
rpc :CreateTopic, Topic, Topic
rpc :Publish, PublishRequest, Google::Protobuf::Empty
rpc :PublishBatch, PublishBatchRequest, PublishBatchResponse
rpc :GetTopic, GetTopicRequest, Topic
rpc :ListTopics, ListTopicsRequest, ListTopicsResponse
rpc :DeleteTopic, DeleteTopicRequest, Google::Protobuf::Empty
end
Stub = Service.rpc_stub_class
end
module SubscriberService
# TODO: add proto service documentation here
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'tech.pubsub.SubscriberService'
rpc :CreateSubscription, Subscription, Subscription
rpc :GetSubscription, GetSubscriptionRequest, Subscription
rpc :ListSubscriptions, ListSubscriptionsRequest, ListSubscriptionsResponse
rpc :DeleteSubscription, DeleteSubscriptionRequest, Google::Protobuf::Empty
rpc :TruncateSubscription, TruncateSubscriptionRequest, Google::Protobuf::Empty
rpc :ModifyPushConfig, ModifyPushConfigRequest, Google::Protobuf::Empty
rpc :Pull, PullRequest, PullResponse
rpc :PullBatch, PullBatchRequest, PullBatchResponse
rpc :ModifyAckDeadline, ModifyAckDeadlineRequest, Google::Protobuf::Empty
rpc :Acknowledge, AcknowledgeRequest, Google::Protobuf::Empty
rpc :Nack, NackRequest, Google::Protobuf::Empty
end
Stub = Service.rpc_stub_class
end
module PushEndpointService
# TODO: add proto service documentation here
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'tech.pubsub.PushEndpointService'
rpc :HandlePubsubEvent, PubsubEvent, Google::Protobuf::Empty
end
Stub = Service.rpc_stub_class
end
end
end

@ -56,6 +56,8 @@ require 'test/cpp/interop/empty'
require 'signet/ssl_config'
include Google::RPC::Auth
# loads the certificates used to access the test server securely.
def load_test_certs
this_dir = File.expand_path(File.dirname(__FILE__))
@ -67,40 +69,54 @@ end
# loads the certificates used to access the test server securely.
def load_prod_cert
fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
p "loading prod certs from #{ENV['SSL_CERT_FILE']}"
logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
File.open(ENV['SSL_CERT_FILE']).read
end
# creates a Credentials from the test certificates.
# creates SSL Credentials from the test certificates.
def test_creds
certs = load_test_certs
GRPC::Core::Credentials.new(certs[0])
end
RX_CERT = /-----BEGIN CERTIFICATE-----\n.*?-----END CERTIFICATE-----\n/m
# creates a Credentials from the production certificates.
# creates SSL Credentials from the production certificates.
def prod_creds
cert_text = load_prod_cert
GRPC::Core::Credentials.new(cert_text)
end
# creates a test stub that accesses host:port securely.
def create_stub(host, port, is_secure, host_override, use_test_ca)
address = "#{host}:#{port}"
if is_secure
creds = nil
if use_test_ca
creds = test_creds
else
creds = prod_creds
end
# creates the SSL Credentials.
def ssl_creds(use_test_ca)
return test_creds if use_test_ca
prod_creds
end
# creates a test stub that accesses host:port securely.
def create_stub(opts)
address = "#{opts.host}:#{opts.port}"
if opts.secure
stub_opts = {
:creds => creds,
GRPC::Core::Channel::SSL_TARGET => host_override
:creds => ssl_creds(opts.use_test_ca),
GRPC::Core::Channel::SSL_TARGET => opts.host_override
}
# Add service account creds if specified
if %w(all service_account_creds).include?(opts.test_case)
unless opts.oauth_scope.nil?
fd = StringIO.new(File.read(opts.oauth_key_file))
logger.info("loading oauth certs from #{opts.oauth_key_file}")
auth_creds = ServiceAccountCredentials.new(opts.oauth_scope, fd)
stub_opts[:update_metadata] = auth_creds.updater_proc
end
end
# Add compute engine creds if specified
if %w(all compute_engine_creds).include?(opts.test_case)
unless opts.oauth_scope.nil?
stub_opts[:update_metadata] = GCECredentials.new.update_proc
end
end
logger.info("... connecting securely to #{address}")
Grpc::Testing::TestService::Stub.new(address, **stub_opts)
else
@ -158,9 +174,10 @@ class NamedTests
include Grpc::Testing::PayloadType
attr_accessor :assertions # required by Minitest::Assertions
def initialize(stub)
def initialize(stub, args)
@assertions = 0 # required by Minitest::Assertions
@stub = stub
@args = args
end
def empty_unary
@ -170,21 +187,37 @@ class NamedTests
end
def large_unary
req_size, wanted_response_size = 271_828, 314_159
payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
req = SimpleRequest.new(response_type: :COMPRESSABLE,
response_size: wanted_response_size,
payload: payload)
resp = @stub.unary_call(req)
assert_equal(:COMPRESSABLE, resp.payload.type,
'large_unary: payload had the wrong type')
assert_equal(wanted_response_size, resp.payload.body.length,
'large_unary: payload had the wrong length')
assert_equal(nulls(wanted_response_size), resp.payload.body,
'large_unary: payload content is invalid')
perform_large_unary
p 'OK: large_unary'
end
def service_account_creds
# ignore this test if the oauth options are not set
if @args.oauth_scope.nil? || @args.oauth_key_file.nil?
p 'NOT RUN: service_account_creds; no service_account settings'
return
end
json_key = File.read(@args.oauth_key_file)
wanted_email = MultiJson.load(json_key)['client_email']
resp = perform_large_unary(fill_username: true,
fill_oauth_scope: true)
assert_equal(wanted_email, resp.username,
'service_account_creds: incorrect username')
assert(@args.oauth_scope.include?(resp.oauth_scope),
'service_account_creds: incorrect oauth_scope')
p 'OK: service_account_creds'
end
def compute_engine_creds
resp = perform_large_unary(fill_username: true,
fill_oauth_scope: true)
assert(@args.oauth_scope.include?(resp.oauth_scope),
'service_account_creds: incorrect oauth_scope')
assert_equal(@args.default_service_account, resp.username,
'service_account_creds: incorrect username')
p 'OK: compute_engine_creds'
end
def client_streaming
msg_sizes = [27_182, 8, 1828, 45_904]
wanted_aggregate_size = 74_922
@ -230,64 +263,89 @@ class NamedTests
method(m).call
end
end
private
def perform_large_unary(fill_username: false, fill_oauth_scope: false)
req_size, wanted_response_size = 271_828, 314_159
payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
req = SimpleRequest.new(response_type: :COMPRESSABLE,
response_size: wanted_response_size,
payload: payload)
req.fill_username = fill_username
req.fill_oauth_scope = fill_oauth_scope
resp = @stub.unary_call(req)
assert_equal(:COMPRESSABLE, resp.payload.type,
'large_unary: payload had the wrong type')
assert_equal(wanted_response_size, resp.payload.body.length,
'large_unary: payload had the wrong length')
assert_equal(nulls(wanted_response_size), resp.payload.body,
'large_unary: payload content is invalid')
resp
end
end
# Args is used to hold the command line info.
Args = Struct.new(:default_service_account, :host, :host_override,
:oauth_scope, :oauth_key_file, :port, :secure, :test_case,
:use_test_ca)
# validates the the command line options, returning them as a Hash.
def parse_options
options = {
'secure' => false,
'server_host' => nil,
'server_host_override' => nil,
'server_port' => nil,
'test_case' => nil
}
def parse_args
args = Args.new
args.host_override = 'foo.test.google.com'
OptionParser.new do |opts|
opts.banner = 'Usage: --server_host <server_host> --server_port server_port'
opts.on('--oauth_scope scope',
'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
options['server_host'] = v
args['host'] = v
end
opts.on('--default_service_account email_address',
'email address of the default service account') do |v|
args['default_service_account'] = v
end
opts.on('--service_account_key_file PATH',
'Path to the service account json key file') do |v|
args['oauth_key_file'] = v
end
opts.on('--server_host_override HOST_OVERRIDE',
'override host via a HTTP header') do |v|
options['server_host_override'] = v
end
opts.on('--server_port SERVER_PORT', 'server port') do |v|
options['server_port'] = v
args['host_override'] = v
end
opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
# instance_methods(false) gives only the methods defined in that class
test_cases = NamedTests.instance_methods(false).map(&:to_s)
test_case_list = test_cases.join(',')
opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
" (#{test_case_list})") do |v|
options['test_case'] = v
end
" (#{test_case_list})") { |v| args['test_case'] = v }
opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
options['secure'] = v
args['secure'] = v
end
opts.on('-t', '--use_test_ca',
'if secure, use the test certificate?') do |v|
options['use_test_ca'] = v
args['use_test_ca'] = v
end
end.parse!
_check_options(options)
_check_args(args)
end
def _check_options(opts)
%w(server_host server_port test_case).each do |arg|
if opts[arg].nil?
def _check_args(args)
%w(host port test_case).each do |a|
if args[a].nil?
fail(OptionParser::MissingArgument, "please specify --#{arg}")
end
end
if opts['server_host_override'].nil?
opts['server_host_override'] = opts['server_host']
if args['oauth_key_file'].nil? ^ args['oauth_scope'].nil?
fail(OptionParser::MissingArgument,
'please specify both of --service_account_key_file and --oauth_scope')
end
opts
args
end
def main
opts = parse_options
stub = create_stub(opts['server_host'], opts['server_port'], opts['secure'],
opts['server_host_override'], opts['use_test_ca'])
NamedTests.new(stub).method(opts['test_case']).call
opts = parse_args
stub = create_stub(opts)
NamedTests.new(stub, opts).method(opts['test_case']).call
end
main

@ -41,10 +41,13 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
optional :response_type, :enum, 1, "grpc.testing.PayloadType"
optional :response_size, :int32, 2
optional :payload, :message, 3, "grpc.testing.Payload"
optional :fill_username, :bool, 4
optional :fill_oauth_scope, :bool, 5
end
add_message "grpc.testing.SimpleResponse" do
optional :payload, :message, 1, "grpc.testing.Payload"
optional :effective_gaia_user_id, :int64, 2
optional :username, :string, 2
optional :oauth_scope, :string, 3
end
add_message "grpc.testing.StreamingInputCallRequest" do
optional :payload, :message, 1, "grpc.testing.Payload"

@ -125,7 +125,7 @@ int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
md_obj_args[1] = rb_ary_entry(val, i);
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
md = grpc_rb_get_wrapped_metadata(md_obj);
err = grpc_call_add_metadata(call, md, NUM2UINT(flags));
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -136,7 +136,7 @@ int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
md_obj_args[1] = val;
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
md = grpc_rb_get_wrapped_metadata(md_obj);
err = grpc_call_add_metadata(call, md, NUM2UINT(flags));
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -220,8 +220,8 @@ static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) {
}
cq = grpc_rb_get_wrapped_completion_queue(cqueue);
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_invoke(call, cq, ROBJECT(metadata_read_tag),
ROBJECT(finished_tag), NUM2UINT(flags));
err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag),
ROBJECT(finished_tag), NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -242,7 +242,7 @@ static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) {
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_read(call, ROBJECT(tag));
err = grpc_call_start_read_old(call, ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start read failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -330,7 +330,7 @@ static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
}
bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_write(call, bfr, ROBJECT(tag), NUM2UINT(flags));
err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start write failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -358,8 +358,8 @@ static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_write_status(call, NUM2UINT(code),
StringValueCStr(status), ROBJECT(tag));
err = grpc_call_start_write_status_old(call, NUM2UINT(code),
StringValueCStr(status), ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start write status: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -374,7 +374,7 @@ static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) {
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_writes_done(call, ROBJECT(tag));
err = grpc_call_writes_done_old(call, ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "writes done: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -405,7 +405,7 @@ static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
flags = UINT2NUM(0); /* Default to no flags */
}
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_server_end_initial_metadata(call, NUM2UINT(flags));
err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -430,7 +430,7 @@ static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue);
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_server_accept(call, cq, ROBJECT(finished_tag));
err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);

@ -192,9 +192,10 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE method, VALUE host,
rb_raise(rb_eRuntimeError, "closed!");
}
call = grpc_channel_create_call(ch, method_chars, host_chars,
grpc_rb_time_timeval(deadline,
/* absolute time */ 0));
call =
grpc_channel_create_call_old(ch, method_chars, host_chars,
grpc_rb_time_timeval(deadline,
/* absolute time */ 0));
if (call == NULL) {
rb_raise(rb_eRuntimeError, "cannot create call with method %s",
method_chars);

@ -175,7 +175,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE tag_new) {
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
} else {
err = grpc_server_request_call(s->wrapped, ROBJECT(tag_new));
err = grpc_server_request_call_old(s->wrapped, ROBJECT(tag_new));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "server request failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);

@ -1,3 +1,4 @@
# -*- ruby -*-
# encoding: utf-8
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
require 'grpc/version'
@ -19,11 +20,14 @@ Gem::Specification.new do |s|
s.require_paths = ['lib']
s.platform = Gem::Platform::RUBY
s.add_dependency 'xray'
s.add_dependency 'logging', '~> 1.8'
s.add_dependency 'faraday', '~> 0.9'
s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
s.add_dependency 'signet', '~> 0.5.1'
s.add_dependency 'logging', '~> 1.8'
s.add_dependency 'jwt', '~> 1.2.1'
s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests
s.add_dependency 'multi_json', '1.10.1'
s.add_dependency 'signet', '~> 0.6.0'
s.add_dependency 'xray', '~> 1.1'
s.add_development_dependency 'bundler', '~> 1.7'
s.add_development_dependency 'rake', '~> 10.0'

@ -27,6 +27,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc/auth/compute_engine.rb'
require 'grpc/auth/service_account.rb'
require 'grpc/errors'
require 'grpc/grpc'
require 'grpc/logconfig'

@ -0,0 +1,69 @@
# 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.
require 'faraday'
require 'grpc/auth/signet'
module Google
module RPC
# Module Auth provides classes that provide Google-specific authentication
# used to access Google gRPC services.
module Auth
# Extends Signet::OAuth2::Client so that the auth token is obtained from
# the GCE metadata server.
class GCECredentials < Signet::OAuth2::Client
COMPUTE_AUTH_TOKEN_URI = 'http://metadata/computeMetadata/v1/'\
'instance/service-accounts/default/token'
COMPUTE_CHECK_URI = 'http://metadata.google.internal'
# Detect if this appear to be a GCE instance, by checking if metadata
# is available
def self.on_gce?(options = {})
c = options[:connection] || Faraday.default_connection
resp = c.get(COMPUTE_CHECK_URI)
return false unless resp.status == 200
return false unless resp.headers.key?('Metadata-Flavor')
return resp.headers['Metadata-Flavor'] == 'Google'
rescue Faraday::ConnectionFailed
return false
end
# Overrides the super class method to change how access tokens are
# fetched.
def fetch_access_token(options = {})
c = options[:connection] || Faraday.default_connection
c.headers = { 'Metadata-Flavor' => 'Google' }
resp = c.get(COMPUTE_AUTH_TOKEN_URI)
Signet::OAuth2.parse_credentials(resp.body,
resp.headers['content-type'])
end
end
end
end
end

@ -0,0 +1,68 @@
# 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.
require 'grpc/auth/signet'
require 'multi_json'
require 'openssl'
# Reads the private key and client email fields from service account JSON key.
def read_json_key(json_key_io)
json_key = MultiJson.load(json_key_io.read)
fail 'missing client_email' unless json_key.key?('client_email')
fail 'missing private_key' unless json_key.key?('private_key')
[json_key['private_key'], json_key['client_email']]
end
module Google
module RPC
# Module Auth provides classes that provide Google-specific authentication
# used to access Google gRPC services.
module Auth
# Authenticates requests using Google's Service Account credentials.
# (cf https://developers.google.com/accounts/docs/OAuth2ServiceAccount)
class ServiceAccountCredentials < Signet::OAuth2::Client
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
AUDIENCE = TOKEN_CRED_URI
# Initializes a ServiceAccountCredentials.
#
# @param scope [string|array] the scope(s) to access
# @param json_key_io [IO] an IO from which the JSON key can be read
def initialize(scope, json_key_io)
private_key, client_email = read_json_key(json_key_io)
super(token_credential_uri: TOKEN_CRED_URI,
audience: AUDIENCE,
scope: scope,
issuer: client_email,
signing_key: OpenSSL::PKey::RSA.new(private_key))
end
end
end
end
end

@ -0,0 +1,67 @@
# 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.
require 'signet/oauth_2/client'
module Signet
# Signet::OAuth2 supports OAuth2 authentication.
module OAuth2
AUTH_METADATA_KEY = :Authorization
# Signet::OAuth2::Client creates an OAuth2 client
#
# Here client is re-opened to add the #apply and #apply! methods which
# update a hash map with the fetched authentication token
#
# Eventually, this change may be merged into signet itself, or some other
# package that provides Google-specific auth via signet, and this extension
# will be unnecessary.
class Client
# Updates a_hash updated with the authentication token
def apply!(a_hash, opts = {})
# fetch the access token there is currently not one, or if the client
# has expired
fetch_access_token!(opts) if access_token.nil? || expired?
a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}"
end
# Returns a clone of a_hash updated with the authentication token
def apply(a_hash, opts = {})
a_copy = a_hash.clone
apply!(a_copy, opts)
a_copy
end
# Returns a reference to the #apply method, suitable for passing as
# a closure
def updater_proc
lambda(&method(:apply))
end
end
end
end

@ -0,0 +1,163 @@
# 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.
spec_dir = File.expand_path(File.join(File.dirname(__FILE__)))
$LOAD_PATH.unshift(spec_dir)
$LOAD_PATH.uniq!
require 'faraday'
require 'spec_helper'
def build_json_response(payload)
[200,
{ 'Content-Type' => 'application/json; charset=utf-8' },
MultiJson.dump(payload)]
end
WANTED_AUTH_KEY = :Authorization
shared_examples 'apply/apply! are OK' do
# tests that use these examples need to define
#
# @client which should be an auth client
#
# @make_auth_stubs, which should stub out the expected http behaviour of the
# auth client
describe '#fetch_access_token' do
it 'should set access_token to the fetched value' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
@client.fetch_access_token!(connection: c)
expect(@client.access_token).to eq(token)
stubs.verify_stubbed_calls
end
end
describe '#apply!' do
it 'should update the target hash with fetched access token' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' }
@client.apply!(md, connection: c)
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" }
expect(md).to eq(want)
stubs.verify_stubbed_calls
end
end
describe 'updater_proc' do
it 'should provide a proc that updates a hash with the access token' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' }
the_proc = @client.updater_proc
got = the_proc.call(md, connection: c)
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" }
expect(got).to eq(want)
stubs.verify_stubbed_calls
end
end
describe '#apply' do
it 'should not update the original hash with the access token' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' }
@client.apply(md, connection: c)
want = { foo: 'bar' }
expect(md).to eq(want)
stubs.verify_stubbed_calls
end
it 'should add the token to the returned hash' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' }
got = @client.apply(md, connection: c)
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" }
expect(got).to eq(want)
stubs.verify_stubbed_calls
end
it 'should not fetch a new token if the current is not expired' do
token = '1/abcdef1234567890'
stubs = make_auth_stubs with_access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
n = 5 # arbitrary
n.times do |_t|
md = { foo: 'bar' }
got = @client.apply(md, connection: c)
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" }
expect(got).to eq(want)
end
stubs.verify_stubbed_calls
end
it 'should fetch a new token if the current one is expired' do
token_1 = '1/abcdef1234567890'
token_2 = '2/abcdef1234567890'
[token_1, token_2].each do |t|
stubs = make_auth_stubs with_access_token: t
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' }
got = @client.apply(md, connection: c)
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{t}" }
expect(got).to eq(want)
stubs.verify_stubbed_calls
@client.expires_at -= 3601 # default is to expire in 1hr
end
end
end
end

@ -0,0 +1,108 @@
# 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.
spec_dir = File.expand_path(File.join(File.dirname(__FILE__)))
$LOAD_PATH.unshift(spec_dir)
$LOAD_PATH.uniq!
require 'apply_auth_examples'
require 'faraday'
require 'grpc/auth/compute_engine'
require 'spec_helper'
describe Google::RPC::Auth::GCECredentials do
MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token'
GCECredentials = Google::RPC::Auth::GCECredentials
before(:example) do
@client = GCECredentials.new
end
def make_auth_stubs(with_access_token: '')
Faraday::Adapter::Test::Stubs.new do |stub|
stub.get(MD_URI) do |env|
headers = env[:request_headers]
expect(headers['Metadata-Flavor']).to eq('Google')
build_json_response(
'access_token' => with_access_token,
'token_type' => 'Bearer',
'expires_in' => 3600)
end
end
end
it_behaves_like 'apply/apply! are OK'
describe '#on_gce?' do
it 'should be true when Metadata-Flavor is Google' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/') do |_env|
[200,
{ 'Metadata-Flavor' => 'Google' },
'']
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(true)
stubs.verify_stubbed_calls
end
it 'should be false when Metadata-Flavor is not Google' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/') do |_env|
[200,
{ 'Metadata-Flavor' => 'NotGoogle' },
'']
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(false)
stubs.verify_stubbed_calls
end
it 'should be false if the response is not 200' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/') do |_env|
[404,
{ 'Metadata-Flavor' => 'Google' },
'']
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(false)
stubs.verify_stubbed_calls
end
end
end

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save