protobuf 1.0.1 → 1.1.0.beta0

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 (45) hide show
  1. data/.gitignore +3 -0
  2. data/.yardopts +5 -0
  3. data/Gemfile.lock +25 -10
  4. data/bin/rpc_server +38 -33
  5. data/lib/protobuf.rb +22 -3
  6. data/lib/protobuf/common/logger.rb +6 -8
  7. data/lib/protobuf/compiler/visitors.rb +8 -9
  8. data/lib/protobuf/descriptor/descriptor_builder.rb +6 -6
  9. data/lib/protobuf/ext/eventmachine.rb +2 -4
  10. data/lib/protobuf/message/message.rb +1 -3
  11. data/lib/protobuf/rpc/buffer.rb +6 -6
  12. data/lib/protobuf/rpc/client.rb +59 -21
  13. data/lib/protobuf/rpc/connector.rb +10 -9
  14. data/lib/protobuf/rpc/connectors/base.rb +23 -8
  15. data/lib/protobuf/rpc/connectors/common.rb +155 -0
  16. data/lib/protobuf/rpc/connectors/em_client.rb +23 -192
  17. data/lib/protobuf/rpc/connectors/eventmachine.rb +36 -44
  18. data/lib/protobuf/rpc/connectors/socket.rb +58 -1
  19. data/lib/protobuf/rpc/error.rb +6 -14
  20. data/lib/protobuf/rpc/server.rb +72 -99
  21. data/lib/protobuf/rpc/servers/evented_runner.rb +32 -0
  22. data/lib/protobuf/rpc/servers/evented_server.rb +29 -0
  23. data/lib/protobuf/rpc/servers/socket_runner.rb +17 -0
  24. data/lib/protobuf/rpc/servers/socket_server.rb +145 -0
  25. data/lib/protobuf/rpc/service.rb +50 -51
  26. data/lib/protobuf/rpc/stat.rb +2 -2
  27. data/lib/protobuf/version.rb +1 -1
  28. data/protobuf.gemspec +9 -4
  29. data/spec/helper/all.rb +1 -7
  30. data/spec/helper/server.rb +45 -5
  31. data/spec/helper/silent_constants.rb +40 -0
  32. data/spec/proto/test_service.rb +0 -1
  33. data/spec/proto/test_service_impl.rb +4 -3
  34. data/spec/spec_helper.rb +19 -6
  35. data/spec/unit/enum_spec.rb +4 -4
  36. data/spec/unit/rpc/client_spec.rb +32 -42
  37. data/spec/unit/rpc/connector_spec.rb +11 -16
  38. data/spec/unit/rpc/connectors/base_spec.rb +14 -3
  39. data/spec/unit/rpc/connectors/common_spec.rb +132 -0
  40. data/spec/unit/rpc/connectors/{eventmachine/client_spec.rb → eventmachine_client_spec.rb} +0 -0
  41. data/spec/unit/rpc/connectors/socket_spec.rb +49 -0
  42. data/spec/unit/rpc/servers/evented_server_spec.rb +18 -0
  43. data/spec/unit/rpc/servers/socket_server_spec.rb +57 -0
  44. metadata +86 -16
  45. data/spec/unit/rpc/server_spec.rb +0 -27
data/spec/helper/all.rb CHANGED
@@ -1,13 +1,7 @@
1
- require 'rubygems'
2
- require 'rspec'
3
-
4
1
  require 'helper/tolerance_matcher'
5
2
  require 'helper/server'
3
+ require 'helper/silent_constants'
6
4
 
7
5
  def now
8
6
  Time.new.to_f
9
7
  end
10
-
11
- RSpec.configure do |con|
12
- con.include(Sander6::CustomMatchers)
13
- end
@@ -1,9 +1,11 @@
1
- require 'lib/protobuf/rpc/server'
1
+ require 'ostruct'
2
+ require 'protobuf/common/logger'
3
+ require 'protobuf/rpc/server'
2
4
  require 'spec/proto/test_service_impl'
3
5
 
4
6
  module StubProtobufServerFactory
5
7
  def self.build(delay)
6
- new_server = Class.new(Protobuf::Rpc::Server) do
8
+ new_server = Class.new(Protobuf::Rpc::EventedServer) do
7
9
  class << self
8
10
  def sleep_interval
9
11
  @sleep_interval
@@ -26,11 +28,49 @@ module StubProtobufServerFactory
26
28
  end
27
29
 
28
30
  class StubServer
29
- def initialize(delay = 0, port = 9191)
30
- @server_handle = EventMachine::start_server("127.0.0.1", port, StubProtobufServerFactory.build(delay))
31
+ include Protobuf::Logger::LogMethods
32
+
33
+ attr_accessor :options
34
+
35
+ def initialize(opts = {})
36
+ @running = true
37
+ @options = OpenStruct.new({
38
+ :host => "127.0.0.1",
39
+ :port => 9939,
40
+ :delay => 0,
41
+ :server => Protobuf::Rpc::EventedServer
42
+ }.merge(opts))
43
+
44
+ start
45
+ yield self
46
+ ensure
47
+ stop if @running
48
+ end
49
+
50
+ def start
51
+ if @options.server == Protobuf::Rpc::EventedServer
52
+ start_em_server
53
+ else
54
+ Protobuf::Rpc::SocketRunner.run(@options)
55
+ end
56
+ log_debug "[stub-server] Server started #{@options.host}:#{@options.port}"
57
+ rescue => ex
58
+ if ex =~ /no acceptor/ # Means EM didn't shutdown in the next_tick yet
59
+ stop
60
+ retry
61
+ end
62
+ end
63
+
64
+ def start_em_server
65
+ @server_handle = EventMachine::start_server(@options.host, @options.port, StubProtobufServerFactory.build(@options.delay))
31
66
  end
32
67
 
33
68
  def stop
34
- EventMachine.stop_server(@server_handle)
69
+ if @options.server == Protobuf::Rpc::EventedServer
70
+ EventMachine.stop_server(@server_handle)
71
+ else
72
+ Protobuf::Rpc::SocketRunner.stop
73
+ end
74
+ @running = false
35
75
  end
36
76
  end
@@ -0,0 +1,40 @@
1
+ # Just a way to keep warnings from being flagged in rename of constants during tests
2
+ module Kernel
3
+ def silence_warnings
4
+ orig_verbosity = $VERBOSE
5
+ $VERBOSE = nil
6
+ yield
7
+ $VERBOSE = orig_verbosity
8
+ end
9
+ end
10
+
11
+ module SilentConstants
12
+ def parse(constant)
13
+ source, _, constant_name = constant.to_s.rpartition('::')
14
+ [Object.const_get(source.to_sym), constant_name.to_sym]
15
+ end
16
+
17
+ # Examples
18
+ # with_constants "Something" => "nothing" do
19
+ # end
20
+ #
21
+ # with_constants "Something::Foo" => "something else" do
22
+ # end
23
+ #
24
+ def with_constants(constants, &block)
25
+ saved_constants = {}
26
+ constants.each do |constant, val|
27
+ source_object, const_name = parse(constant)
28
+ saved_constants[constant] = source_object.const_get(const_name)
29
+ Kernel::silence_warnings { source_object.const_set(const_name, val) }
30
+ end
31
+
32
+ block.call
33
+ ensure
34
+ constants.each do |constant, val|
35
+ source_object, const_name = parse(constant)
36
+ Kernel::silence_warnings { source_object.const_set(const_name, saved_constants[constant]) }
37
+ end
38
+ end
39
+
40
+ end
@@ -1,5 +1,4 @@
1
1
  require 'protobuf/rpc/service'
2
- require 'spec/proto/test.pb'
3
2
 
4
3
  ## !! DO NOT EDIT THIS FILE !!
5
4
  ##
@@ -1,9 +1,10 @@
1
- require 'spec/proto/test_service'
1
+ require 'protobuf/rpc/service'
2
+ require File.dirname(__FILE__) + '/test.pb'
3
+ require File.dirname(__FILE__) + '/test_service'
2
4
 
3
5
  module Spec
4
6
  module Proto
5
7
  class TestService
6
- located_at "localhost:9191"
7
8
 
8
9
  # request -> Spec::Proto::ResourceFindRequest
9
10
  # response -> Spec::Proto::Resource
@@ -14,4 +15,4 @@ module Spec
14
15
 
15
16
  end
16
17
  end
17
- end
18
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,16 +1,29 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  require 'rubygems'
2
5
  require 'bundler'
3
6
  Bundler.setup :default, :development, :test
4
7
 
5
- RSpec.configure do |c|
6
- c.mock_with :rspec
7
- end
8
-
9
8
  $:.push File.expand_path('..', File.dirname(__FILE__))
10
9
  $:.push File.expand_path('../lib', File.dirname(__FILE__))
11
- require 'protobuf'
12
10
 
11
+ require 'protobuf'
13
12
  require 'protobuf/rpc/client'
13
+ require File.dirname(__FILE__) + '/helper/all'
14
+
15
+ # Including a way to turn on debug logger for spec runs
16
+ if ENV["DEBUG"]
17
+ debug_log = File.expand_path('../debug_specs.log', File.dirname(__FILE__) )
18
+ Protobuf::Logger.configure(:file => debug_log, :level => ::Logger::DEBUG)
19
+ end
20
+
21
+ RSpec.configure do |c|
22
+ c.include(SilentConstants)
23
+ c.include(Sander6::CustomMatchers)
24
+ c.mock_with :rspec
25
+ end
26
+
14
27
  class ::Protobuf::Rpc::Client
15
28
  def == other
16
29
  connector.options == other.options && \
@@ -21,4 +34,4 @@ end
21
34
 
22
35
  def reset_service_location service
23
36
  service.instance_variable_set :@locations, nil
24
- end
37
+ end
@@ -4,10 +4,10 @@ require 'spec/proto/test.pb'
4
4
  describe Protobuf::Enum do
5
5
  context 'when coercing from enum' do
6
6
  subject { Spec::Proto::StatusType::PENDING }
7
- it { should == 0 }
7
+ it { should eq(0) }
8
8
  end
9
+
9
10
  context 'when coercing from integer' do
10
- subject { 0 }
11
- it { should == Spec::Proto::StatusType::PENDING }
11
+ it { 0.should eq(Spec::Proto::StatusType::PENDING) }
12
12
  end
13
- end
13
+ end
@@ -1,61 +1,53 @@
1
1
  require 'spec_helper'
2
2
  require 'spec/proto/test_service_impl'
3
- require 'spec/helper/all'
4
3
 
5
4
  describe Protobuf::Rpc::Client do
6
5
 
7
6
  context "when using fiber based calls" do
8
7
  it "waits for response when running synchronously" do
9
8
  EventMachine.fiber_run do
10
- delay = 3
11
- server = StubServer.new(delay)
12
- stop_servers = lambda { server.stop; EventMachine.stop }
13
- client = Spec::Proto::TestService.client(:async => false)
14
-
15
- start = now
16
-
17
- client.find(:name => "Test Name", :active => true) do |c|
18
- c.on_success do |succ|
19
- succ.name.should eq("Test Name")
20
- succ.status.should eq(Spec::Proto::StatusType::ENABLED)
9
+ StubServer.new(:delay => 3) do |server|
10
+ client = Spec::Proto::TestService.client(:async => false)
11
+ start = now
12
+
13
+ client.find(:name => "Test Name", :active => true) do |c|
14
+ c.on_success do |succ|
15
+ succ.name.should eq("Test Name")
16
+ succ.status.should eq(Spec::Proto::StatusType::ENABLED)
17
+ end
18
+
19
+ c.on_failure do |err|
20
+ raise err.inspect
21
+ end
21
22
  end
22
23
 
23
- c.on_failure do |err|
24
- raise err.inspect
25
- end
24
+ (now - start).should be_within(server.options.delay * 0.10).of(server.options.delay)
26
25
  end
27
26
 
28
- (now - start).should be_within(delay * 0.10).of(delay)
29
- stop_servers.call
27
+ EM.stop
30
28
  end
31
29
  end
32
30
 
33
31
  it "doesn't wait for response when running async call inside fiber" do
34
32
  EventMachine.fiber_run do
35
- delay = 3
36
- server = StubServer.new(delay)
37
- stop_servers = lambda { server.stop; EventMachine.stop }
38
- client = Spec::Proto::TestService.client(:async => true)
39
-
40
- start = now
41
-
42
- client.find(:name => "Test Name", :active => true)
33
+ StubServer.new(:delay => 3) do |server|
34
+ client = Spec::Proto::TestService.client(:async => true)
35
+ start = now
36
+ client.find(:name => "Test Name", :active => true)
43
37
 
44
- (now - start).should_not be_within(delay * 0.10).of(delay)
45
- stop_servers.call
38
+ (now - start).should_not be_within(server.options.delay* 0.10).of(server.options.delay)
39
+ end
40
+ EM.stop
46
41
  end
47
42
  end
48
43
 
49
44
  it "throws and error when synchronous code is attempted without 'EventMachine.fiber_run'" do
50
45
  subject = Proc.new do
51
46
  EventMachine.run do
52
- delay = 1
53
- server = StubServer.new(delay)
54
- stop_servers = lambda { server.stop; EventMachine.stop }
55
- client = Spec::Proto::TestService.client(:async => false)
56
-
57
- client.find(:name => "Test Name", :active => true)
58
- stop_servers.call
47
+ StubServer.new(:delay => 1) do |server|
48
+ client = Spec::Proto::TestService.client(:async => false)
49
+ client.find(:name => "Test Name", :active => true)
50
+ end
59
51
  end
60
52
  end
61
53
 
@@ -65,13 +57,11 @@ describe Protobuf::Rpc::Client do
65
57
  it "throws a timeout when client timeout is exceeded" do
66
58
  subject = Proc.new do
67
59
  EventMachine.fiber_run do
68
- delay = 3
69
- server = StubServer.new(delay)
70
- stop_servers = lambda { server.stop; EventMachine.stop }
71
- client = Spec::Proto::TestService.client(:async => false, :timeout => 1)
72
-
73
- client.find(:name => "Test Name", :active => true)
74
- stop_servers.call
60
+ StubServer.new(:delay => 2) do |server|
61
+ client = Spec::Proto::TestService.client(:async => false, :timeout => 1)
62
+ client.find(:name => "Test Name", :active => true)
63
+ end
64
+ EM.stop
75
65
  end
76
66
  end
77
67
 
@@ -164,7 +154,7 @@ describe Protobuf::Rpc::Client do
164
154
  client = Spec::Proto::TestService.client
165
155
  client.should_receive(:send_request)
166
156
  client.find({:name => 'Test Name', :active => false})
167
- client.options[:request].should be_a Spec::Proto::ResourceFindRequest
157
+ client.options[:request].should be_a(Spec::Proto::ResourceFindRequest)
168
158
  client.options[:request].name.should eq('Test Name')
169
159
  client.options[:request].active.should eq(false)
170
160
  end
@@ -2,32 +2,27 @@ require 'spec_helper'
2
2
 
3
3
  describe Protobuf::Rpc::Connector do
4
4
 
5
- describe '.connector_for_platform' do
5
+ describe '.connector_for_client' do
6
6
 
7
- context 'when platform is java' do
8
- let(:platform) { 'jruby' }
7
+ context 'when set to Socket connector' do
9
8
  it 'returns a socket connector class reference' do
10
- Protobuf::Rpc::Connector.connector_for_platform(platform).should eq Protobuf::Rpc::Connectors::Socket
9
+ with_constants "Protobuf::ConnectorType" => "Socket" do
10
+ Protobuf::Rpc::Connector.connector_for_client.should eq(Protobuf::Rpc::Connectors::Socket)
11
+ end
11
12
  end
12
13
  end
13
14
 
14
- context 'when platform is mri' do
15
- let(:platform) { 'mri' }
15
+ context 'when set to non Socket Connector' do
16
16
  it 'returns an eventmachine connector class reference' do
17
- Protobuf::Rpc::Connector.connector_for_platform(platform).should eq Protobuf::Rpc::Connectors::EventMachine
17
+ with_constants "Protobuf::ConnectorType" => "EventMachine" do
18
+ Protobuf::Rpc::Connector.connector_for_client.should eq Protobuf::Rpc::Connectors::EventMachine
19
+ end
18
20
  end
19
21
  end
20
22
 
21
- context 'when platform is unknown' do
22
- let(:platform) { 'some_bogus_engine' }
23
+ context 'when connector type not given' do
23
24
  it 'returns an eventmachine connector class reference' do
24
- Protobuf::Rpc::Connector.connector_for_platform(platform).should eq Protobuf::Rpc::Connectors::EventMachine
25
- end
26
- end
27
-
28
- context 'when platform is not given' do
29
- it 'returns an eventmachine connector class reference' do
30
- Protobuf::Rpc::Connector.connector_for_platform.should eq Protobuf::Rpc::Connectors::EventMachine
25
+ Protobuf::Rpc::Connector.connector_for_client.should eq Protobuf::Rpc::Connectors::EventMachine
31
26
  end
32
27
  end
33
28
 
@@ -8,9 +8,20 @@ describe Protobuf::Rpc::Connectors::Base do
8
8
 
9
9
  subject { Protobuf::Rpc::Connectors::Base.new(opts) }
10
10
 
11
+ describe "#send_request" do
12
+ it "raising an error when 'send_request' is not overridden" do
13
+ expect{ subject.send_request }.to raise_error(RuntimeError, /inherit a Connector/)
14
+ end
15
+
16
+ it "does not raise error when 'send_request' is overridden" do
17
+ new_sub = Class.new(subject.class){ def send_request; end }.new(opts)
18
+ expect{ new_sub.send_request }.to_not raise_error
19
+ end
20
+ end
21
+
11
22
  describe '.new' do
12
23
  it 'assigns passed options and initializes success/failure callbacks' do
13
- subject.options.should eq opts
24
+ subject.options.should eq(Protobuf::Rpc::Connectors::DEFAULT_OPTIONS.merge(opts))
14
25
  subject.success_cb.should be_nil
15
26
  subject.failure_cb.should be_nil
16
27
  end
@@ -21,7 +32,7 @@ describe Protobuf::Rpc::Connectors::Base do
21
32
  subject.success_cb.should be_nil
22
33
  cb = proc {|res| raise res }
23
34
  subject.success_cb = cb
24
- subject.success_cb.should eq cb
35
+ subject.success_cb.should eq(cb)
25
36
  expect { subject.success_cb.call('an error from cb') }.to raise_error 'an error from cb'
26
37
  end
27
38
  end
@@ -31,7 +42,7 @@ describe Protobuf::Rpc::Connectors::Base do
31
42
  subject.failure_cb.should be_nil
32
43
  cb = proc {|res| raise res }
33
44
  subject.failure_cb = cb
34
- subject.failure_cb.should eq cb
45
+ subject.failure_cb.should eq(cb)
35
46
  expect { subject.failure_cb.call('an error from cb') }.to raise_error 'an error from cb'
36
47
  end
37
48
  end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+ require 'protobuf/rpc/service'
3
+
4
+ describe Protobuf::Rpc::Connectors::Common do
5
+ let(:common_class) do
6
+ Class.new(Protobuf::Rpc::Connectors::Base) do
7
+ include Protobuf::Rpc::Connectors::Common
8
+ attr_accessor :options
9
+ attr_accessor :stats
10
+ end
11
+ end
12
+
13
+ subject{ @subject ||= common_class.new({}) }
14
+
15
+ context "API" do
16
+ specify{ subject.respond_to?(:any_callbacks?).should be_true }
17
+ specify{ subject.respond_to?(:data_callback).should be_true }
18
+ specify{ subject.respond_to?(:error).should be_true }
19
+ specify{ subject.respond_to?(:fail).should be_true }
20
+ specify{ subject.respond_to?(:complete).should be_true }
21
+ specify{ subject.respond_to?(:parse_response).should be_true }
22
+ specify{ subject.respond_to?(:_send_request).should be_true }
23
+ specify{ subject.respond_to?(:verify_options).should be_true }
24
+ specify{ subject.respond_to?(:verify_callbacks).should be_true }
25
+ end
26
+
27
+ context "#any_callbacks?" do
28
+
29
+ [:@complete_cb, :@success_cb, :@failure_cb].each do |cb|
30
+ it "returns true if #{cb} is provided" do
31
+ subject.instance_variable_set(cb, "something")
32
+ subject.any_callbacks?.should be_true
33
+ end
34
+ end
35
+
36
+ it "returns false when all callbacks are not provided" do
37
+ subject.instance_variable_set(:@complete_cb, nil)
38
+ subject.instance_variable_set(:@success_cb, nil)
39
+ subject.instance_variable_set(:@failure_cb, nil)
40
+
41
+ subject.any_callbacks?.should be_false
42
+ end
43
+
44
+ end
45
+
46
+ context "#data_callback" do
47
+ it "changes state to use the data callback" do
48
+ subject.data_callback("data")
49
+ subject.instance_variable_get(:@used_data_callback).should be_true
50
+ end
51
+
52
+ it "sets the data var when using the data_callback" do
53
+ subject.data_callback("data")
54
+ subject.instance_variable_get(:@data).should eq("data")
55
+ end
56
+ end
57
+
58
+ context "#verify_callbacks" do
59
+
60
+ it "sets @failure_cb to #data_callback when no callbacks are defined" do
61
+ subject.verify_callbacks
62
+ subject.instance_variable_get(:@failure_cb).should eq(subject.method(:data_callback))
63
+ end
64
+
65
+ it "sets @success_cb to #data_callback when no callbacks are defined" do
66
+ subject.verify_callbacks
67
+ subject.instance_variable_get(:@success_cb).should eq(subject.method(:data_callback))
68
+ end
69
+
70
+ it "doesn't set @failure_cb when already defined" do
71
+ set_cb = lambda{ true }
72
+ subject.instance_variable_set(:@failure_cb, set_cb)
73
+ subject.verify_callbacks
74
+ subject.instance_variable_get(:@failure_cb).should eq(set_cb)
75
+ subject.instance_variable_get(:@failure_cb).should_not eq(subject.method(:data_callback))
76
+ end
77
+
78
+ it "doesn't set @success_cb when already defined" do
79
+ set_cb = lambda{ true }
80
+ subject.instance_variable_set(:@success_cb, set_cb)
81
+ subject.verify_callbacks
82
+ subject.instance_variable_get(:@success_cb).should eq(set_cb)
83
+ subject.instance_variable_get(:@success_cb).should_not eq(subject.method(:data_callback))
84
+ end
85
+
86
+ end
87
+
88
+ shared_examples "a ConnectorDisposition" do |meth, cb, *args|
89
+
90
+ it "calls #complete before exit" do
91
+ stats = double("Object")
92
+ stats.stub(:end) { true }
93
+ stats.stub(:log_stats) { true }
94
+ subject.stats = stats
95
+
96
+ subject.should_receive(:complete)
97
+ subject.method(meth).call(*args)
98
+ end
99
+
100
+ it "calls the #{cb} callback when provided" do
101
+ stats = double("Object")
102
+ stats.stub(:end) { true }
103
+ stats.stub(:log_stats) { true }
104
+ subject.stats = stats
105
+ _cb = double("Object")
106
+
107
+ subject.instance_variable_set("@#{cb}", _cb)
108
+ _cb.should_receive(:call).and_return(true)
109
+ subject.method(meth).call(*args)
110
+ end
111
+
112
+ it "calls the complete callback when provided" do
113
+ stats = double("Object")
114
+ stats.stub(:end) { true }
115
+ stats.stub(:log_stats) { true }
116
+ subject.stats = stats
117
+ comp_cb = double("Object")
118
+
119
+ subject.instance_variable_set(:@complete_cb, comp_cb)
120
+ comp_cb.should_receive(:call).and_return(true)
121
+ subject.method(meth).call(*args)
122
+ end
123
+
124
+ end
125
+
126
+ it_behaves_like("a ConnectorDisposition", :fail, "failure_cb", "code", "message")
127
+ it_behaves_like("a ConnectorDisposition", :fail, "complete_cb", "code", "message")
128
+ it_behaves_like("a ConnectorDisposition", :succeed, "complete_cb", "response")
129
+ it_behaves_like("a ConnectorDisposition", :succeed, "success_cb", "response")
130
+ it_behaves_like("a ConnectorDisposition", :complete, "complete_cb")
131
+
132
+ end