cocaine-framework-ruby 0.11.2

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.
@@ -0,0 +1,3 @@
1
+ module Cocaine
2
+ VERSION = '0.11.2'
3
+ end
@@ -0,0 +1,160 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../lib/cocaine/asio/channel'
4
+ require_relative '../lib/cocaine/asio/channel/combiner'
5
+
6
+ describe Cocaine::Channel do
7
+ it 'should invoke callback immediately if it has pending data' do
8
+ done = false
9
+ channel = Cocaine::Channel.new
10
+ channel.trigger 'actual'
11
+ channel.callback { |data|
12
+ expect(data).to be == 'actual'
13
+ done = true
14
+ }
15
+ done.should == true
16
+ end
17
+
18
+ it 'should invoke errback immediately if it has pending errors' do
19
+ done = false
20
+ channel = Cocaine::Channel.new
21
+ channel.error 'actual'
22
+ channel.errback { |data|
23
+ expect(data).to be == 'actual'
24
+ done = true
25
+ }
26
+ done.should == true
27
+ end
28
+
29
+ it 'should invoke callback after triggering' do
30
+ done = false
31
+ channel = Cocaine::Channel.new
32
+ channel.callback { |data|
33
+ expect(data).to be == 'actual'
34
+ done = true
35
+ }
36
+ channel.trigger 'actual'
37
+ done.should == true
38
+ end
39
+
40
+ it 'should invoke errback after triggering' do
41
+ done = false
42
+ channel = Cocaine::Channel.new
43
+ channel.errback { |data|
44
+ expect(data).to be == 'actual'
45
+ done = true
46
+ }
47
+ channel.error 'actual'
48
+ done.should == true
49
+ end
50
+
51
+ it 'should invoke all callbacks after closed' do
52
+ counter = 0
53
+
54
+ channel = Cocaine::Channel.new
55
+ channel.trigger 'actual'
56
+ channel.trigger 'actual'
57
+
58
+ channel.callback { |data|
59
+ expect(data).to be == 'actual'
60
+ counter += 1
61
+ }
62
+ channel.close
63
+
64
+ expect counter == 2
65
+ end
66
+
67
+ it 'should raise error when triggered after it was closed' do
68
+ channel = Cocaine::Channel.new
69
+ channel.close
70
+ expect { channel.trigger nil }.to raise_error IllegalStateError
71
+ end
72
+
73
+ it 'should raise error when adding callback after is was closed' do
74
+ channel = Cocaine::Channel.new
75
+ channel.close
76
+ expect { channel.callback {} }.to raise_error IllegalStateError
77
+ end
78
+ end
79
+
80
+ describe Cocaine::Channel, '#collect' do
81
+ it 'should have `collect` method' do
82
+ Cocaine::Channel.new.collect
83
+ end
84
+
85
+ it 'should return all collected chunks after closing' do
86
+ flag = false
87
+ ch = Cocaine::Channel.new
88
+ ch.trigger 'chunk'
89
+ ch.trigger 'chmod'
90
+ ch.trigger 'chang'
91
+ df = ch.collect
92
+ df.callback { |chunks|
93
+ expect(chunks).to eq(%w(chunk chmod chang))
94
+ flag = true
95
+ }
96
+ ch.close
97
+ expect(flag).to be true
98
+ end
99
+
100
+ it 'should return all collected errors after closing' do
101
+ flag = false
102
+ ch = Cocaine::Channel.new
103
+ ch.error Exception.new 123
104
+ ch.error Exception.new 456
105
+ df = ch.collect
106
+ df.callback { |errors|
107
+ expect(errors).to eq([Exception.new(123), Exception.new(456)])
108
+ flag = true
109
+ }
110
+ ch.close
111
+ expect(flag).to be true
112
+ end
113
+
114
+ it 'should fail and return error if only one error comes' do
115
+ flag = false
116
+ ch = Cocaine::Channel.new
117
+ ch.error Exception.new 123
118
+ df = ch.collect
119
+ df.errback { |errors|
120
+ expect(errors).to eq(Exception.new(123))
121
+ flag = true
122
+ }
123
+ ch.close
124
+ expect(flag).to be true
125
+ end
126
+ end
127
+
128
+
129
+ describe Cocaine::ChannelCombiner do
130
+ it 'should be' do
131
+ channel = Cocaine::Channel.new
132
+ Cocaine::ChannelCombiner.new channel
133
+ end
134
+
135
+ it 'should merge callbacks' do
136
+ flag = false
137
+ channel = Cocaine::Channel.new
138
+ zipper = Cocaine::ChannelCombiner.new channel
139
+ zipper.callback { |r|
140
+ expect(r.get).to eq('test')
141
+ flag = true
142
+ }
143
+ channel.trigger('test')
144
+
145
+ expect(flag).to be true
146
+ end
147
+
148
+ it 'should merge errorbacks' do
149
+ flag = false
150
+ channel = Cocaine::Channel.new
151
+ zipper = Cocaine::ChannelCombiner.new channel
152
+ zipper.callback { |r|
153
+ expect { r.get }.to raise_error(Exception)
154
+ flag = true
155
+ }
156
+ channel.error(Exception.new 'test')
157
+
158
+ expect(flag).to be true
159
+ end
160
+ end
@@ -0,0 +1,31 @@
1
+ require 'rspec'
2
+ require 'msgpack'
3
+
4
+ require_relative '../lib/cocaine/asio/connection'
5
+ require_relative '../lib/cocaine/client/dispatcher'
6
+ require_relative '../lib/cocaine/protocol'
7
+
8
+ require_relative 'stub_server'
9
+
10
+ describe Cocaine::Connection do
11
+ it 'should transmit received data to decoder' do
12
+ EventMachine::run {
13
+ msg = [4, 1, [['0.0.0.0', 0], 0, {0 => 'method'}].to_msgpack]
14
+ encoded_msg = msg.to_msgpack
15
+ server = StubServer.new(response: encoded_msg)
16
+
17
+ decoder = double()
18
+ expect(decoder).to receive(:feed).with(encoded_msg) do |&arg|
19
+ arg.call(msg)
20
+ end
21
+ EventMachine.connect '127.0.0.1', 9053, Cocaine::Connection, decoder do |conn|
22
+ dispatcher = Cocaine::ClientDispatcher.new conn
23
+ channel = dispatcher.invoke 0, 'bullshit'
24
+ channel.callback {
25
+ server.stop
26
+ EventMachine::stop
27
+ }
28
+ end
29
+ }
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../lib/cocaine/server/health'
4
+
5
+ describe Cocaine::HealthManager do
6
+ it 'should be' do
7
+ d = double()
8
+ Cocaine::HealthManager.new d
9
+ end
10
+
11
+ it 'should stop event loop if nobody takes breath to it until timeout' do
12
+ EM.run do
13
+ d = double()
14
+ d.should_receive(:send_heartbeat).with(0).once
15
+ health = Cocaine::HealthManager.new d, disown: 0.0, heartbeat: 0.1
16
+ health.start()
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,322 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../lib/cocaine/client/service'
4
+ require_relative '../lib/cocaine/protocol'
5
+ require_relative '../lib/cocaine/synchrony/service'
6
+ require_relative '../lib/cocaine/testing/mock_server'
7
+
8
+ require_relative 'stub_server'
9
+
10
+
11
+ describe Cocaine::Locator do
12
+ it 'should send correct message to the locator while resolving service' do
13
+ EM.run do
14
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'start_app', 1 => 'pause_app', 2 => 'list'}}
15
+ server = CocaineRuntimeMock.new
16
+ server.register 'node', 1, expected
17
+ server.run
18
+
19
+ locator = Cocaine::Locator.new
20
+ locator.resolve('node').callback { |endpoint, version, api|
21
+ expect(endpoint).to eq(expected[:endpoint])
22
+ expect(version).to eq(expected[:version])
23
+ expect(api).to eq(expected[:api])
24
+ EM.stop()
25
+ }.errback {
26
+ fail('Failed')
27
+ EM.stop()
28
+ }
29
+ end
30
+ end
31
+
32
+ it 'should trigger errorback if locator cannot be reached' do
33
+ EM.run do
34
+ locator = Cocaine::Locator.new
35
+ locator.resolve('node-when-locator-not-reached').callback {
36
+ fail('Failed')
37
+ EM.stop()
38
+ }.errback { |err|
39
+ expect(err).to eq(Cocaine::ConnectionError.new)
40
+ EM.stop()
41
+ }
42
+ end
43
+ end
44
+
45
+ it 'should trigger errorback is service can not be resolved' do
46
+ EM.run do
47
+ server = CocaineRuntimeMock.new
48
+ server.on 'locator', [0, 1, ['node']], [Error.new(1, 'service is not available')]
49
+ server.run
50
+
51
+ locator = Cocaine::Locator.new
52
+ locator.resolve('node').callback {
53
+ fail('Failed')
54
+ EM.stop()
55
+ }.errback { |err|
56
+ expect(err).to be_a(Cocaine::ServiceError)
57
+ EM.stop()
58
+ }
59
+ end
60
+ end
61
+ end
62
+
63
+ describe Cocaine::Service do
64
+ it 'should connect to the provided endpoint' do
65
+ flag = false
66
+ EM.run do
67
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'start_app', 1 => 'pause_app', 2 => 'list'}}
68
+ server = CocaineRuntimeMock.new
69
+ server.register 'node', 1, expected
70
+ server.when('node').connected do
71
+ flag = true
72
+ EM.stop
73
+ end
74
+ server.run
75
+
76
+ node = Cocaine::Service.new 'node'
77
+ node.connect
78
+ end
79
+ expect(flag).to be true
80
+ end
81
+
82
+ it 'should provide methods dynamically' do
83
+ flag = false
84
+ EM.run do
85
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'start_app', 1 => 'pause_app', 2 => 'list'}}
86
+ server = CocaineRuntimeMock.new
87
+ server.register 'node', 1, expected
88
+ server.when('node').message([2, 1, []]) do
89
+ flag = true
90
+ EM.stop
91
+ ['app']
92
+ end
93
+ server.run
94
+
95
+ node = Cocaine::Service.new 'node'
96
+ node.connect.callback {
97
+ node.list
98
+ }.errback { |err|
99
+ fail("Failed: #{err}")
100
+ EM.stop
101
+ }
102
+ end
103
+ expect(flag).to be true
104
+ end
105
+
106
+ it 'should return error if service cannot be reached' do
107
+ EM.synchrony do
108
+ server = CocaineRuntimeMock.new
109
+ server.on 'locator',
110
+ [0, 1, ['node']],
111
+ [[['127.0.0.1', 10054], 1, {0 => 'start_app', 1 => 'pause_app', 2 => 'list'}]]
112
+ server.run
113
+
114
+ node = Cocaine::Service.new 'node'
115
+ node.connect.callback {
116
+ fail('Failed')
117
+ EM.stop
118
+ }.errback { |err|
119
+ expect(err).to be_a(Cocaine::ConnectionError)
120
+ EM.stop
121
+ }
122
+ end
123
+ end
124
+
125
+ it 'should return future with error if service throws error' do
126
+ counter = 0
127
+ EM.synchrony do
128
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'list'}}
129
+ server = CocaineRuntimeMock.new
130
+ server.register 'node', 1, expected
131
+ server.when('node').message([0, 1, []]) do
132
+ [Error.new(1, 'wtf')]
133
+ end
134
+ server.run
135
+
136
+ expected = [Cocaine::ServiceError, ChokeEvent]
137
+ node = Cocaine::Service.new 'node'
138
+ node.connect.callback {
139
+ node.list.callback { |future|
140
+ expect { future.get }.to raise_error expected[counter]
141
+ counter += 1
142
+ EM.stop if counter == 2
143
+ }
144
+ }.errback {
145
+ fail('Failed')
146
+ EM.stop
147
+ }
148
+ end
149
+ expect(counter).to be 2
150
+ end
151
+ end
152
+
153
+ describe Cocaine::Synchrony::Service do
154
+ it 'should synchrony connect to the service' do
155
+ flag = false
156
+ EM.synchrony do
157
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {}}
158
+ server = CocaineRuntimeMock.new
159
+ server.register 'mock-app', 1, expected
160
+ server.when('mock-app').connected do
161
+ flag = true
162
+ EM.stop
163
+ end
164
+ server.run
165
+
166
+ Cocaine::Synchrony::Service.new 'mock-app'
167
+ end
168
+ expect(flag).to be true
169
+ end
170
+
171
+ it 'should throw error on locator connect failure' do
172
+ EM.synchrony do
173
+ expect { Cocaine::Synchrony::Service.new 'mock-app' }.to raise_error Cocaine::ConnectionError
174
+ EM.stop
175
+ end
176
+ end
177
+
178
+ it 'should throw error on connect failure' do
179
+ EM.synchrony do
180
+ server = CocaineRuntimeMock.new
181
+ server.on 'locator',
182
+ [0, 1, ['mock-app']],
183
+ [[['127.0.0.1', 10054], 1, {0 => 'start_app', 1 => 'pause_app', 2 => 'list'}]]
184
+ server.run
185
+
186
+ expect { Cocaine::Synchrony::Service.new 'mock-app' }.to raise_error Cocaine::ConnectionError
187
+ EM.stop
188
+ end
189
+ end
190
+
191
+ it 'should synchrony read exactly one chunk' do
192
+ EM.synchrony do
193
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
194
+ server = CocaineRuntimeMock.new
195
+ server.register 'mock-app', 1, expected
196
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1'] }
197
+ server.run
198
+
199
+ service = Cocaine::Synchrony::Service.new 'mock-app'
200
+ ch = service.enqueue('ping', 'message')
201
+ msg = ch.read
202
+ expect(msg).to eq('chunk#1')
203
+ EM.stop
204
+ end
205
+ end
206
+
207
+ it 'should synchrony read exactly three chunks' do
208
+ EM.synchrony do
209
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
210
+ server = CocaineRuntimeMock.new
211
+ server.register 'mock-app', 1, expected
212
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', 'chunk#2', 'chunk#3'] }
213
+ server.run
214
+
215
+ service = Cocaine::Synchrony::Service.new 'mock-app'
216
+ ch = service.enqueue('ping', 'message')
217
+ msg = [nil] * 3
218
+ msg[0] = ch.read
219
+ msg[1] = ch.read
220
+ msg[2] = ch.read
221
+ expect(msg).to eq(['chunk#1', 'chunk#2', 'chunk#3'])
222
+ EM.stop
223
+ end
224
+ end
225
+
226
+ it 'should synchrony partial read chunks via collect' do
227
+ EM.synchrony do
228
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
229
+ server = CocaineRuntimeMock.new
230
+ server.register 'mock-app', 1, expected
231
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', 'chunk#2', 'chunk#3'] }
232
+ server.run
233
+
234
+ service = Cocaine::Synchrony::Service.new 'mock-app'
235
+ ch = service.enqueue('ping', 'message')
236
+ actual = ch.collect(2)
237
+ expect(actual).to eq(['chunk#1', 'chunk#2'])
238
+ EM.stop
239
+ end
240
+ end
241
+
242
+ it 'should synchrony fully read chunks via collect' do
243
+ EM.synchrony do
244
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
245
+ server = CocaineRuntimeMock.new
246
+ server.register 'mock-app', 1, expected
247
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', 'chunk#2', 'chunk#3'] }
248
+ server.run
249
+
250
+ service = Cocaine::Synchrony::Service.new 'mock-app'
251
+ ch = service.enqueue('ping', 'message')
252
+ actual = ch.collect(3)
253
+ expect(actual).to eq(['chunk#1', 'chunk#2', 'chunk#3'])
254
+ EM.stop
255
+ end
256
+ end
257
+
258
+ it 'should synchrony read chunks until choke' do
259
+ EM.synchrony do
260
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
261
+ server = CocaineRuntimeMock.new
262
+ server.register 'mock-app', 1, expected
263
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', 'chunk#2', 'chunk#3'] }
264
+ server.run
265
+
266
+ service = Cocaine::Synchrony::Service.new 'mock-app'
267
+ ch = service.enqueue('ping', 'message')
268
+ actual = ch.collect()
269
+ expect(actual).to eq(['chunk#1', 'chunk#2', 'chunk#3'])
270
+ EM.stop
271
+ end
272
+ end
273
+
274
+ it 'should synchrony iterate chunks with each method' do
275
+ EM.synchrony do
276
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
277
+ server = CocaineRuntimeMock.new
278
+ server.register 'mock-app', 1, expected
279
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', 'chunk#2', 'chunk#3'] }
280
+ server.run
281
+
282
+ results = []
283
+ service = Cocaine::Synchrony::Service.new 'mock-app'
284
+ ch = service.enqueue('ping', 'message')
285
+ ch.each do |result|
286
+ results.push result
287
+ end
288
+ expect(results).to eq(['chunk#1', 'chunk#2', 'chunk#3'])
289
+ EM.stop
290
+ end
291
+ end
292
+
293
+ it 'should throw error on error received while single fetching' do
294
+ EM.synchrony do
295
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
296
+ server = CocaineRuntimeMock.new
297
+ server.register 'mock-app', 1, expected
298
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { [Error.new(1, 'Some error occurred')] }
299
+ server.run
300
+
301
+ service = Cocaine::Synchrony::Service.new 'mock-app'
302
+ ch = service.enqueue('ping', 'message')
303
+ expect { ch.read }.to raise_error Cocaine::ServiceError
304
+ EM.stop
305
+ end
306
+ end
307
+
308
+ it 'should throw error on error received while collect fetching' do
309
+ EM.synchrony do
310
+ expected = {endpoint: ['127.0.0.1', 10054], version: 1, api: {0 => 'enqueue', 1 => 'info'}}
311
+ server = CocaineRuntimeMock.new
312
+ server.register 'mock-app', 1, expected
313
+ server.when('mock-app').message([0, 1, ['ping', 'message']]) { ['chunk#1', Error.new(1, 'Some error occurred')] }
314
+ server.run
315
+
316
+ service = Cocaine::Synchrony::Service.new 'mock-app'
317
+ ch = service.enqueue('ping', 'message')
318
+ expect { ch.collect }.to raise_error Cocaine::ServiceError
319
+ EM.stop
320
+ end
321
+ end
322
+ end