protobuffy 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CHANGES.md +261 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +14 -0
- data/README.md +58 -0
- data/Rakefile +61 -0
- data/bin/protoc-gen-ruby +17 -0
- data/bin/rpc_server +4 -0
- data/examples/bin/reverse-client-http +4 -0
- data/examples/bin/reverse-client-socket +4 -0
- data/examples/bin/reverse-client-zmq +4 -0
- data/examples/config.ru +6 -0
- data/examples/definitions/example/reverse.proto +12 -0
- data/examples/lib/example/reverse-client.rb +23 -0
- data/examples/lib/example/reverse-service.rb +9 -0
- data/examples/lib/example/reverse.pb.rb +36 -0
- data/lib/protobuf.rb +106 -0
- data/lib/protobuf/cli.rb +249 -0
- data/lib/protobuf/code_generator.rb +41 -0
- data/lib/protobuf/decoder.rb +74 -0
- data/lib/protobuf/deprecator.rb +42 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
- data/lib/protobuf/encoder.rb +62 -0
- data/lib/protobuf/enum.rb +319 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +280 -0
- data/lib/protobuf/field/bool_field.rb +53 -0
- data/lib/protobuf/field/bytes_field.rb +81 -0
- data/lib/protobuf/field/double_field.rb +26 -0
- data/lib/protobuf/field/enum_field.rb +57 -0
- data/lib/protobuf/field/field_array.rb +86 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +29 -0
- data/lib/protobuf/field/float_field.rb +38 -0
- data/lib/protobuf/field/int32_field.rb +22 -0
- data/lib/protobuf/field/int64_field.rb +22 -0
- data/lib/protobuf/field/integer_field.rb +24 -0
- data/lib/protobuf/field/message_field.rb +66 -0
- data/lib/protobuf/field/sfixed32_field.rb +28 -0
- data/lib/protobuf/field/sfixed64_field.rb +29 -0
- data/lib/protobuf/field/signed_integer_field.rb +30 -0
- data/lib/protobuf/field/sint32_field.rb +22 -0
- data/lib/protobuf/field/sint64_field.rb +22 -0
- data/lib/protobuf/field/string_field.rb +35 -0
- data/lib/protobuf/field/uint32_field.rb +22 -0
- data/lib/protobuf/field/uint64_field.rb +22 -0
- data/lib/protobuf/field/varint_field.rb +68 -0
- data/lib/protobuf/generators/base.rb +71 -0
- data/lib/protobuf/generators/enum_generator.rb +42 -0
- data/lib/protobuf/generators/extension_generator.rb +28 -0
- data/lib/protobuf/generators/field_generator.rb +132 -0
- data/lib/protobuf/generators/file_generator.rb +140 -0
- data/lib/protobuf/generators/group_generator.rb +113 -0
- data/lib/protobuf/generators/message_generator.rb +99 -0
- data/lib/protobuf/generators/printable.rb +161 -0
- data/lib/protobuf/generators/service_generator.rb +27 -0
- data/lib/protobuf/http.rb +20 -0
- data/lib/protobuf/lifecycle.rb +46 -0
- data/lib/protobuf/logger.rb +86 -0
- data/lib/protobuf/message.rb +182 -0
- data/lib/protobuf/message/fields.rb +122 -0
- data/lib/protobuf/message/serialization.rb +84 -0
- data/lib/protobuf/optionable.rb +23 -0
- data/lib/protobuf/rpc/buffer.rb +79 -0
- data/lib/protobuf/rpc/client.rb +168 -0
- data/lib/protobuf/rpc/connector.rb +21 -0
- data/lib/protobuf/rpc/connectors/base.rb +54 -0
- data/lib/protobuf/rpc/connectors/common.rb +172 -0
- data/lib/protobuf/rpc/connectors/http.rb +90 -0
- data/lib/protobuf/rpc/connectors/socket.rb +73 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
- data/lib/protobuf/rpc/env.rb +58 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
- data/lib/protobuf/rpc/middleware/logger.rb +91 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +53 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/http/server.rb +101 -0
- data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
- data/lib/protobuf/rpc/service.rb +179 -0
- data/lib/protobuf/rpc/service_directory.rb +245 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
- data/lib/protobuf/rpc/service_filters.rb +273 -0
- data/lib/protobuf/rpc/stat.rb +148 -0
- data/lib/protobuf/socket.rb +22 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +61 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +620 -0
- data/proto/rpc.proto +62 -0
- data/protobuffy.gemspec +37 -0
- data/spec/benchmark/tasks.rb +113 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
- data/spec/data/data.bin +3 -0
- data/spec/data/types.bin +0 -0
- data/spec/encoding/all_types_spec.rb +91 -0
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +103 -0
- data/spec/lib/protobuf/cli_spec.rb +267 -0
- data/spec/lib/protobuf/code_generator_spec.rb +60 -0
- data/spec/lib/protobuf/enum_spec.rb +239 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
- data/spec/lib/protobuf/field_spec.rb +194 -0
- data/spec/lib/protobuf/generators/base_spec.rb +87 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
- data/spec/lib/protobuf/logger_spec.rb +136 -0
- data/spec/lib/protobuf/message_spec.rb +368 -0
- data/spec/lib/protobuf/optionable_spec.rb +46 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
- data/spec/lib/protobuf_spec.rb +78 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/support/all.rb +7 -0
- data/spec/support/packed_field.rb +22 -0
- data/spec/support/server.rb +94 -0
- data/spec/support/test/all_types.data.bin +0 -0
- data/spec/support/test/all_types.data.txt +119 -0
- data/spec/support/test/defaults.pb.rb +25 -0
- data/spec/support/test/defaults.proto +9 -0
- data/spec/support/test/enum.pb.rb +59 -0
- data/spec/support/test/enum.proto +34 -0
- data/spec/support/test/extended.pb.rb +22 -0
- data/spec/support/test/extended.proto +10 -0
- data/spec/support/test/extreme_values.data.bin +0 -0
- data/spec/support/test/google_unittest.pb.rb +543 -0
- data/spec/support/test/google_unittest.proto +713 -0
- data/spec/support/test/google_unittest_import.pb.rb +37 -0
- data/spec/support/test/google_unittest_import.proto +64 -0
- data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
- data/spec/support/test/google_unittest_import_public.proto +38 -0
- data/spec/support/test/multi_field_extensions.pb.rb +56 -0
- data/spec/support/test/multi_field_extensions.proto +33 -0
- data/spec/support/test/resource.pb.rb +117 -0
- data/spec/support/test/resource.proto +94 -0
- data/spec/support/test/resource_service.rb +26 -0
- data/spec/support/test_app_file.rb +2 -0
- data/spec/support/tolerance_matcher.rb +40 -0
- metadata +367 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'protobuf/zmq'
|
3
|
+
|
4
|
+
describe ::Protobuf::Rpc::Connectors::Zmq do
|
5
|
+
subject { described_class.new(options) }
|
6
|
+
|
7
|
+
it_behaves_like "a Protobuf Connector"
|
8
|
+
|
9
|
+
specify{ described_class.include?(Protobuf::Rpc::Connectors::Common).should be_true }
|
10
|
+
|
11
|
+
let(:options) {{
|
12
|
+
:service => "Test::Service",
|
13
|
+
:method => "find",
|
14
|
+
:timeout => 3,
|
15
|
+
:host => "127.0.0.1",
|
16
|
+
:port => "9400"
|
17
|
+
}}
|
18
|
+
|
19
|
+
let(:socket_double) do
|
20
|
+
sm = double(::ZMQ::Socket)
|
21
|
+
sm.stub(:connect).and_return(0)
|
22
|
+
sm
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:zmq_context_double) do
|
26
|
+
zc = double(::ZMQ::Context)
|
27
|
+
zc.stub(:socket).and_return(socket_double)
|
28
|
+
zc
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
::ZMQ::Context.stub(:new).and_return(zmq_context_double)
|
33
|
+
end
|
34
|
+
|
35
|
+
before(:all) do
|
36
|
+
@ping_port_before = ENV['PB_RPC_PING_PORT']
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:all) do
|
40
|
+
ENV['PB_RPC_PING_PORT'] = @ping_port_before
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#lookup_server_uri" do
|
44
|
+
let(:service_directory) { double('ServiceDirectory', :running? => running? ) }
|
45
|
+
let(:listing) { double('Listing', :address => '127.0.0.2', :port => 9399) }
|
46
|
+
let(:listings) { [listing] }
|
47
|
+
let(:running?) { true }
|
48
|
+
|
49
|
+
before do
|
50
|
+
subject.stub(:service_directory) { service_directory }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the service directory is running" do
|
54
|
+
it "searches the service directory" do
|
55
|
+
service_directory.stub(:all_listings_for).and_return(listings)
|
56
|
+
subject.send(:lookup_server_uri).should eq "tcp://127.0.0.2:9399"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "defaults to the options" do
|
60
|
+
service_directory.stub(:all_listings_for).and_return([])
|
61
|
+
subject.send(:lookup_server_uri).should eq "tcp://127.0.0.1:9400"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the service directory is not running" do
|
66
|
+
let(:running?) { false }
|
67
|
+
|
68
|
+
it "defaults to the options" do
|
69
|
+
service_directory.stub(:all_listings_for).and_return([])
|
70
|
+
subject.send(:lookup_server_uri).should eq "tcp://127.0.0.1:9400"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "checks if the server is alive" do
|
75
|
+
service_directory.stub(:all_listings_for).and_return([])
|
76
|
+
subject.should_receive(:host_alive?).with("127.0.0.1") { true }
|
77
|
+
subject.send(:lookup_server_uri).should eq "tcp://127.0.0.1:9400"
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when no host is alive" do
|
81
|
+
it "raises an error" do
|
82
|
+
service_directory.stub(:all_listings_for).and_return(listings)
|
83
|
+
subject.stub(:host_alive?).and_return(false)
|
84
|
+
expect { subject.send(:lookup_server_uri) }.to raise_error
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#host_alive?" do
|
91
|
+
context "when the PB_RPC_PING_PORT is not set" do
|
92
|
+
before do
|
93
|
+
ENV.delete("PB_RPC_PING_PORT")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns true" do
|
97
|
+
subject.send(:host_alive?, "yip.yip").should be_true
|
98
|
+
end
|
99
|
+
|
100
|
+
it "does not attempt a connection" do
|
101
|
+
TCPSocket.should_not_receive(:new)
|
102
|
+
subject.send(:host_alive?, "blargh.com")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when the PB_RPC_PING_PORT is set" do
|
107
|
+
before do
|
108
|
+
ENV["PB_RPC_PING_PORT"] = "3307"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns true when the connection succeeds" do
|
112
|
+
TCPSocket.should_receive(:new).with("huzzah.com", 3307) { double(:close => nil) }
|
113
|
+
subject.send(:host_alive?, "huzzah.com").should be_true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns false when the connection fails" do
|
117
|
+
TCPSocket.should_receive(:new).with("hayoob.com", 3307).and_raise(Errno::ECONNREFUSED)
|
118
|
+
subject.send(:host_alive?, "hayoob.com").should be_false
|
119
|
+
end
|
120
|
+
|
121
|
+
it "closes the socket" do
|
122
|
+
socket = double("TCPSocket")
|
123
|
+
socket.should_receive(:close)
|
124
|
+
TCPSocket.should_receive(:new).with("absorbalof.com", 3307) { socket }
|
125
|
+
subject.send(:host_alive?, "absorbalof.com").should be_true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Protobuf::Rpc::Middleware::ExceptionHandler do
|
4
|
+
let(:app) { Proc.new { |env| env } }
|
5
|
+
let(:env) { Protobuf::Rpc::Env.new }
|
6
|
+
|
7
|
+
subject { described_class.new(app) }
|
8
|
+
|
9
|
+
describe "#call" do
|
10
|
+
it "calls the stack" do
|
11
|
+
app.should_receive(:call).with(env)
|
12
|
+
subject.call(env)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns the env" do
|
16
|
+
subject.call(env).should eq env
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when exceptions occur" do
|
20
|
+
let(:encoded_error) { error.encode }
|
21
|
+
let(:error) { Protobuf::Rpc::MethodNotFound.new('Boom!') }
|
22
|
+
|
23
|
+
before { app.stub(:call).and_raise(error, 'Boom!') }
|
24
|
+
|
25
|
+
it "rescues exceptions" do
|
26
|
+
expect { subject.call(env) }.not_to raise_exception
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when exception is a Protobuf error" do
|
30
|
+
it "does not wrap the exception in a generic Protobuf error" do
|
31
|
+
stack_env = subject.call(env)
|
32
|
+
|
33
|
+
# Can't compare the error instances because the response has been
|
34
|
+
# raised and thus has a backtrace while the error does not.
|
35
|
+
stack_env.response.class.should eq error.class
|
36
|
+
end
|
37
|
+
|
38
|
+
it "encodes the response" do
|
39
|
+
stack_env = subject.call(env)
|
40
|
+
stack_env.encoded_response.should eq encoded_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when exception is not a Protobuf error" do
|
45
|
+
let(:encoded_error) { error.encode }
|
46
|
+
let(:error) { Protobuf::Rpc::RpcFailed.new('Boom!') }
|
47
|
+
|
48
|
+
before { app.stub(:call).and_raise(RuntimeError, 'Boom!') }
|
49
|
+
|
50
|
+
it "wraps the exception in a generic Protobuf error" do
|
51
|
+
stack_env = subject.call(env)
|
52
|
+
stack_env.response.should eq error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "encodes the wrapped exception" do
|
56
|
+
stack_env = subject.call(env)
|
57
|
+
stack_env.encoded_response.should eq encoded_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Protobuf::Rpc::Middleware::Logger do
|
4
|
+
let(:app) { Proc.new { |inner_env| inner_env } }
|
5
|
+
let(:env) {
|
6
|
+
Protobuf::Rpc::Env.new(
|
7
|
+
'client_host' => 'client_host.test.co',
|
8
|
+
'encoded_request' => request_wrapper.encode,
|
9
|
+
'encoded_response' => response_wrapper.encode,
|
10
|
+
'method_name' => method_name,
|
11
|
+
'request' => request,
|
12
|
+
'request_type' => rpc_method.request_type,
|
13
|
+
'response' => response,
|
14
|
+
'response_type' => rpc_method.response_type,
|
15
|
+
'rpc_method' => rpc_method,
|
16
|
+
'rpc_service' => service_class,
|
17
|
+
'service_name' => service_name,
|
18
|
+
)
|
19
|
+
}
|
20
|
+
let(:method_name) { :find }
|
21
|
+
let(:request) { request_type.new(:name => 'required') }
|
22
|
+
let(:request_type) { rpc_method.request_type }
|
23
|
+
let(:request_wrapper) {
|
24
|
+
Protobuf::Socketrpc::Request.new(
|
25
|
+
:service_name => service_name,
|
26
|
+
:method_name => method_name.to_s,
|
27
|
+
:request_proto => request
|
28
|
+
)
|
29
|
+
}
|
30
|
+
let(:response_wrapper) { Protobuf::Socketrpc::Response.new(:response_proto => response) }
|
31
|
+
let(:response) { rpc_method.response_type.new(:name => 'required') }
|
32
|
+
let(:rpc_method) { service_class.rpcs[method_name] }
|
33
|
+
let(:rpc_service) { service_class.new(env) }
|
34
|
+
let(:service_class) { Test::ResourceService }
|
35
|
+
let(:service_name) { service_class.to_s }
|
36
|
+
|
37
|
+
subject { described_class.new(app) }
|
38
|
+
|
39
|
+
describe "#call" do
|
40
|
+
it "calls the stack" do
|
41
|
+
app.should_receive(:call).with(env)
|
42
|
+
subject.call(env)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns the env" do
|
46
|
+
subject.call(env).should eq env
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Protobuf::Rpc::Middleware::RequestDecoder do
|
4
|
+
let(:app) { Proc.new { |env| env } }
|
5
|
+
let(:client_host) { 'client_host.test.co' }
|
6
|
+
let(:env) {
|
7
|
+
Protobuf::Rpc::Env.new(
|
8
|
+
'encoded_request' => encoded_request,
|
9
|
+
'log_signature' => 'log_signature'
|
10
|
+
)
|
11
|
+
}
|
12
|
+
let(:encoded_request) { request_wrapper.encode }
|
13
|
+
let(:method_name) { :find }
|
14
|
+
let(:request) { request_type.new(:name => 'required') }
|
15
|
+
let(:request_type) { rpc_method.request_type }
|
16
|
+
let(:request_wrapper) {
|
17
|
+
Protobuf::Socketrpc::Request.new(
|
18
|
+
:caller => client_host,
|
19
|
+
:service_name => service_name,
|
20
|
+
:method_name => method_name.to_s,
|
21
|
+
:request_proto => request
|
22
|
+
)
|
23
|
+
}
|
24
|
+
let(:response_type) { rpc_method.response_type }
|
25
|
+
let(:rpc_method) { rpc_service.rpcs[method_name] }
|
26
|
+
let(:rpc_service) { Test::ResourceService }
|
27
|
+
let(:service_name) { rpc_service.to_s }
|
28
|
+
|
29
|
+
subject { described_class.new(app) }
|
30
|
+
|
31
|
+
describe "#call" do
|
32
|
+
it "decodes the request" do
|
33
|
+
stack_env = subject.call(env)
|
34
|
+
stack_env.request.should eq request
|
35
|
+
end
|
36
|
+
|
37
|
+
it "calls the stack" do
|
38
|
+
app.should_receive(:call).with(env)
|
39
|
+
subject.call(env)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "sets Env#client_host" do
|
43
|
+
stack_env = subject.call(env)
|
44
|
+
stack_env.client_host.should eq client_host
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets Env#service_name" do
|
48
|
+
stack_env = subject.call(env)
|
49
|
+
stack_env.service_name.should eq service_name
|
50
|
+
end
|
51
|
+
|
52
|
+
it "sets Env#method_name" do
|
53
|
+
stack_env = subject.call(env)
|
54
|
+
stack_env.method_name.should eq method_name.to_sym
|
55
|
+
end
|
56
|
+
|
57
|
+
it "sets Env#request_type" do
|
58
|
+
stack_env = subject.call(env)
|
59
|
+
stack_env.request_type.should eq request_type
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets Env#response_type" do
|
63
|
+
stack_env = subject.call(env)
|
64
|
+
stack_env.response_type.should eq response_type
|
65
|
+
end
|
66
|
+
|
67
|
+
it "sets Env#rpc_method" do
|
68
|
+
stack_env = subject.call(env)
|
69
|
+
stack_env.rpc_method.should eq rpc_method
|
70
|
+
end
|
71
|
+
|
72
|
+
it "sets Env#rpc_service" do
|
73
|
+
stack_env = subject.call(env)
|
74
|
+
stack_env.rpc_service.should eq rpc_service
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when decoding fails" do
|
78
|
+
before { Protobuf::Socketrpc::Request.stub(:decode).and_raise(RuntimeError) }
|
79
|
+
|
80
|
+
it "raises a bad request data exception" do
|
81
|
+
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::BadRequestData)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when the RPC service is not defined" do
|
86
|
+
let(:request_wrapper) {
|
87
|
+
Protobuf::Socketrpc::Request.new(
|
88
|
+
:caller => client_host,
|
89
|
+
:service_name => 'Foo',
|
90
|
+
:method_name => method_name.to_s,
|
91
|
+
:request_proto => request
|
92
|
+
)
|
93
|
+
}
|
94
|
+
|
95
|
+
it "raises a bad request data exception" do
|
96
|
+
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::ServiceNotFound)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when RPC method is not defined" do
|
101
|
+
let(:request_wrapper) {
|
102
|
+
Protobuf::Socketrpc::Request.new(
|
103
|
+
:caller => client_host,
|
104
|
+
:service_name => service_name,
|
105
|
+
:method_name => 'foo',
|
106
|
+
:request_proto => request
|
107
|
+
)
|
108
|
+
}
|
109
|
+
|
110
|
+
it "raises a bad request data exception" do
|
111
|
+
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::MethodNotFound)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
4
|
+
let(:app) { Proc.new { |env| env.response = response; env } }
|
5
|
+
let(:env) {
|
6
|
+
Protobuf::Rpc::Env.new(
|
7
|
+
'response_type' => Test::Resource,
|
8
|
+
'log_signature' => 'log_signature'
|
9
|
+
)
|
10
|
+
}
|
11
|
+
let(:encoded_response) { response_wrapper.encode }
|
12
|
+
let(:response) { Test::Resource.new(:name => 'required') }
|
13
|
+
let(:response_wrapper) { Protobuf::Socketrpc::Response.new(:response_proto => response) }
|
14
|
+
|
15
|
+
subject { described_class.new(app) }
|
16
|
+
|
17
|
+
describe "#call" do
|
18
|
+
it "encodes the response" do
|
19
|
+
stack_env = subject.call(env)
|
20
|
+
stack_env.encoded_response.should eq encoded_response
|
21
|
+
end
|
22
|
+
|
23
|
+
it "calls the stack" do
|
24
|
+
stack_env = subject.call(env)
|
25
|
+
stack_env.response.should eq response
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when response is responds to :to_hash" do
|
29
|
+
let(:app) { proc { |env| env.response = hashable; env } }
|
30
|
+
let(:hashable) { double('hashable', :to_hash => response.to_hash) }
|
31
|
+
|
32
|
+
it "sets Env#response" do
|
33
|
+
stack_env = subject.call(env)
|
34
|
+
stack_env.response.should eq response
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when response is responds to :to_proto" do
|
39
|
+
let(:app) { proc { |env| env.response = protoable; env } }
|
40
|
+
let(:protoable) { double('protoable', :to_proto => response) }
|
41
|
+
|
42
|
+
it "sets Env#response" do
|
43
|
+
stack_env = subject.call(env)
|
44
|
+
stack_env.response.should eq response
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when response is not a valid response type" do
|
49
|
+
let(:app) { proc { |env| env.response = "I'm not a valid response"; env } }
|
50
|
+
|
51
|
+
it "raises a bad response proto exception" do
|
52
|
+
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::BadResponseProto)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when response is a Protobuf error" do
|
57
|
+
let(:app) { proc { |env| env.response = error; env } }
|
58
|
+
let(:error) { Protobuf::Rpc::RpcError.new }
|
59
|
+
let(:response_wrapper) { error.to_response }
|
60
|
+
|
61
|
+
it "wraps and encodes the response" do
|
62
|
+
stack_env = subject.call(env)
|
63
|
+
stack_env.encoded_response.should eq encoded_response
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when encoding fails" do
|
68
|
+
before { Protobuf::Socketrpc::Response.any_instance.stub(:encode).and_raise(RuntimeError) }
|
69
|
+
|
70
|
+
it "raises a bad request data exception" do
|
71
|
+
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::PbError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'protobuf/rpc/servers/http/server'
|
3
|
+
|
4
|
+
# A simple service:
|
5
|
+
require 'protobuf/message'
|
6
|
+
require 'protobuf/rpc/service'
|
7
|
+
|
8
|
+
module ReverseModule
|
9
|
+
class ReverseRequest < ::Protobuf::Message
|
10
|
+
required :string, :input, 1
|
11
|
+
end
|
12
|
+
class ReverseResponse < ::Protobuf::Message
|
13
|
+
required :string, :reversed, 1
|
14
|
+
end
|
15
|
+
class ReverseService < ::Protobuf::Rpc::Service
|
16
|
+
rpc :reverse, ReverseRequest, ReverseResponse
|
17
|
+
def reverse
|
18
|
+
respond_with :reversed => request.input.reverse
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Protobuf::Rpc::Http::Server do
|
24
|
+
subject { described_class.new }
|
25
|
+
|
26
|
+
describe '#call' do
|
27
|
+
client = nil
|
28
|
+
before do
|
29
|
+
client = Rack::MockRequest.new(subject)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return the correct response for ReverseModule::ReverseService.reverse' do
|
33
|
+
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode()
|
34
|
+
response.status.should eq 200
|
35
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
36
|
+
response.headers['x-protobuf-error'].should be_nil
|
37
|
+
response.headers['x-protobuf-error-reason'].should be_nil
|
38
|
+
response.body.should eq ReverseModule::ReverseResponse.new(:reversed => "hello world".reverse).encode()
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return METHOD_NOT_FOUND for ReverseModule::ReverseService.bobloblaw' do
|
42
|
+
response = client.post "/ReverseModule%3A%3AReverseService/bobloblaw", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode()
|
43
|
+
response.status.should eq 404
|
44
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
45
|
+
response.headers['x-protobuf-error'].should eq "ReverseModule::ReverseService#bobloblaw is not a defined RPC method."
|
46
|
+
response.headers['x-protobuf-error-reason'].should eq Protobuf::Socketrpc::ErrorReason::METHOD_NOT_FOUND.to_s
|
47
|
+
response.body.should eq ""
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return SERVICE_NOT_FOUND for Bar::ReverseService.reverse' do
|
51
|
+
response = client.post "/Bar%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode()
|
52
|
+
response.status.should eq 404
|
53
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
54
|
+
response.headers['x-protobuf-error'].should eq "Service class Bar::ReverseService is not defined."
|
55
|
+
response.headers['x-protobuf-error-reason'].should eq Protobuf::Socketrpc::ErrorReason::SERVICE_NOT_FOUND.to_s
|
56
|
+
response.body.should eq ""
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return RPC_FAILED for missing input' do
|
60
|
+
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => ""
|
61
|
+
response.status.should eq 500
|
62
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
63
|
+
response.headers['x-protobuf-error-reason'].should eq Protobuf::Socketrpc::ErrorReason::RPC_FAILED.to_s
|
64
|
+
response.body.should eq ""
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should return RPC_ERROR for invalid input' do
|
68
|
+
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => "\\n\\x03foo"
|
69
|
+
response.status.should eq 500
|
70
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
71
|
+
response.headers['x-protobuf-error-reason'].should eq Protobuf::Socketrpc::ErrorReason::RPC_ERROR.to_s
|
72
|
+
response.body.should eq ""
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should return INVALID_REQUEST_PROTO for invalid URL' do
|
76
|
+
response = client.post "/foo", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode()
|
77
|
+
response.status.should eq 400
|
78
|
+
response.headers['content-type'].should eq "application/x-protobuf"
|
79
|
+
# response.headers['x-protobuf-error'].should eq "Service class Bar::ReverseService is not defined."
|
80
|
+
response.headers['x-protobuf-error-reason'].should eq Protobuf::Socketrpc::ErrorReason::INVALID_REQUEST_PROTO.to_s
|
81
|
+
response.body.should eq ""
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '.running?' do
|
86
|
+
it 'returns true if running' do
|
87
|
+
subject.instance_variable_set(:@running, true)
|
88
|
+
subject.running?.should be_true
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns false if not running' do
|
92
|
+
subject.instance_variable_set(:@running, false)
|
93
|
+
subject.running?.should be_false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '.stop' do
|
98
|
+
it 'sets running to false' do
|
99
|
+
# subject.instance_variable_set(:@workers, [])
|
100
|
+
subject.stop
|
101
|
+
subject.instance_variable_get(:@running).should be_false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|