ione 1.0.0 → 1.1.0.pre0
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.
- checksums.yaml +4 -4
- data/lib/ione/io/acceptor.rb +96 -0
- data/lib/ione/io/base_connection.rb +162 -0
- data/lib/ione/io/connection.rb +9 -150
- data/lib/ione/io/io_reactor.rb +15 -0
- data/lib/ione/io/server_connection.rb +17 -0
- data/lib/ione/io.rb +6 -0
- data/lib/ione/version.rb +1 -1
- data/spec/integration/io_spec.rb +41 -4
- data/spec/ione/io/acceptor_spec.rb +223 -0
- data/spec/ione/io/connection_common.rb +255 -0
- data/spec/ione/io/connection_spec.rb +23 -178
- data/spec/ione/io/io_reactor_spec.rb +48 -3
- data/spec/ione/io/server_connection_spec.rb +37 -0
- metadata +13 -4
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
+
require 'ione/io/connection_common'
|
4
5
|
|
5
6
|
|
6
7
|
module Ione
|
@@ -38,10 +39,21 @@ module Ione
|
|
38
39
|
.and_return(socket)
|
39
40
|
end
|
40
41
|
|
42
|
+
before do
|
43
|
+
socket.stub(:connect_nonblock)
|
44
|
+
socket.stub(:close)
|
45
|
+
end
|
46
|
+
|
47
|
+
it_behaves_like 'a connection' do
|
48
|
+
before do
|
49
|
+
handler.connect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
41
53
|
describe '#connect' do
|
42
54
|
it 'creates a socket and calls #connect_nonblock' do
|
43
|
-
socket.should_receive(:connect_nonblock).with('SOCKADDR1')
|
44
55
|
handler.connect
|
56
|
+
socket.should have_received(:connect_nonblock).with('SOCKADDR1')
|
45
57
|
end
|
46
58
|
|
47
59
|
it 'handles EINPROGRESS that #connect_nonblock raises' do
|
@@ -56,23 +68,26 @@ module Ione
|
|
56
68
|
end
|
57
69
|
|
58
70
|
it 'is connecting even after the second call' do
|
59
|
-
socket.
|
71
|
+
socket.stub(:connect_nonblock).and_raise(Errno::EINPROGRESS)
|
60
72
|
handler.connect
|
61
73
|
handler.connect
|
62
74
|
handler.should be_connecting
|
75
|
+
socket.should have_received(:connect_nonblock).twice
|
63
76
|
end
|
64
77
|
|
65
78
|
it 'does not create a new socket the second time' do
|
66
|
-
socket_impl.
|
79
|
+
socket_impl.stub(:new).and_return(socket)
|
67
80
|
socket.stub(:connect_nonblock).and_raise(Errno::EINPROGRESS)
|
68
81
|
handler.connect
|
69
82
|
handler.connect
|
83
|
+
socket_impl.should have_received(:new).once
|
70
84
|
end
|
71
85
|
|
72
86
|
it 'attempts another connect the second time' do
|
73
|
-
socket.
|
87
|
+
socket.stub(:connect_nonblock).and_raise(Errno::EINPROGRESS)
|
74
88
|
handler.connect
|
75
89
|
handler.connect
|
90
|
+
socket.should have_received(:connect_nonblock).twice
|
76
91
|
end
|
77
92
|
|
78
93
|
shared_examples 'on successfull connection' do
|
@@ -264,60 +279,6 @@ module Ione
|
|
264
279
|
end
|
265
280
|
end
|
266
281
|
|
267
|
-
describe '#close' do
|
268
|
-
before do
|
269
|
-
socket.stub(:connect_nonblock)
|
270
|
-
socket.stub(:close)
|
271
|
-
handler.connect
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'closes the socket' do
|
275
|
-
socket.should_receive(:close)
|
276
|
-
handler.close
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'returns true' do
|
280
|
-
handler.close.should be_true
|
281
|
-
end
|
282
|
-
|
283
|
-
it 'swallows SystemCallErrors' do
|
284
|
-
socket.stub(:close).and_raise(SystemCallError.new('Bork!', 9999))
|
285
|
-
handler.close
|
286
|
-
end
|
287
|
-
|
288
|
-
it 'swallows IOErrors' do
|
289
|
-
socket.stub(:close).and_raise(IOError.new('Bork!'))
|
290
|
-
handler.close
|
291
|
-
end
|
292
|
-
|
293
|
-
it 'calls the closed listener' do
|
294
|
-
called = false
|
295
|
-
handler.on_closed { called = true }
|
296
|
-
handler.close
|
297
|
-
called.should be_true, 'expected the close listener to have been called'
|
298
|
-
end
|
299
|
-
|
300
|
-
it 'does nothing when closed a second time' do
|
301
|
-
socket.should_receive(:close).once
|
302
|
-
calls = 0
|
303
|
-
handler.on_closed { calls += 1 }
|
304
|
-
handler.close
|
305
|
-
handler.close
|
306
|
-
calls.should == 1
|
307
|
-
end
|
308
|
-
|
309
|
-
it 'returns false if it did nothing' do
|
310
|
-
handler.close
|
311
|
-
handler.close.should be_false
|
312
|
-
end
|
313
|
-
|
314
|
-
it 'is not writable when closed' do
|
315
|
-
handler.write('foo')
|
316
|
-
handler.close
|
317
|
-
handler.should_not be_writable
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
282
|
describe '#to_io' do
|
322
283
|
before do
|
323
284
|
socket.stub(:connect_nonblock)
|
@@ -340,128 +301,10 @@ module Ione
|
|
340
301
|
end
|
341
302
|
end
|
342
303
|
|
343
|
-
describe '#write/#flush' do
|
344
|
-
before do
|
345
|
-
socket.stub(:connect_nonblock)
|
346
|
-
handler.connect
|
347
|
-
end
|
348
|
-
|
349
|
-
it 'appends to its buffer when #write is called' do
|
350
|
-
handler.write('hello world')
|
351
|
-
end
|
352
|
-
|
353
|
-
it 'unblocks the reactor' do
|
354
|
-
unblocker.should_receive(:unblock!)
|
355
|
-
handler.write('hello world')
|
356
|
-
end
|
357
|
-
|
358
|
-
it 'is writable when there are bytes to write' do
|
359
|
-
handler.should_not be_writable
|
360
|
-
handler.write('hello world')
|
361
|
-
handler.should be_writable
|
362
|
-
socket.should_receive(:write_nonblock).with('hello world').and_return(11)
|
363
|
-
handler.flush
|
364
|
-
handler.should_not be_writable
|
365
|
-
end
|
366
|
-
|
367
|
-
it 'writes to the socket from its buffer when #flush is called' do
|
368
|
-
handler.write('hello world')
|
369
|
-
socket.should_receive(:write_nonblock).with('hello world').and_return(11)
|
370
|
-
handler.flush
|
371
|
-
end
|
372
|
-
|
373
|
-
it 'takes note of how much the #write_nonblock call consumed and writes the rest of the buffer on the next call to #flush' do
|
374
|
-
handler.write('hello world')
|
375
|
-
socket.should_receive(:write_nonblock).with('hello world').and_return(6)
|
376
|
-
handler.flush
|
377
|
-
socket.should_receive(:write_nonblock).with('world').and_return(5)
|
378
|
-
handler.flush
|
379
|
-
end
|
380
|
-
|
381
|
-
it 'does not call #write_nonblock if the buffer is empty' do
|
382
|
-
handler.flush
|
383
|
-
handler.write('hello world')
|
384
|
-
socket.should_receive(:write_nonblock).with('hello world').and_return(11)
|
385
|
-
handler.flush
|
386
|
-
socket.should_not_receive(:write_nonblock)
|
387
|
-
handler.flush
|
388
|
-
end
|
389
|
-
|
390
|
-
context 'with a block' do
|
391
|
-
it 'yields a byte buffer to the block' do
|
392
|
-
socket.should_receive(:write_nonblock).with('hello world').and_return(11)
|
393
|
-
handler.write do |buffer|
|
394
|
-
buffer << 'hello world'
|
395
|
-
end
|
396
|
-
handler.flush
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
context 'when #write_nonblock raises an error' do
|
401
|
-
before do
|
402
|
-
socket.stub(:close)
|
403
|
-
socket.stub(:write_nonblock).and_raise('Bork!')
|
404
|
-
end
|
405
|
-
|
406
|
-
it 'closes the socket' do
|
407
|
-
socket.should_receive(:close)
|
408
|
-
handler.write('hello world')
|
409
|
-
handler.flush
|
410
|
-
end
|
411
|
-
|
412
|
-
it 'passes the error to the close handler' do
|
413
|
-
error = nil
|
414
|
-
handler.on_closed { |e| error = e }
|
415
|
-
handler.write('hello world')
|
416
|
-
handler.flush
|
417
|
-
error.should be_a(Exception)
|
418
|
-
end
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
describe '#read' do
|
423
|
-
before do
|
424
|
-
socket.stub(:connect_nonblock)
|
425
|
-
handler.connect
|
426
|
-
end
|
427
|
-
|
428
|
-
it 'reads a chunk from the socket' do
|
429
|
-
socket.should_receive(:read_nonblock).with(instance_of(Fixnum)).and_return('foo bar')
|
430
|
-
handler.read
|
431
|
-
end
|
432
|
-
|
433
|
-
it 'calls the data listener with the new data' do
|
434
|
-
socket.should_receive(:read_nonblock).with(instance_of(Fixnum)).and_return('foo bar')
|
435
|
-
data = nil
|
436
|
-
handler.on_data { |d| data = d }
|
437
|
-
handler.read
|
438
|
-
data.should == 'foo bar'
|
439
|
-
end
|
440
|
-
|
441
|
-
context 'when #read_nonblock raises an error' do
|
442
|
-
before do
|
443
|
-
socket.stub(:close)
|
444
|
-
socket.stub(:read_nonblock).and_raise('Bork!')
|
445
|
-
end
|
446
|
-
|
447
|
-
it 'closes the socket' do
|
448
|
-
socket.should_receive(:close)
|
449
|
-
handler.read
|
450
|
-
end
|
451
|
-
|
452
|
-
it 'passes the error to the close handler' do
|
453
|
-
error = nil
|
454
|
-
handler.on_closed { |e| error = e }
|
455
|
-
handler.read
|
456
|
-
error.should be_a(Exception)
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
304
|
describe '#to_s' do
|
462
305
|
context 'returns a string that' do
|
463
306
|
it 'includes the class name' do
|
464
|
-
handler.to_s.should include(
|
307
|
+
handler.to_s.should include(described_class.name.to_s)
|
465
308
|
end
|
466
309
|
|
467
310
|
it 'includes the host and port' do
|
@@ -469,13 +312,15 @@ module Ione
|
|
469
312
|
end
|
470
313
|
|
471
314
|
it 'includes the connection state' do
|
472
|
-
handler.to_s.should include('
|
315
|
+
handler.to_s.should include('connecting')
|
473
316
|
socket.stub(:connect_nonblock).and_raise(Errno::EINPROGRESS)
|
474
317
|
handler.connect
|
475
318
|
handler.to_s.should include('connecting')
|
476
319
|
socket.stub(:connect_nonblock)
|
477
320
|
handler.connect
|
478
321
|
handler.to_s.should include('connected')
|
322
|
+
handler.close
|
323
|
+
handler.to_s.should include('closed')
|
479
324
|
end
|
480
325
|
end
|
481
326
|
end
|
@@ -146,22 +146,64 @@ module Ione
|
|
146
146
|
describe '#connect' do
|
147
147
|
include_context 'running_reactor'
|
148
148
|
|
149
|
-
it 'calls the given block with
|
149
|
+
it 'calls the given block with a connection' do
|
150
150
|
connection = nil
|
151
151
|
reactor.start.value
|
152
152
|
reactor.connect('example.com', 9999, 5) { |c| connection = c }.value
|
153
|
-
connection.
|
153
|
+
connection.should_not be_nil
|
154
154
|
end
|
155
155
|
|
156
156
|
it 'returns a future that resolves to what the given block returns' do
|
157
157
|
reactor.start.value
|
158
|
-
reactor.connect('example.com', 9999, 5) { :foo }.value
|
158
|
+
x = reactor.connect('example.com', 9999, 5) { :foo }.value
|
159
|
+
x.should == :foo
|
159
160
|
end
|
160
161
|
|
161
162
|
it 'returns the connection when no block is given' do
|
162
163
|
reactor.start.value
|
163
164
|
reactor.connect('example.com', 9999, 5).value.should be_a(Connection)
|
164
165
|
end
|
166
|
+
|
167
|
+
it 'creates a connection and passes it to the selector as a readable' do
|
168
|
+
reactor.start.value
|
169
|
+
connection = reactor.connect('example.com', 9999, 5).value
|
170
|
+
await { selector.last_arguments[0].length > 1 }
|
171
|
+
selector.last_arguments[0].should include(connection)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#bind' do
|
176
|
+
include_context 'running_reactor'
|
177
|
+
|
178
|
+
let :port do
|
179
|
+
2**15 + rand(2**15)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'calls the given block with an acceptor' do
|
183
|
+
acceptor = nil
|
184
|
+
reactor.start.value
|
185
|
+
reactor.bind(ENV['SERVER_HOST'], port, 5) { |a| acceptor = a }.value
|
186
|
+
acceptor.should_not be_nil
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'returns a future that resolves to what the given block returns' do
|
190
|
+
reactor.start.value
|
191
|
+
x = reactor.bind(ENV['SERVER_HOST'], port, 5) { |acceptor| :foo }.value
|
192
|
+
x.should == :foo
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'returns the acceptor when no block is given' do
|
196
|
+
reactor.start.value
|
197
|
+
acceptor = reactor.bind(ENV['SERVER_HOST'], port, 5).value
|
198
|
+
acceptor.should be_an(Acceptor)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'creates an acceptor and passes it to the selector as a readable' do
|
202
|
+
reactor.start.value
|
203
|
+
acceptor = reactor.bind(ENV['SERVER_HOST'], port, 5).value
|
204
|
+
await { selector.last_arguments[0].length > 1 }
|
205
|
+
selector.last_arguments[0].should include(acceptor)
|
206
|
+
end
|
165
207
|
end
|
166
208
|
|
167
209
|
describe '#schedule_timer' do
|
@@ -357,6 +399,8 @@ end
|
|
357
399
|
|
358
400
|
module IoReactorSpec
|
359
401
|
class FakeSelector
|
402
|
+
attr_reader :last_arguments
|
403
|
+
|
360
404
|
def initialize
|
361
405
|
handler { [[], [], []] }
|
362
406
|
end
|
@@ -366,6 +410,7 @@ module IoReactorSpec
|
|
366
410
|
end
|
367
411
|
|
368
412
|
def select(*args)
|
413
|
+
@last_arguments = args
|
369
414
|
@body.call(*args)
|
370
415
|
end
|
371
416
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'ione/io/connection_common'
|
5
|
+
|
6
|
+
|
7
|
+
module Ione
|
8
|
+
module Io
|
9
|
+
describe ServerConnection do
|
10
|
+
let :handler do
|
11
|
+
described_class.new(socket, 'example.com', 4321, unblocker)
|
12
|
+
end
|
13
|
+
|
14
|
+
let :socket do
|
15
|
+
double(:socket, close: nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
let :unblocker do
|
19
|
+
double(:unblocker, unblock!: nil)
|
20
|
+
end
|
21
|
+
|
22
|
+
it_behaves_like 'a connection'
|
23
|
+
|
24
|
+
describe '#to_io' do
|
25
|
+
it 'returns the socket' do
|
26
|
+
handler.to_io.should equal(socket)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns nil when the socket is closed' do
|
30
|
+
socket.stub(:close)
|
31
|
+
handler.close
|
32
|
+
handler.to_io.should be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ione
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.1.0.pre0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Hultberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Reactive programming framework for Ruby, painless evented IO, futures
|
14
14
|
and an efficient byte buffer
|
@@ -24,14 +24,20 @@ files:
|
|
24
24
|
- lib/ione/byte_buffer.rb
|
25
25
|
- lib/ione/future.rb
|
26
26
|
- lib/ione/io.rb
|
27
|
+
- lib/ione/io/acceptor.rb
|
28
|
+
- lib/ione/io/base_connection.rb
|
27
29
|
- lib/ione/io/connection.rb
|
28
30
|
- lib/ione/io/io_reactor.rb
|
31
|
+
- lib/ione/io/server_connection.rb
|
29
32
|
- lib/ione/version.rb
|
30
33
|
- spec/integration/io_spec.rb
|
31
34
|
- spec/ione/byte_buffer_spec.rb
|
32
35
|
- spec/ione/future_spec.rb
|
36
|
+
- spec/ione/io/acceptor_spec.rb
|
37
|
+
- spec/ione/io/connection_common.rb
|
33
38
|
- spec/ione/io/connection_spec.rb
|
34
39
|
- spec/ione/io/io_reactor_spec.rb
|
40
|
+
- spec/ione/io/server_connection_spec.rb
|
35
41
|
- spec/spec_helper.rb
|
36
42
|
- spec/support/await_helper.rb
|
37
43
|
- spec/support/fake_server.rb
|
@@ -50,9 +56,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
56
|
version: 1.9.3
|
51
57
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
58
|
requirements:
|
53
|
-
- - '
|
59
|
+
- - '>'
|
54
60
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
61
|
+
version: 1.3.1
|
56
62
|
requirements: []
|
57
63
|
rubyforge_project:
|
58
64
|
rubygems_version: 2.2.1
|
@@ -63,8 +69,11 @@ test_files:
|
|
63
69
|
- spec/integration/io_spec.rb
|
64
70
|
- spec/ione/byte_buffer_spec.rb
|
65
71
|
- spec/ione/future_spec.rb
|
72
|
+
- spec/ione/io/acceptor_spec.rb
|
73
|
+
- spec/ione/io/connection_common.rb
|
66
74
|
- spec/ione/io/connection_spec.rb
|
67
75
|
- spec/ione/io/io_reactor_spec.rb
|
76
|
+
- spec/ione/io/server_connection_spec.rb
|
68
77
|
- spec/spec_helper.rb
|
69
78
|
- spec/support/await_helper.rb
|
70
79
|
- spec/support/fake_server.rb
|