protobuf 2.7.12 → 2.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.md +39 -2
  2. data/lib/protobuf.rb +17 -26
  3. data/lib/protobuf/cli.rb +106 -86
  4. data/lib/protobuf/field/bytes_field.rb +6 -8
  5. data/lib/protobuf/field/float_field.rb +5 -1
  6. data/lib/protobuf/field/string_field.rb +7 -8
  7. data/lib/protobuf/rpc/connectors/base.rb +1 -1
  8. data/lib/protobuf/rpc/connectors/zmq.rb +157 -29
  9. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
  10. data/lib/protobuf/rpc/error/client_error.rb +5 -5
  11. data/lib/protobuf/rpc/error/server_error.rb +7 -7
  12. data/lib/protobuf/rpc/rpc.pb.rb +13 -12
  13. data/lib/protobuf/rpc/servers/evented_runner.rb +11 -6
  14. data/lib/protobuf/rpc/servers/socket/server.rb +19 -15
  15. data/lib/protobuf/rpc/servers/socket_runner.rb +21 -18
  16. data/lib/protobuf/rpc/servers/zmq/broker.rb +104 -94
  17. data/lib/protobuf/rpc/servers/zmq/server.rb +263 -43
  18. data/lib/protobuf/rpc/servers/zmq/util.rb +18 -6
  19. data/lib/protobuf/rpc/servers/zmq/worker.rb +102 -39
  20. data/lib/protobuf/rpc/servers/zmq_runner.rb +31 -20
  21. data/lib/protobuf/rpc/service.rb +24 -12
  22. data/lib/protobuf/rpc/service_directory.rb +206 -0
  23. data/lib/protobuf/rpc/stat.rb +1 -1
  24. data/lib/protobuf/version.rb +1 -1
  25. data/proto/dynamic_discovery.proto +44 -0
  26. data/spec/benchmark/tasks.rb +1 -3
  27. data/spec/functional/socket_server_spec.rb +6 -5
  28. data/spec/functional/zmq_server_spec.rb +59 -30
  29. data/spec/lib/protobuf/cli_spec.rb +49 -54
  30. data/spec/lib/protobuf/enum_spec.rb +1 -1
  31. data/spec/lib/protobuf/rpc/client_spec.rb +1 -1
  32. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +43 -1
  33. data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +2 -1
  34. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +9 -8
  35. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +24 -19
  36. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +5 -5
  37. data/spec/lib/protobuf/rpc/service_directory_spec.rb +183 -0
  38. data/spec/support/server.rb +21 -12
  39. data/spec/support/test/resource.pb.rb +6 -0
  40. data/spec/support/test/resource.proto +5 -0
  41. data/spec/support/test/resource_service.rb +7 -0
  42. metadata +70 -38
  43. checksums.yaml +0 -7
  44. data/spec/lib/protobuf/field/string_field_spec.rb +0 -46
  45. data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +0 -31
@@ -6,7 +6,7 @@ describe Protobuf::Enum do
6
6
 
7
7
  before(:all) do
8
8
  Test::EnumTestType.define(:MINUS_ONE, -1)
9
- Test::EnumTestType.define(name, tag)
9
+ Test::EnumTestType.define(:THREE, 3)
10
10
  end
11
11
 
12
12
  describe '.define' do
@@ -6,7 +6,7 @@ describe Protobuf::Rpc::Client do
6
6
  load 'protobuf/evented.rb'
7
7
  end
8
8
 
9
- context "when using fiber based calls" do
9
+ context "when using fiber based calls", :skip => true do
10
10
  it "waits for response" do
11
11
  EventMachine.fiber_run do
12
12
  StubServer.new(:delay => 1) do |server|
@@ -2,6 +2,16 @@ require 'spec_helper'
2
2
  require 'protobuf/zmq'
3
3
 
4
4
  describe ::Protobuf::Rpc::Connectors::Zmq do
5
+ subject { described_class.new(options) }
6
+
7
+ let(:options) {{
8
+ :service => "Test::Service",
9
+ :method => "find",
10
+ :timeout => 3,
11
+ :host => "127.0.0.1",
12
+ :port => "9400"
13
+ }}
14
+
5
15
  let(:socket_mock) do
6
16
  sm = mock(::ZMQ::Socket)
7
17
  sm.stub(:connect).and_return(0)
@@ -14,9 +24,41 @@ describe ::Protobuf::Rpc::Connectors::Zmq do
14
24
  zc
15
25
  end
16
26
 
17
- before(:each) do
27
+ before do
18
28
  ::ZMQ::Context.stub(:new).and_return(zmq_context_mock)
19
29
  end
20
30
 
31
+ describe "#lookup_server_uri" do
32
+ let(:service_directory) { double('ServiceDirectory', :running? => running? ) }
33
+ let(:listing) { double('Listing', :address => '127.0.0.2', :port => 9399) }
34
+ let(:running?) { true }
35
+
36
+ before do
37
+ subject.stub(:service_directory) { service_directory }
38
+ end
39
+
40
+ context "when the service directory is running" do
41
+ it "searches the service directory" do
42
+ service_directory.should_receive(:lookup).and_return(listing)
43
+ subject.send(:lookup_server_uri).should eq "tcp://127.0.0.2:9399"
44
+ end
45
+
46
+ it "defaults to the options" do
47
+ service_directory.should_receive(:lookup) { nil }
48
+ subject.send(:lookup_server_uri).should eq "tcp://127.0.0.1:9400"
49
+ end
50
+ end
51
+
52
+ context "when the service directory is not running" do
53
+ let(:running?) { false }
54
+
55
+ it "does not search the directory" do
56
+ service_directory.should_not_receive(:lookup)
57
+ subject.send(:lookup_server_uri).should eq "tcp://127.0.0.1:9400"
58
+ end
59
+ end
60
+
61
+ end
62
+
21
63
  pending
22
64
  end
@@ -12,7 +12,8 @@ describe Protobuf::Rpc::Evented::Server do
12
12
 
13
13
  it "Runner provides a stop method" do
14
14
  runner_class = described_class.to_s.gsub(/Evented::Server/, "EventedRunner").constantize
15
- runner_class.respond_to?(:stop).should be_true
15
+ runner = runner_class.new({})
16
+ runner.respond_to?(:stop).should be_true
16
17
  end
17
18
 
18
19
  end
@@ -12,23 +12,24 @@ describe Protobuf::Rpc::Socket::Server do
12
12
  before(:all) do
13
13
  load 'protobuf/socket.rb'
14
14
  Thread.abort_on_exception = true
15
- server = OpenStruct.new(:server => "127.0.0.1", :port => 9399, :backlog => 100, :threshold => 100)
16
- @server_thread = Thread.new(server) { |s| Protobuf::Rpc::SocketRunner.run(s) }
17
- Thread.pass until Protobuf::Rpc::Socket::Server.running?
15
+ @options = OpenStruct.new(:host => "127.0.0.1", :port => 9399, :backlog => 100, :threshold => 100)
16
+ @runner = ::Protobuf::Rpc::SocketRunner.new(@options)
17
+ @server = @runner.instance_variable_get(:@server)
18
+ @server_thread = Thread.new(@runner) { |runner| runner.run }
19
+ Thread.pass until @server.running?
18
20
  end
19
21
 
20
22
  after(:all) do
21
- Protobuf::Rpc::SocketRunner.stop
23
+ @server.stop
22
24
  @server_thread.join
23
25
  end
24
26
 
25
27
  it "Runner provides a stop method" do
26
- runner_class = described_class.to_s.gsub(/Evented::Server/, "EventedRunner").constantize
27
- runner_class.respond_to?(:stop).should be_true
28
+ @runner.should respond_to(:stop)
28
29
  end
29
30
 
30
31
  it "provides a stop method" do
31
- described_class.respond_to?(:stop).should be_true
32
+ @server.should respond_to(:stop)
32
33
  end
33
34
 
34
35
  it "provides a Runner class" do
@@ -37,7 +38,7 @@ describe Protobuf::Rpc::Socket::Server do
37
38
  end
38
39
 
39
40
  it "signals the Server is running" do
40
- described_class.running?.should be_true
41
+ @server.should be_running
41
42
  end
42
43
 
43
44
  end
@@ -2,40 +2,45 @@ require 'spec_helper'
2
2
  require 'protobuf/rpc/servers/zmq/server'
3
3
 
4
4
  describe Protobuf::Rpc::Zmq::Server do
5
- before(:each) do
5
+ subject { described_class.new(options) }
6
+
7
+ let(:options) {{
8
+ :host => '127.0.0.1',
9
+ :port => 9399,
10
+ :worker_port => 9400,
11
+ :workers_only => true
12
+ }}
13
+
14
+ before do
6
15
  load 'protobuf/zmq.rb'
7
16
  end
8
17
 
18
+ after do
19
+ subject.teardown
20
+ end
21
+
9
22
  describe '.running?' do
10
23
  it 'returns true if running' do
11
- described_class.instance_variable_set(:@running, true)
12
- described_class.running?.should be_true
24
+ subject.instance_variable_set(:@running, true)
25
+ subject.running?.should be_true
13
26
  end
14
27
 
15
28
  it 'returns false if not running' do
16
- described_class.instance_variable_set(:@running, false)
17
- described_class.running?.should be_false
29
+ subject.instance_variable_set(:@running, false)
30
+ subject.running?.should be_false
18
31
  end
19
32
  end
20
33
 
21
34
  describe '.stop' do
22
- # keep threads instance variable from retaining any thread mocks we've
23
- # created (breaks tests down the line, otherwise)
24
- after(:each) do
25
- described_class.instance_variable_set(:@threads, [])
26
- end
27
-
28
- it 'lets all threads stop' do
29
- thread_mock = double(Thread)
30
- thread_mock.should_receive(:join).and_return(thread_mock)
31
- described_class.instance_variable_set(:@threads, [thread_mock])
32
- described_class.stop
35
+ it 'signals shutdown' do
36
+ subject.should_receive(:signal_shutdown)
37
+ subject.stop
33
38
  end
34
39
 
35
40
  it 'sets running to false' do
36
- described_class.instance_variable_set(:@threads, [])
37
- described_class.stop
38
- described_class.instance_variable_get(:@running).should be_false
41
+ subject.instance_variable_set(:@workers, [])
42
+ subject.stop
43
+ subject.instance_variable_get(:@running).should be_false
39
44
  end
40
45
  end
41
46
  end
@@ -13,26 +13,26 @@ describe ::Protobuf::Rpc::Zmq::Util do
13
13
  describe '#zmq_error_check' do
14
14
  it 'raises when the error code is less than 0' do
15
15
  expect {
16
- subject.zmq_error_check(-1)
17
- }.to raise_error
16
+ subject.zmq_error_check(-1, :test)
17
+ }.to raise_error(/test/)
18
18
  end
19
19
 
20
20
  it 'retrieves the error string from ZeroMQ' do
21
21
  ZMQ::Util.stub(:error_string).and_return('an error from zmq')
22
22
  expect {
23
- subject.zmq_error_check(-1)
23
+ subject.zmq_error_check(-1, :test)
24
24
  }.to raise_error(RuntimeError, /an error from zmq/i)
25
25
  end
26
26
 
27
27
  it 'does nothing if the error code is > 0' do
28
28
  expect {
29
- subject.zmq_error_check(1)
29
+ subject.zmq_error_check(1, :test)
30
30
  }.to_not raise_error
31
31
  end
32
32
 
33
33
  it 'does nothing if the error code is == 0' do
34
34
  expect {
35
- subject.zmq_error_check(0)
35
+ subject.zmq_error_check(0, :test)
36
36
  }.to_not raise_error
37
37
  end
38
38
  end
@@ -0,0 +1,183 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/rpc/service_directory'
4
+
5
+ describe ::Protobuf::Rpc::ServiceDirectory do
6
+ let(:instance) { ::Protobuf::Rpc::ServiceDirectory.instance }
7
+
8
+ def listings
9
+ instance.instance_variable_get(:@listings)
10
+ end
11
+
12
+ def duration
13
+ start = Time.now.to_f
14
+ yield
15
+ Time.now.to_f - start
16
+ end
17
+
18
+ after do
19
+ instance.stop
20
+ end
21
+
22
+ it "is a singleton" do
23
+ instance.should be_a_kind_of(Singleton)
24
+ end
25
+
26
+ describe "#lookup" do
27
+ let(:server) { double('server', :uuid => '123',
28
+ :services => ['Known::Service'],
29
+ :address => "0.0.0.0",
30
+ :port => 9999,
31
+ :ttl => 15) }
32
+ let(:listing) { ::Protobuf::Rpc::ServiceDirectory::Listing.new(server) }
33
+
34
+ it "returns a listing for the given service" do
35
+ instance.add_listing_for(server)
36
+ instance.lookup("Known::Service").should eq listing
37
+ end
38
+
39
+ it "returns random listings" do
40
+ instance.add_listing_for double(:uuid => 1, :ttl => 5, :services => ["Test"])
41
+ instance.add_listing_for double(:uuid => 2, :ttl => 5, :services => ["Test"])
42
+
43
+ uuids = 100.times.map { instance.lookup("Test").uuid }
44
+ uuids.count(1).should be_within(25).of(50)
45
+ uuids.count(2).should be_within(25).of(50)
46
+ end
47
+
48
+ it "does not return expired listings" do
49
+ instance.instance_variable_set(:@listings, {
50
+ '1' => double(:current? => false, :services => ["Test"]),
51
+ })
52
+
53
+ instance.lookup("Test").should be_nil
54
+ end
55
+ end
56
+
57
+ describe "#remove_expired_listings" do
58
+ before do
59
+ instance.instance_variable_set(:@listings, {
60
+ '1' => double(:expired? => true),
61
+ '2' => double(:expired? => true),
62
+ '3' => double(:expired? => false),
63
+ })
64
+ end
65
+
66
+ it "removes expired listings" do
67
+ expect {
68
+ instance.remove_expired_listings
69
+ }.to change(listings, :size).from(3).to(1)
70
+ listings.keys.should eq ['3']
71
+ end
72
+ end
73
+
74
+ describe "#start" do
75
+ it "creates a thread" do
76
+ Thread.should_receive(:new)
77
+ instance.start
78
+ end
79
+
80
+ it "initializes the socket" do
81
+ instance.should_receive :init_socket
82
+ instance.start
83
+ end
84
+
85
+ it "calls #run" do
86
+ instance.should_receive(:run)
87
+ instance.start
88
+ sleep 0.01
89
+ end
90
+
91
+ it "changes the running state" do
92
+ expect {
93
+ instance.start
94
+ }.to change(instance, :running?).from(false).to(true)
95
+ end
96
+ end
97
+
98
+ describe "#wait_for" do
99
+ it "returns a listing for the given service" do
100
+ server = double(:uuid => 1, :ttl => 5, :services => ["Test"])
101
+ instance.add_listing_for server
102
+ instance.lookup("Test").should eq server
103
+ end
104
+
105
+ it "depends on #lookup" do
106
+ instance.stub(:lookup).with("Hayoob!") { "yup" }
107
+ instance.wait_for("Hayoob!").should eq "yup"
108
+ end
109
+
110
+ it "waits for the service to appear" do
111
+ server = double(:uuid => 1, :ttl => 5, :services => ["Test"])
112
+
113
+ t = Thread.new do
114
+ sleep 0.5
115
+ instance.add_listing_for server
116
+ end
117
+
118
+ duration { instance.wait_for("Test") }.should be_within(0.01).of(0.5)
119
+ t.join
120
+ end
121
+
122
+ it "returns nil if the service doesn't appear withint the timeout period" do
123
+ server = double(:uuid => 1, :ttl => 5, :services => ["Test"])
124
+
125
+ t = Thread.new do
126
+ sleep 0.5
127
+ instance.add_listing_for server
128
+ end
129
+
130
+ instance.wait_for("Test", 0.1).should be_nil
131
+ t.join
132
+ end
133
+ end
134
+
135
+ describe "a running service directory" do
136
+ let(:socket) { UDPSocket.new }
137
+
138
+ def thread
139
+ instance.instance_variable_get(:@thread)
140
+ end
141
+
142
+ before do
143
+ described_class.start do |config|
144
+ config.address = "127.0.0.1"
145
+ config.port = 33333
146
+ end
147
+
148
+ socket.connect described_class.address, described_class.port
149
+ end
150
+
151
+ context "receiving a heartbeat" do
152
+ let(:server) { ::Protobuf::Rpc::DynamicDiscovery::Server.new(:uuid => 'heartbeat', :address => '127.0.0.1') }
153
+ let(:beacon) { ::Protobuf::Rpc::DynamicDiscovery::Beacon.new(
154
+ :server => server,
155
+ :beacon_type => ::Protobuf::Rpc::DynamicDiscovery::BeaconType::HEARTBEAT
156
+ )}
157
+ let(:payload) { beacon.serialize_to_string }
158
+
159
+ it "adds a listing" do
160
+ instance.should_receive(:add_listing_for).with(server)
161
+ instance.should_receive(:remove_expired_listings)
162
+ socket.send(payload, 0)
163
+ sleep 0.01
164
+ end
165
+ end
166
+
167
+ context "receiving a flatline" do
168
+ let(:server) { ::Protobuf::Rpc::DynamicDiscovery::Server.new(:uuid => 'flatline', :address => '127.0.0.1') }
169
+ let(:beacon) { ::Protobuf::Rpc::DynamicDiscovery::Beacon.new(
170
+ :server => server,
171
+ :beacon_type => ::Protobuf::Rpc::DynamicDiscovery::BeaconType::FLATLINE
172
+ )}
173
+ let(:payload) { beacon.serialize_to_string }
174
+
175
+ it "removes a listing" do
176
+ instance.should_receive(:remove_listing_for).with(server)
177
+ instance.should_receive(:remove_expired_listings)
178
+ socket.send(payload, 0)
179
+ sleep 0.01
180
+ end
181
+ end
182
+ end
183
+ end
@@ -53,8 +53,10 @@ class StubServer
53
53
 
54
54
  def start
55
55
  case
56
- when @options.server == Protobuf::Rpc::Evented::Server then start_em_server
57
- when @options.server == Protobuf::Rpc::Zmq::Server then start_zmq_server
56
+ when @options.server == Protobuf::Rpc::Evented::Server
57
+ start_em_server
58
+ when @options.server == Protobuf::Rpc::Zmq::Server
59
+ start_zmq_server
58
60
  else
59
61
  start_socket_server
60
62
  end
@@ -67,18 +69,25 @@ class StubServer
67
69
  end
68
70
 
69
71
  def start_em_server
70
- @server_handle = EventMachine.start_server(@options.host, @options.port, StubProtobufServerFactory.build(@options.delay))
72
+ @server_handle = EventMachine.start_server(
73
+ @options.host,
74
+ @options.port,
75
+ StubProtobufServerFactory.build(@options.delay)
76
+ )
71
77
  end
72
78
 
73
79
  def start_socket_server
74
- @sock_server = Thread.new(@options) { |opt| Protobuf::Rpc::SocketRunner.run(opt) }
75
- @sock_server.abort_on_exception = true # Set for testing purposes
76
- Thread.pass until Protobuf::Rpc::Socket::Server.running?
80
+ @sock_runner = ::Protobuf::Rpc::SocketRunner.new(opt)
81
+ @sock_thread = Thread.new(@sock_runner) { |runner| runner.run }
82
+ @sock_thread.abort_on_exception = true # Set for testing purposes
83
+ Thread.pass until @sock_runner.running?
77
84
  end
78
85
 
79
86
  def start_zmq_server
80
- @zmq_server = Thread.new(@options) { |opt| Protobuf::Rpc::ZmqRunner.run(opt) }
81
- Thread.pass until Protobuf::Rpc::Zmq::Server.running?
87
+ @zmq_runnger = ::Protobuf::Rpc::ZmqRunner.new(opt)
88
+ @zmq_thread = Thread.new(@zmq_runner) { |runner| runner.run }
89
+ @zmq_thread.abort_on_exception = true # Set for testing purposes
90
+ Thread.pass until @zmq_runner.running?
82
91
  end
83
92
 
84
93
  def stop
@@ -86,11 +95,11 @@ class StubServer
86
95
  when @options.server == Protobuf::Rpc::Evented::Server then
87
96
  EventMachine.stop_server(@server_handle) if @server_handle
88
97
  when @options.server == Protobuf::Rpc::Zmq::Server then
89
- Protobuf::Rpc::ZmqRunner.stop
90
- @zmq_server.join if @zmq_server
98
+ @zmq_runner.try :stop
99
+ @zmq_thread.join if @zmq_thread
91
100
  else
92
- Protobuf::Rpc::SocketRunner.stop
93
- @sock_server.join if @sock_server
101
+ @sock_runner.stop
102
+ @sock_thread.join if @sock_thread
94
103
  end
95
104
 
96
105
  @running = false