mirror of https://github.com/grpc/grpc.git
Resolve a conflict between adding write buffer hint and the change of API Conflicts: src/cpp/server/async_server_context.ccpull/388/head
commit
280744ec64
158 changed files with 3546 additions and 1312 deletions
@ -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" |
@ -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
|
@ -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; |
||||
} |
@ -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__ */ |
@ -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 |
@ -1,6 +0,0 @@ |
||||
<?php |
||||
function getNewPort() { |
||||
static $port = 10000; |
||||
$port += 1; |
||||
return $port; |
||||
} |
@ -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 |
@ -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…
Reference in new issue