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.
Files changed (192) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +5 -0
  5. data/CHANGES.md +261 -0
  6. data/CONTRIBUTING.md +16 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +14 -0
  9. data/README.md +58 -0
  10. data/Rakefile +61 -0
  11. data/bin/protoc-gen-ruby +17 -0
  12. data/bin/rpc_server +4 -0
  13. data/examples/bin/reverse-client-http +4 -0
  14. data/examples/bin/reverse-client-socket +4 -0
  15. data/examples/bin/reverse-client-zmq +4 -0
  16. data/examples/config.ru +6 -0
  17. data/examples/definitions/example/reverse.proto +12 -0
  18. data/examples/lib/example/reverse-client.rb +23 -0
  19. data/examples/lib/example/reverse-service.rb +9 -0
  20. data/examples/lib/example/reverse.pb.rb +36 -0
  21. data/lib/protobuf.rb +106 -0
  22. data/lib/protobuf/cli.rb +249 -0
  23. data/lib/protobuf/code_generator.rb +41 -0
  24. data/lib/protobuf/decoder.rb +74 -0
  25. data/lib/protobuf/deprecator.rb +42 -0
  26. data/lib/protobuf/descriptors.rb +3 -0
  27. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
  28. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
  29. data/lib/protobuf/encoder.rb +62 -0
  30. data/lib/protobuf/enum.rb +319 -0
  31. data/lib/protobuf/exceptions.rb +9 -0
  32. data/lib/protobuf/field.rb +74 -0
  33. data/lib/protobuf/field/base_field.rb +280 -0
  34. data/lib/protobuf/field/bool_field.rb +53 -0
  35. data/lib/protobuf/field/bytes_field.rb +81 -0
  36. data/lib/protobuf/field/double_field.rb +26 -0
  37. data/lib/protobuf/field/enum_field.rb +57 -0
  38. data/lib/protobuf/field/field_array.rb +86 -0
  39. data/lib/protobuf/field/fixed32_field.rb +25 -0
  40. data/lib/protobuf/field/fixed64_field.rb +29 -0
  41. data/lib/protobuf/field/float_field.rb +38 -0
  42. data/lib/protobuf/field/int32_field.rb +22 -0
  43. data/lib/protobuf/field/int64_field.rb +22 -0
  44. data/lib/protobuf/field/integer_field.rb +24 -0
  45. data/lib/protobuf/field/message_field.rb +66 -0
  46. data/lib/protobuf/field/sfixed32_field.rb +28 -0
  47. data/lib/protobuf/field/sfixed64_field.rb +29 -0
  48. data/lib/protobuf/field/signed_integer_field.rb +30 -0
  49. data/lib/protobuf/field/sint32_field.rb +22 -0
  50. data/lib/protobuf/field/sint64_field.rb +22 -0
  51. data/lib/protobuf/field/string_field.rb +35 -0
  52. data/lib/protobuf/field/uint32_field.rb +22 -0
  53. data/lib/protobuf/field/uint64_field.rb +22 -0
  54. data/lib/protobuf/field/varint_field.rb +68 -0
  55. data/lib/protobuf/generators/base.rb +71 -0
  56. data/lib/protobuf/generators/enum_generator.rb +42 -0
  57. data/lib/protobuf/generators/extension_generator.rb +28 -0
  58. data/lib/protobuf/generators/field_generator.rb +132 -0
  59. data/lib/protobuf/generators/file_generator.rb +140 -0
  60. data/lib/protobuf/generators/group_generator.rb +113 -0
  61. data/lib/protobuf/generators/message_generator.rb +99 -0
  62. data/lib/protobuf/generators/printable.rb +161 -0
  63. data/lib/protobuf/generators/service_generator.rb +27 -0
  64. data/lib/protobuf/http.rb +20 -0
  65. data/lib/protobuf/lifecycle.rb +46 -0
  66. data/lib/protobuf/logger.rb +86 -0
  67. data/lib/protobuf/message.rb +182 -0
  68. data/lib/protobuf/message/fields.rb +122 -0
  69. data/lib/protobuf/message/serialization.rb +84 -0
  70. data/lib/protobuf/optionable.rb +23 -0
  71. data/lib/protobuf/rpc/buffer.rb +79 -0
  72. data/lib/protobuf/rpc/client.rb +168 -0
  73. data/lib/protobuf/rpc/connector.rb +21 -0
  74. data/lib/protobuf/rpc/connectors/base.rb +54 -0
  75. data/lib/protobuf/rpc/connectors/common.rb +172 -0
  76. data/lib/protobuf/rpc/connectors/http.rb +90 -0
  77. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  78. data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
  79. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
  80. data/lib/protobuf/rpc/env.rb +58 -0
  81. data/lib/protobuf/rpc/error.rb +28 -0
  82. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  83. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  84. data/lib/protobuf/rpc/middleware.rb +25 -0
  85. data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
  86. data/lib/protobuf/rpc/middleware/logger.rb +91 -0
  87. data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
  88. data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
  89. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  90. data/lib/protobuf/rpc/rpc.pb.rb +53 -0
  91. data/lib/protobuf/rpc/server.rb +39 -0
  92. data/lib/protobuf/rpc/servers/http/server.rb +101 -0
  93. data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
  94. data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
  95. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  96. data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
  97. data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
  98. data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
  99. data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
  100. data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
  101. data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
  102. data/lib/protobuf/rpc/service.rb +179 -0
  103. data/lib/protobuf/rpc/service_directory.rb +245 -0
  104. data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
  105. data/lib/protobuf/rpc/service_filters.rb +273 -0
  106. data/lib/protobuf/rpc/stat.rb +148 -0
  107. data/lib/protobuf/socket.rb +22 -0
  108. data/lib/protobuf/tasks.rb +1 -0
  109. data/lib/protobuf/tasks/compile.rake +61 -0
  110. data/lib/protobuf/version.rb +3 -0
  111. data/lib/protobuf/wire_type.rb +10 -0
  112. data/lib/protobuf/zmq.rb +21 -0
  113. data/proto/dynamic_discovery.proto +44 -0
  114. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  115. data/proto/google/protobuf/descriptor.proto +620 -0
  116. data/proto/rpc.proto +62 -0
  117. data/protobuffy.gemspec +37 -0
  118. data/spec/benchmark/tasks.rb +113 -0
  119. data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
  120. data/spec/data/data.bin +3 -0
  121. data/spec/data/types.bin +0 -0
  122. data/spec/encoding/all_types_spec.rb +91 -0
  123. data/spec/encoding/extreme_values_spec.rb +0 -0
  124. data/spec/functional/socket_server_spec.rb +59 -0
  125. data/spec/functional/zmq_server_spec.rb +103 -0
  126. data/spec/lib/protobuf/cli_spec.rb +267 -0
  127. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  128. data/spec/lib/protobuf/enum_spec.rb +239 -0
  129. data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
  131. data/spec/lib/protobuf/field_spec.rb +194 -0
  132. data/spec/lib/protobuf/generators/base_spec.rb +87 -0
  133. data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
  134. data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
  135. data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
  136. data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
  137. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  138. data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
  139. data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
  140. data/spec/lib/protobuf/logger_spec.rb +136 -0
  141. data/spec/lib/protobuf/message_spec.rb +368 -0
  142. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  143. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  144. data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
  145. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  146. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
  147. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
  148. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
  149. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
  150. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
  151. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  152. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  153. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  154. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
  163. data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
  165. data/spec/lib/protobuf_spec.rb +78 -0
  166. data/spec/spec_helper.rb +57 -0
  167. data/spec/support/all.rb +7 -0
  168. data/spec/support/packed_field.rb +22 -0
  169. data/spec/support/server.rb +94 -0
  170. data/spec/support/test/all_types.data.bin +0 -0
  171. data/spec/support/test/all_types.data.txt +119 -0
  172. data/spec/support/test/defaults.pb.rb +25 -0
  173. data/spec/support/test/defaults.proto +9 -0
  174. data/spec/support/test/enum.pb.rb +59 -0
  175. data/spec/support/test/enum.proto +34 -0
  176. data/spec/support/test/extended.pb.rb +22 -0
  177. data/spec/support/test/extended.proto +10 -0
  178. data/spec/support/test/extreme_values.data.bin +0 -0
  179. data/spec/support/test/google_unittest.pb.rb +543 -0
  180. data/spec/support/test/google_unittest.proto +713 -0
  181. data/spec/support/test/google_unittest_import.pb.rb +37 -0
  182. data/spec/support/test/google_unittest_import.proto +64 -0
  183. data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
  184. data/spec/support/test/google_unittest_import_public.proto +38 -0
  185. data/spec/support/test/multi_field_extensions.pb.rb +56 -0
  186. data/spec/support/test/multi_field_extensions.proto +33 -0
  187. data/spec/support/test/resource.pb.rb +117 -0
  188. data/spec/support/test/resource.proto +94 -0
  189. data/spec/support/test/resource_service.rb +26 -0
  190. data/spec/support/test_app_file.rb +2 -0
  191. data/spec/support/tolerance_matcher.rb +40 -0
  192. 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