green 0.0.1 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,417 @@
1
+ # based on https://github.com/igrigorik/em-synchrony/pull/127
2
+
3
+ require 'spec_helper'
4
+ require 'green/socket'
5
+ require 'green/group'
6
+ require 'green/event'
7
+ describe Green::TCPSocket do
8
+ describe '.new' do
9
+ describe 'to an open TCP port on an resolvable host' do
10
+ it 'succeeds' do
11
+ Green.spawn do
12
+ s = Green::TCPServer.new '127.0.0.1', 12345
13
+ s.accept
14
+ s.close
15
+ end
16
+ Green.spawn do
17
+ s = Green::TCPSocket.new '127.0.0.1', 12345
18
+ s.close
19
+ end.join
20
+ end
21
+ end
22
+
23
+ describe 'to an unresolvable host' do
24
+ it 'raises SocketError' do
25
+ proc {
26
+ Green::TCPSocket.new 'xxxyyyzzz', 12345
27
+ }.must_raise SocketError
28
+ end
29
+ end
30
+
31
+ describe 'to a closed TCP port' do
32
+ it 'raises Errno::ECONNREFUSED' do
33
+ proc {
34
+ Green::TCPSocket.new '127.0.0.1', 12345
35
+ }.must_raise Errno::ECONNREFUSED
36
+ end
37
+ end
38
+ end
39
+
40
+ def in_connect(&blk)
41
+ server = Green::TCPServer.new '127.0.0.1', 12345
42
+ s = nil
43
+ client = nil
44
+ g = Green::Group.new
45
+ g.spawn do
46
+ s = server.accept
47
+ s.write '1234'
48
+ end
49
+ g.spawn do
50
+ client = Green::TCPSocket.new '127.0.0.1', 12345
51
+ end
52
+ g.join
53
+ blk.call s, client
54
+ ensure
55
+ s.close rescue nil
56
+ client.close rescue nil
57
+ server.close rescue nil
58
+ end
59
+
60
+ describe '#closed?' do
61
+ describe 'after calling #close' do
62
+ it 'returns true' do
63
+ in_connect do |s, c|
64
+ c.close
65
+ c.closed?.must_equal true
66
+ end
67
+ end
68
+ end
69
+ describe 'after the peer has closed the connection' do
70
+ describe 'when we\'ve not yet read EOF' do
71
+ it 'returns false' do
72
+ in_connect do |s, c|
73
+ s.close
74
+ c.read(2).size.must_equal 2
75
+ c.closed?.must_equal false
76
+ end
77
+ end
78
+ end
79
+ describe 'when we\'ve read EOF' do
80
+ it 'returns false' do
81
+ in_connect do |s, c|
82
+ s.close
83
+ c.read(10).size.must_equal 4
84
+ c.read(10).must_equal nil
85
+ c.closed?.must_equal false
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#read' do
93
+ describe 'with a length argument' do
94
+ describe 'with a possitive length argument' do
95
+ describe 'when the connection is open' do
96
+ describe 'with greater or equal than the requested data buffered' do
97
+ it 'returns the requested data and no more' do
98
+ in_connect do |s, c|
99
+ c.read(2).size.must_equal 2
100
+ c.read(1).size.must_equal 1
101
+ end
102
+ end
103
+ end
104
+ describe 'with less than the requested data buffered' do
105
+ it 'blocks' do
106
+ in_connect do |s, c|
107
+ blocked = true
108
+ g = Green.spawn { blocked.must_equal true; s.close }
109
+ res = c.read(10)
110
+ blocked = false
111
+ g.join
112
+ end
113
+ end
114
+ end
115
+ end
116
+ describe 'when the peer has closed the connection' do
117
+ describe 'with no data buffered' do
118
+ it 'returns nil' do
119
+ in_connect do |s, c|
120
+ s.close
121
+ c.read(4).size.must_equal 4
122
+ c.read(1).must_equal nil
123
+ end
124
+ end
125
+ end
126
+ describe 'with less than the requested data buffered' do
127
+ it 'returns the buffered data' do
128
+ in_connect do |s, c|
129
+ s.close
130
+ c.read(50).size.must_equal 4
131
+ end
132
+ end
133
+ end
134
+ describe 'with greater or equal than the requested data buffered' do
135
+ it 'returns the requested data and no more' do
136
+ in_connect do |s, c|
137
+ c.read(2).size.must_equal 2
138
+ end
139
+ end
140
+ end
141
+ end
142
+ describe 'when we closed the connection' do
143
+ it 'raises IOError' do
144
+ in_connect do |s, c|
145
+ c.close
146
+ proc {
147
+ c.read(4)
148
+ }.must_raise IOError
149
+ end
150
+ end
151
+ end
152
+ end
153
+ describe 'with a negative length argument' do
154
+ it 'raises ArgumentError' do
155
+ in_connect do |s, c|
156
+ proc {
157
+ c.read(-10)
158
+ }.must_raise ArgumentError
159
+ end
160
+ end
161
+ end
162
+ describe 'with a zero length argument' do
163
+ describe 'when the connection is open' do
164
+ it 'returns an empty string' do
165
+ in_connect do |s, c|
166
+ c.read(0).must_equal ""
167
+ end
168
+ end
169
+ end
170
+ describe 'when the peer has closed the connection' do
171
+ it 'returns an empty string' do
172
+ in_connect do |s, c|
173
+ s.close
174
+ c.read(0).must_equal ""
175
+ end
176
+ end
177
+ end
178
+ describe 'when we closed the connection' do
179
+ it 'raises IOError' do
180
+ in_connect do |s, c|
181
+ c.close
182
+ proc {
183
+ c.read(0)
184
+ }.must_raise IOError
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+ describe 'without a length argument' do
191
+ describe 'when the connection is open' do
192
+ it 'blocks until the peer closes the connection and returns all data sent' do
193
+ in_connect do |s, c|
194
+ blocked = true
195
+ Green.hub.timer(0.01) { blocked.must_equal true; s.close }
196
+ c.read(10).must_equal '1234'
197
+ blocked = false
198
+ end
199
+ end
200
+ end
201
+ describe 'when the peer has closed the connection' do
202
+ describe 'with no data buffered' do
203
+ it 'returns an empty string' do
204
+ in_connect do |s, c|
205
+ s.close
206
+ c.read
207
+ c.read.must_equal ""
208
+ end
209
+ end
210
+ end
211
+ describe 'with data buffered' do
212
+ it 'returns the buffered data' do
213
+ in_connect do |s, c|
214
+ s.close
215
+ c.read.must_equal "1234"
216
+ end
217
+ end
218
+ end
219
+ end
220
+ describe 'when we closed the connection' do
221
+ it 'raises IOError' do
222
+ in_connect do |s, c|
223
+ c.close
224
+ proc {
225
+ c.read
226
+ }.must_raise IOError
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ describe '#recv' do
234
+ describe 'with a length argument' do
235
+ describe 'with a positive length argument' do
236
+ describe 'when the connection is open' do
237
+ describe 'with greater or equal than the requested data buffered' do
238
+ it 'returns the requested data and no more' do
239
+ in_connect do |s, c|
240
+ c.recv(2).size.must_equal 2
241
+ c.recv(1).size.must_equal 1
242
+ end
243
+ end
244
+ end
245
+ describe 'with less than the requested data buffered' do
246
+ it 'return the buffered data' do
247
+ in_connect do |s, c|
248
+ c.recv(50).size.must_equal 4
249
+ end
250
+ end
251
+ end
252
+ describe 'with no buffered data' do
253
+ it 'blocks' do
254
+ in_connect do |s, c|
255
+ c.recv(10)
256
+ blocked = true
257
+ g = Green.spawn do
258
+ blocked.must_equal true
259
+ s.close
260
+ end
261
+ c.recv(10)
262
+ blocked = false
263
+ g.join
264
+ end
265
+ end
266
+ end
267
+ end
268
+ describe 'when the peer has closed the connection' do
269
+ describe 'with no data buffered' do
270
+ it 'returns an empty string' do
271
+ in_connect do |s, c|
272
+ s.close
273
+ c.read(4).size.must_equal 4
274
+ c.recv(1).must_equal ""
275
+ end
276
+ end
277
+ end
278
+ describe 'with less than the requested data buffered' do
279
+ it 'returns the buffered data' do
280
+ in_connect do |s, c|
281
+ s.close
282
+ c.recv(50).size.must_equal 4
283
+ end
284
+ end
285
+ end
286
+ describe 'with greater or equal than the requested data buffered' do
287
+ it 'returns the requested data and no more' do
288
+ in_connect do |s, c|
289
+ s.close
290
+ c.recv(2).size.must_equal 2
291
+ end
292
+ end
293
+ end
294
+ end
295
+ describe 'when we closed the connection' do
296
+ it 'raises IOError' do
297
+ in_connect do |s, c|
298
+ c.close
299
+ proc {
300
+ res = c.recv(4)
301
+ }.must_raise IOError
302
+ end
303
+ end
304
+ end
305
+ end
306
+ describe 'with a negative length argument' do
307
+ it 'raises ArgumentError' do
308
+ in_connect do |s, c|
309
+ proc {
310
+ c.recv(-10)
311
+ }.must_raise ArgumentError
312
+ end
313
+ end
314
+ end
315
+ describe 'with a zero length argument' do
316
+ describe 'when the connection is open' do
317
+ it 'returns an empty string' do
318
+ in_connect do |s, c|
319
+ c.recv(0).must_equal ""
320
+ end
321
+ end
322
+ end
323
+ describe 'when the peer has closed the connection' do
324
+ it 'returns an empty string' do
325
+ in_connect do |s, c|
326
+ s.close
327
+ c.recv(0).must_equal ""
328
+ end
329
+ end
330
+ end
331
+ describe 'when we closed the connection' do
332
+ it 'raises IOError' do
333
+ in_connect do |s, c|
334
+ c.close
335
+ proc {
336
+ c.recv(0)
337
+ }.must_raise IOError
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
343
+ describe 'without a length argument' do
344
+ it 'raises ArgumentError' do
345
+ in_connect do |s, c|
346
+ proc {
347
+ c.recv()
348
+ }.must_raise ArgumentError
349
+ end
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#write' do
355
+ describe 'when the peer has closed the connection' do
356
+ it 'raises Errno::EPIPE' do
357
+ in_connect do |s, c|
358
+ s.close
359
+ Green.spawn do
360
+ Green.sleep 0.01
361
+ proc {
362
+ c.write 100000.times.to_a * '' # on small chunks it can not raise exception
363
+ }.must_raise Errno::EPIPE, Errno::ECONNRESET, Errno::EBADF
364
+ end.join
365
+ end
366
+ end
367
+ end
368
+ describe 'when we closed the connection' do
369
+ it 'raises IOError' do
370
+ in_connect do |s, c|
371
+ c.close
372
+ proc {
373
+ c.write("foo")
374
+ }.must_raise IOError
375
+ end
376
+ end
377
+ end
378
+ end
379
+
380
+ describe '#send' do
381
+ describe 'when the peer has closed the connection' do
382
+ it 'raises Errno::EPIPE' do
383
+ in_connect do |s, c|
384
+ s.close
385
+ Green.spawn do
386
+ Green.sleep 0.01
387
+ proc {
388
+ c.send 100000.times.to_a * '', 0
389
+ }.must_raise Errno::EPIPE, Errno::ECONNRESET, Errno::EBADF
390
+ end.join
391
+ end
392
+ end
393
+ end
394
+
395
+ describe 'when we closed the connection' do
396
+ it 'raises IOError' do
397
+ in_connect do |s, c|
398
+ c.close
399
+ proc {
400
+ c.send "foo", 0
401
+ }.must_raise IOError
402
+ end
403
+ end
404
+ end
405
+
406
+ describe 'without a flags argument' do
407
+ it 'raises ArgumentError' do
408
+ in_connect do |s, c|
409
+ proc {
410
+ c.send 'foo'
411
+ }.must_raise ArgumentError
412
+ end
413
+ end
414
+ end
415
+ end
416
+
417
+ end
@@ -0,0 +1,121 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "spec_helper"
3
+ require 'green/zmq'
4
+ require 'green/group'
5
+
6
+ describe ZMQ::Socket do
7
+
8
+ describe "simple case" do
9
+ before do
10
+ @ctx = ZMQ::Context.new
11
+ @rep = @ctx.socket(ZMQ::REP)
12
+ @req = @ctx.socket(ZMQ::REQ)
13
+ @rep.bind('inproc://test')
14
+ @req.connect('inproc://test')
15
+ end
16
+
17
+ after do
18
+ @req.close
19
+ @rep.close
20
+ @ctx.terminate
21
+ end
22
+
23
+ it "works" do
24
+ @req.send_string 'hello'
25
+ Green.spawn do
26
+ str = ''
27
+ @rep.recv_string(str)
28
+ str.must_equal 'hello'
29
+ end.join
30
+ end
31
+ end
32
+
33
+ # describe "complex topology" do
34
+ # let(:router_endpoint) { "tcp://127.0.0.1:12345" }
35
+ # let(:dealer_endpoint) { "tcp://127.0.0.1:12346" }
36
+ # before do
37
+ # @ctx = ZMQ::Context.new
38
+ # @router = @ctx.socket ZMQ::ROUTER
39
+ # @dealer = @ctx.socket ZMQ::DEALER
40
+ # @router.bind(router_endpoint)
41
+ # @dealer.bind(dealer_endpoint)
42
+ # @router_green = Green.spawn do
43
+ # begin
44
+ # strings = []
45
+ # while (@router.recv_strings(strings) == 0)
46
+ # @dealer.send_strings strings
47
+ # strings = []
48
+ # end
49
+ # ensure
50
+ # @router.close
51
+ # end
52
+ # end
53
+ # @dealer_green = Green.spawn do
54
+ # begin
55
+ # strings = []
56
+ # while (@dealer.recv_strings(strings) == 0)
57
+ # @router.send_strings strings
58
+ # strings = []
59
+ # end
60
+ # ensure
61
+ # @dealer.close
62
+ # end
63
+ # end
64
+ # end
65
+
66
+ # def spawn_workers
67
+ # @workers_ctx = ZMQ::Context.new
68
+ # @workers = Green::Group.new
69
+ # 10.times.map do
70
+ # @workers.spawn do
71
+ # begin
72
+ # s = @workers_ctx.socket ZMQ::REP
73
+ # s.connect dealer_endpoint
74
+ # strings = []
75
+ # while (s.recv_strings(strings) == 0)
76
+ # s.send_string((strings.first.to_i + 1).to_s)
77
+ # strings = []
78
+ # end
79
+ # ensure
80
+ # s.close
81
+ # end
82
+ # end
83
+ # end
84
+ # end
85
+
86
+ # it "should increment numbers" do
87
+ # ctx = ZMQ::Context.new
88
+ # clients = Green::Group.new
89
+ # 5.times do
90
+ # clients.spawn do
91
+ # s = ctx.socket ZMQ::REQ
92
+ # s.connect router_endpoint
93
+ # i = 0
94
+ # str = ''
95
+ # 10.times do
96
+ # s.send_string i.to_s
97
+ # s.recv_string str
98
+ # i = str.to_i
99
+ # end
100
+ # s.close
101
+ # i.must_equal 10
102
+ # end
103
+ # end
104
+ # Green.spawn do
105
+ # Green.sleep 1
106
+ # spawn_workers
107
+ # end
108
+ # clients.join
109
+ # ctx.terminate
110
+ # end
111
+
112
+ # after do
113
+ # @workers.kill
114
+ # @router_green.kill
115
+ # @dealer_green.kill
116
+ # # @ctx.terminate # FIXME
117
+ # # @workers_ctx.terminate
118
+ # end
119
+ # end
120
+ end
121
+
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Green do
4
+ describe ".spawn" do
5
+ it "should spawn greens" do
6
+ g = Green.spawn do
7
+ :hello
8
+ end
9
+ g.join.must_equal :hello
10
+ end
11
+ end
12
+
13
+ describe "sleep" do
14
+ it "should set sleep" do
15
+ t = Time.now
16
+ Green.spawn do
17
+ Green.sleep 0.1
18
+ end.join
19
+ (Time.now - t).must_be :>, 0.1
20
+ end
21
+ end
22
+
23
+ describe "timeouts" do
24
+ it "should set timeout" do
25
+ t = Time.now
26
+ Green.spawn do
27
+ begin
28
+ Green.timeout(0.01) do
29
+ Green.sleep 0.1
30
+ end
31
+ rescue Timeout::Error
32
+ end
33
+ end.join
34
+ (Time.now - t).must_be :<, 0.1
35
+ end
36
+ end
37
+ end
data/spec/helpers.rb ADDED
File without changes
@@ -0,0 +1,32 @@
1
+ require 'bundler'
2
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
3
+ Bundler.setup
4
+
5
+ require 'minitest/spec'
6
+ require 'minitest/autorun'
7
+ require 'minitest/reporters'
8
+
9
+ require 'helpers'
10
+
11
+ require 'green'
12
+
13
+ MiniTest::Unit.runner = MiniTest::SuiteRunner.new
14
+ MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
15
+
16
+
17
+ # class MiniTest::Spec
18
+ # def teardown
19
+ # g = Green.current
20
+ # Green.hub.callback { g.switch }
21
+ # Green.hub.switch
22
+ # puts "Callback: #{Green.hub.callbacks.size}; Timers: #{Green.hub.timers.size}; Cancels: #{Green.hub.cancel_timers.size}"
23
+ # puts Green.hub.callbacks.inspect
24
+ # end
25
+ # end
26
+
27
+ # at_exit {
28
+ # loop do
29
+ # MiniTest::Unit.new.run
30
+ # break if MiniTest::Unit.runner.errors != 0
31
+ # end
32
+ # }