cool.io 1.4.1-x64-mingw32
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 +7 -0
- data/.gitignore +29 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/CHANGES.md +229 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +166 -0
- data/Rakefile +79 -0
- data/cool.io.gemspec +29 -0
- data/examples/callbacked_echo_server.rb +24 -0
- data/examples/dslified_echo_client.rb +34 -0
- data/examples/dslified_echo_server.rb +24 -0
- data/examples/echo_client.rb +38 -0
- data/examples/echo_server.rb +27 -0
- data/examples/google.rb +9 -0
- data/ext/cool.io/.gitignore +5 -0
- data/ext/cool.io/cool.io.h +59 -0
- data/ext/cool.io/cool.io_ext.c +25 -0
- data/ext/cool.io/ev_wrap.h +10 -0
- data/ext/cool.io/extconf.rb +61 -0
- data/ext/cool.io/iowatcher.c +189 -0
- data/ext/cool.io/libev.c +8 -0
- data/ext/cool.io/loop.c +261 -0
- data/ext/cool.io/stat_watcher.c +269 -0
- data/ext/cool.io/timer_watcher.c +219 -0
- data/ext/cool.io/utils.c +122 -0
- data/ext/cool.io/watcher.c +264 -0
- data/ext/cool.io/watcher.h +71 -0
- data/ext/iobuffer/extconf.rb +9 -0
- data/ext/iobuffer/iobuffer.c +767 -0
- data/ext/libev/Changes +507 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +58 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5054 -0
- data/ext/libev/ev.h +853 -0
- data/ext/libev/ev_epoll.c +282 -0
- data/ext/libev/ev_kqueue.c +214 -0
- data/ext/libev/ev_poll.c +148 -0
- data/ext/libev/ev_port.c +185 -0
- data/ext/libev/ev_select.c +362 -0
- data/ext/libev/ev_vars.h +204 -0
- data/ext/libev/ev_win32.c +163 -0
- data/ext/libev/ev_wrap.h +200 -0
- data/ext/libev/ruby_gil.patch +97 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/ext/libev/win_select.patch +115 -0
- data/lib/.gitignore +2 -0
- data/lib/cool.io.rb +34 -0
- data/lib/cool.io/async_watcher.rb +43 -0
- data/lib/cool.io/custom_require.rb +9 -0
- data/lib/cool.io/dns_resolver.rb +219 -0
- data/lib/cool.io/dsl.rb +139 -0
- data/lib/cool.io/io.rb +194 -0
- data/lib/cool.io/iowatcher.rb +17 -0
- data/lib/cool.io/listener.rb +99 -0
- data/lib/cool.io/loop.rb +122 -0
- data/lib/cool.io/meta.rb +49 -0
- data/lib/cool.io/server.rb +75 -0
- data/lib/cool.io/socket.rb +230 -0
- data/lib/cool.io/timer_watcher.rb +17 -0
- data/lib/cool.io/version.rb +7 -0
- data/lib/coolio.rb +2 -0
- data/spec/async_watcher_spec.rb +57 -0
- data/spec/dns_spec.rb +43 -0
- data/spec/iobuffer_spec.rb +147 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/stat_watcher_spec.rb +77 -0
- data/spec/tcp_server_spec.rb +225 -0
- data/spec/tcp_socket_spec.rb +185 -0
- data/spec/timer_watcher_spec.rb +59 -0
- data/spec/udp_socket_spec.rb +58 -0
- data/spec/unix_listener_spec.rb +25 -0
- data/spec/unix_server_spec.rb +27 -0
- metadata +182 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C)2007 Tony Arcieri
|
3
|
+
# You can redistribute this under the terms of the Ruby license
|
4
|
+
# See file LICENSE for details
|
5
|
+
#++
|
6
|
+
|
7
|
+
module Coolio
|
8
|
+
class TimerWatcher
|
9
|
+
# The actual implementation of this class resides in the C extension
|
10
|
+
# Here we metaprogram proper event_callbacks for the callback methods
|
11
|
+
# These can take a block and store it to be called when the event
|
12
|
+
# is actually fired.
|
13
|
+
|
14
|
+
extend Meta
|
15
|
+
event_callback :on_timer
|
16
|
+
end
|
17
|
+
end
|
data/lib/coolio.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'tempfile'
|
3
|
+
require 'fcntl'
|
4
|
+
|
5
|
+
describe Cool.io::AsyncWatcher, :env => :exclude_win do
|
6
|
+
|
7
|
+
it "does not signal on spurious wakeups" do
|
8
|
+
aw = Cool.io::AsyncWatcher.new
|
9
|
+
tmp = Tempfile.new('coolio_async_watcher_test')
|
10
|
+
nr_fork = 2 # must be at least two for spurious wakeups
|
11
|
+
|
12
|
+
# We have aetter chance of failing if this overflows the pipe buffer
|
13
|
+
# which POSIX requires >= 512 bytes, Linux 2.6 uses 4096 bytes
|
14
|
+
nr_signal = 4096 * 4
|
15
|
+
|
16
|
+
append = File.open(tmp.path, "ab")
|
17
|
+
append.sync = true
|
18
|
+
rd, wr = ::IO.pipe
|
19
|
+
|
20
|
+
aw.on_signal { append.syswrite("#$$\n") }
|
21
|
+
children = nr_fork.times.map do
|
22
|
+
fork do
|
23
|
+
trap(:TERM) { exit!(0) }
|
24
|
+
rloop = Cool.io::Loop.default
|
25
|
+
aw.attach(rloop)
|
26
|
+
wr.write '.' # signal to master that we're ready
|
27
|
+
rloop.run
|
28
|
+
exit!(1) # should not get here
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# ensure children are ready
|
33
|
+
nr_fork.times { expect(rd.sysread(1)).to eq('.') }
|
34
|
+
|
35
|
+
# send our signals
|
36
|
+
nr_signal.times { aw.signal }
|
37
|
+
|
38
|
+
# wait for the pipe buffer to be consumed by the children
|
39
|
+
sleep 1 while tmp.stat.ctime >= (Time.now - 4)
|
40
|
+
|
41
|
+
children.each do |pid|
|
42
|
+
Process.kill(:TERM, pid)
|
43
|
+
_, status = Process.waitpid2(pid)
|
44
|
+
expect(status.exitstatus).to eq(0)
|
45
|
+
end
|
46
|
+
|
47
|
+
# we should've written a line for every signal we sent
|
48
|
+
lines = tmp.readlines
|
49
|
+
expect(lines.size).to eq(nr_signal)
|
50
|
+
|
51
|
+
# theoretically a bad kernel scheduler could give us fewer...
|
52
|
+
expect(lines.sort.uniq.size).to eq(nr_fork)
|
53
|
+
|
54
|
+
tmp.close!
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/spec/dns_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
VALID_DOMAIN = "google.com"
|
4
|
+
INVALID_DOMAIN = "gibidigibigididibitidibigitibidigitidididi.com"
|
5
|
+
|
6
|
+
class ItWorked < StandardError; end
|
7
|
+
class WontResolve < StandardError; end
|
8
|
+
|
9
|
+
class ConnectorThingy < Cool.io::TCPSocket
|
10
|
+
def on_connect
|
11
|
+
raise ItWorked
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_resolve_failed
|
15
|
+
raise WontResolve
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "DNS" do
|
20
|
+
before :each do
|
21
|
+
@loop = Cool.io::Loop.new
|
22
|
+
end
|
23
|
+
|
24
|
+
it "connects to valid domains" do
|
25
|
+
begin
|
26
|
+
c = ConnectorThingy.connect(VALID_DOMAIN, 80).attach(@loop)
|
27
|
+
|
28
|
+
expect do
|
29
|
+
@loop.run
|
30
|
+
end.to raise_error(ItWorked)
|
31
|
+
ensure
|
32
|
+
c.close
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "fires on_resolve_failed for invalid domains" do
|
37
|
+
ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
|
38
|
+
|
39
|
+
expect do
|
40
|
+
@loop.run
|
41
|
+
end.to raise_error(WontResolve)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
|
4
|
+
describe IO::Buffer do
|
5
|
+
|
6
|
+
let :buffer do
|
7
|
+
IO::Buffer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "provides a subset of the methods available in Strings" do
|
11
|
+
expect(buffer << "foo").to eq "foo"
|
12
|
+
expect(buffer << "bar").to eq "bar"
|
13
|
+
expect(buffer.to_str).to eq "foobar"
|
14
|
+
expect(buffer.to_str).to eq "foobar"
|
15
|
+
expect(buffer.size).to eq 6
|
16
|
+
end
|
17
|
+
|
18
|
+
it "provides append and prepend" do
|
19
|
+
expect(buffer.append "bar").to eq "bar"
|
20
|
+
expect(buffer.prepend "foo").to eq "foo"
|
21
|
+
expect(buffer.append "baz").to eq "baz"
|
22
|
+
expect(buffer.to_str).to eq "foobarbaz"
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#read" do
|
26
|
+
it "can be used to retrieve the contents of a buffer" do
|
27
|
+
expect(buffer << "foo").to eq "foo"
|
28
|
+
expect(buffer.read 2).to eq "fo"
|
29
|
+
expect(buffer << "bar").to eq "bar"
|
30
|
+
expect(buffer.read 2).to eq "ob"
|
31
|
+
expect(buffer << "baz").to eq "baz"
|
32
|
+
expect(buffer.read 3).to eq "arb"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "provides methods for performing non-blocking I/O" do
|
37
|
+
require "tempfile"
|
38
|
+
|
39
|
+
context "#read_from" do
|
40
|
+
context "using local file", :env => :exclude_win do
|
41
|
+
let :tmp do
|
42
|
+
t = Tempfile.open "read_from"
|
43
|
+
t << "foobar"
|
44
|
+
t.rewind
|
45
|
+
t
|
46
|
+
end
|
47
|
+
|
48
|
+
it "will read as much data as possible" do
|
49
|
+
expect(buffer.read_from tmp).to eq 6
|
50
|
+
expect(buffer.to_str).to eq "foobar"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "using udp socket" do
|
55
|
+
before :each do
|
56
|
+
@receiver = UDPSocket.open
|
57
|
+
@receiver.bind nil, 0
|
58
|
+
|
59
|
+
@sender = UDPSocket.open
|
60
|
+
@sender.connect "localhost", @receiver.addr[1]
|
61
|
+
end
|
62
|
+
after :each do
|
63
|
+
@receiver.close
|
64
|
+
@sender.close
|
65
|
+
end
|
66
|
+
|
67
|
+
it "will read as much data as possible" do
|
68
|
+
select [], [@sender]
|
69
|
+
@sender.send "foo", 0
|
70
|
+
select [@receiver]
|
71
|
+
expect(buffer.read_from @receiver).to eq 3
|
72
|
+
expect(buffer.to_str).to eq "foo"
|
73
|
+
|
74
|
+
select [], [@sender]
|
75
|
+
@sender.send "barbaz", 0
|
76
|
+
select [@receiver]
|
77
|
+
expect(buffer.read_from @receiver).to eq 6
|
78
|
+
expect(buffer.to_str).to eq "foobarbaz"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "#write_to" do
|
84
|
+
context "using local file", :env => :exclude_win do
|
85
|
+
let :tmp do
|
86
|
+
Tempfile.open "write_to"
|
87
|
+
end
|
88
|
+
it "writes the contents of the buffer" do
|
89
|
+
buffer << "foo"
|
90
|
+
expect(buffer.write_to tmp).to eq 3
|
91
|
+
tmp.rewind
|
92
|
+
expect(tmp.read 3).to eq "foo"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "using udp socket" do
|
97
|
+
before :each do
|
98
|
+
@receiver = UDPSocket.open
|
99
|
+
@receiver.bind nil, 0
|
100
|
+
|
101
|
+
@sender = UDPSocket.open
|
102
|
+
@sender.connect "localhost", @receiver.addr[1]
|
103
|
+
end
|
104
|
+
after :each do
|
105
|
+
@receiver.close
|
106
|
+
@sender.close
|
107
|
+
end
|
108
|
+
|
109
|
+
it "will read as much data as possible" do
|
110
|
+
buffer << "foo"
|
111
|
+
select [], [@sender]
|
112
|
+
expect(buffer.write_to @sender).to eq 3
|
113
|
+
select [@receiver]
|
114
|
+
expect(@receiver.recvfrom_nonblock(3)[0]).to eq "foo"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "#clear" do
|
121
|
+
it "clear all data" do
|
122
|
+
buffer << "foo"
|
123
|
+
expect(buffer.size).to eq 3
|
124
|
+
expect(buffer.empty?).to eq false
|
125
|
+
buffer.clear
|
126
|
+
expect(buffer.size).to eq 0
|
127
|
+
expect(buffer.empty?).to eq true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "#read_frame" do
|
132
|
+
it "Read up to and including the given frame marker" do
|
133
|
+
buffer << "foo\nbarbaz"
|
134
|
+
data = ""
|
135
|
+
expect(buffer.read_frame data, "\n".ord).to eq true
|
136
|
+
expect(buffer.empty?).to eq false
|
137
|
+
expect(data).to eq "foo\n"
|
138
|
+
expect(buffer.to_str).to eq "barbaz"
|
139
|
+
|
140
|
+
expect(buffer.read_frame data, "\n".ord).to eq false
|
141
|
+
expect(buffer.empty?).to eq true
|
142
|
+
expect(data).to eq "foo\nbarbaz"
|
143
|
+
expect(buffer.to_str).to eq ""
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
require 'cool.io'
|
6
|
+
|
7
|
+
def unused_port
|
8
|
+
s = TCPServer.open(0)
|
9
|
+
port = s.addr[1]
|
10
|
+
s.close
|
11
|
+
port
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.configure do |c|
|
15
|
+
if RUBY_PLATFORM =~ /mingw|mswin/
|
16
|
+
$stderr.puts "Skip some specs on Windows"
|
17
|
+
c.filter_run_excluding :env => :exclude_win
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
TEMP_FILE_PATH = "./test.txt"
|
4
|
+
|
5
|
+
INTERVAL = 0.010
|
6
|
+
|
7
|
+
class MyStatWatcher < Cool.io::StatWatcher
|
8
|
+
attr_accessor :accessed, :previous, :current
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
super path, INTERVAL
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_change(previous, current)
|
15
|
+
self.accessed = true
|
16
|
+
self.previous = previous
|
17
|
+
self.current = current
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_with_file_change(path)
|
22
|
+
reactor = Cool.io::Loop.new
|
23
|
+
|
24
|
+
sw = MyStatWatcher.new(path)
|
25
|
+
sw.attach(reactor)
|
26
|
+
|
27
|
+
tw = Cool.io::TimerWatcher.new(INTERVAL, true)
|
28
|
+
tw.on_timer do
|
29
|
+
reactor.stop if sw.accessed
|
30
|
+
write_file(path)
|
31
|
+
end
|
32
|
+
tw.attach(reactor)
|
33
|
+
|
34
|
+
reactor.run
|
35
|
+
|
36
|
+
tw.detach
|
37
|
+
sw.detach
|
38
|
+
|
39
|
+
sw
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_file(path)
|
43
|
+
File.open(path, "w+") { |f| f.write(rand.to_s) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_file(path)
|
47
|
+
File.delete(TEMP_FILE_PATH)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe Cool.io::StatWatcher do
|
51
|
+
|
52
|
+
let :watcher do
|
53
|
+
run_with_file_change(TEMP_FILE_PATH)
|
54
|
+
end
|
55
|
+
|
56
|
+
before :each do
|
57
|
+
write_file(TEMP_FILE_PATH)
|
58
|
+
end
|
59
|
+
|
60
|
+
after :each do
|
61
|
+
delete_file(TEMP_FILE_PATH)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "fire on_change when the file it is watching is modified" do
|
65
|
+
expect(watcher.accessed).to eq(true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should pass previous and current file stat info given a stat watcher" do
|
69
|
+
expect(watcher.previous.ino).to eq(watcher.current.ino)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise when the handler does not take 2 parameters" do
|
73
|
+
class MyStatWatcher < Cool.io::StatWatcher; def on_change; end; end
|
74
|
+
expect { watcher.accessed }.to raise_error(ArgumentError)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
TIMEOUT = 0.010
|
4
|
+
HOST = '127.0.0.1'
|
5
|
+
PORT = unused_port
|
6
|
+
|
7
|
+
def send_data(data)
|
8
|
+
io = TCPSocket.new('127.0.0.1', PORT)
|
9
|
+
begin
|
10
|
+
io.write data
|
11
|
+
ensure
|
12
|
+
io.close
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class MyConnection < Coolio::Socket
|
17
|
+
attr_accessor :data, :connected, :closed
|
18
|
+
|
19
|
+
def initialize(io, on_message)
|
20
|
+
super(io)
|
21
|
+
@on_message = on_message
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_connect
|
25
|
+
@connected = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_close
|
29
|
+
@closed = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_read(data)
|
33
|
+
@on_message.call(data)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@data = ""
|
38
|
+
def on_message(data)
|
39
|
+
@data = data
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_run(data = nil)
|
43
|
+
reactor = Coolio::Loop.new
|
44
|
+
server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
|
45
|
+
reactor.attach(server)
|
46
|
+
thread = Thread.new { reactor.run }
|
47
|
+
send_data(data) if data
|
48
|
+
sleep TIMEOUT
|
49
|
+
reactor.stop
|
50
|
+
server.detach
|
51
|
+
send_data('') # to leave from blocking loop
|
52
|
+
thread.join
|
53
|
+
@data
|
54
|
+
ensure
|
55
|
+
server.close
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_run_once(data = nil)
|
59
|
+
reactor = Coolio::Loop.new
|
60
|
+
server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
|
61
|
+
reactor.attach(server)
|
62
|
+
thread = Thread.new do
|
63
|
+
reactor.run_once # on_connect
|
64
|
+
reactor.run_once # on_read
|
65
|
+
end
|
66
|
+
send_data(data) if data
|
67
|
+
thread.join
|
68
|
+
server.detach
|
69
|
+
@data
|
70
|
+
ensure
|
71
|
+
server.close
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_run_once_timeout(timeout = TIMEOUT)
|
75
|
+
reactor = Coolio::Loop.new
|
76
|
+
server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
|
77
|
+
reactor.attach(server)
|
78
|
+
running = true
|
79
|
+
thread = Thread.new { reactor.run_once(timeout) }
|
80
|
+
sleep timeout
|
81
|
+
server.detach
|
82
|
+
thread.join
|
83
|
+
@data
|
84
|
+
ensure
|
85
|
+
server.close
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_run_timeout(data = nil, timeout = TIMEOUT)
|
89
|
+
reactor = Coolio::Loop.new
|
90
|
+
server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
|
91
|
+
reactor.attach(server)
|
92
|
+
running = true
|
93
|
+
thread = Thread.new do
|
94
|
+
while running and reactor.has_active_watchers?
|
95
|
+
reactor.run_once(timeout)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
send_data(data) if data
|
99
|
+
sleep timeout
|
100
|
+
server.detach
|
101
|
+
running = false # another send is not required
|
102
|
+
thread.join
|
103
|
+
@data
|
104
|
+
ensure
|
105
|
+
server.close
|
106
|
+
end
|
107
|
+
|
108
|
+
# This test should work on Windows
|
109
|
+
describe Coolio::TCPServer do
|
110
|
+
|
111
|
+
it '#run' do
|
112
|
+
expect(test_run("hello")).to eq("hello")
|
113
|
+
end
|
114
|
+
|
115
|
+
it '#run_once' do
|
116
|
+
expect(test_run_once("hello")).to eq("hello")
|
117
|
+
end
|
118
|
+
|
119
|
+
it '#run_once(timeout)' do
|
120
|
+
test_run_once_timeout # should not block
|
121
|
+
end
|
122
|
+
|
123
|
+
it '#run_once(-timeout)' do
|
124
|
+
expect { test_run_once_timeout(-0.1) }.to raise_error(ArgumentError)
|
125
|
+
end
|
126
|
+
|
127
|
+
it '#run(timeout)' do
|
128
|
+
expect(test_run_timeout("hello")).to eq("hello")
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "functionaltest" do
|
132
|
+
let :loop do
|
133
|
+
Coolio::Loop.new
|
134
|
+
end
|
135
|
+
|
136
|
+
let :port do
|
137
|
+
unused_port
|
138
|
+
end
|
139
|
+
|
140
|
+
context "#on_connect" do
|
141
|
+
class ServerOnConnect < Coolio::Socket
|
142
|
+
def initialize(io, cb)
|
143
|
+
super(io)
|
144
|
+
@cb = cb
|
145
|
+
end
|
146
|
+
def on_connect
|
147
|
+
@cb.call
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "connected socket called on_connect" do
|
152
|
+
begin
|
153
|
+
connected = false
|
154
|
+
server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { connected = true })
|
155
|
+
loop.attach server
|
156
|
+
s = TCPSocket.open("localhost", port)
|
157
|
+
loop.run_once
|
158
|
+
s.close
|
159
|
+
expect(connected).to eq true
|
160
|
+
ensure
|
161
|
+
server.detach
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "#on_close" do
|
167
|
+
class ServerOnClose < Coolio::Socket
|
168
|
+
def initialize(io, cb)
|
169
|
+
super(io)
|
170
|
+
@cb = cb
|
171
|
+
end
|
172
|
+
def on_close
|
173
|
+
@cb.call
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "closed socket called on_close" do
|
178
|
+
begin
|
179
|
+
closed = false
|
180
|
+
server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { closed = true })
|
181
|
+
loop.attach server
|
182
|
+
s = TCPSocket.open("localhost", port)
|
183
|
+
loop.run_once
|
184
|
+
s.close
|
185
|
+
loop.run_once
|
186
|
+
expect(closed).to eq true
|
187
|
+
ensure
|
188
|
+
server.detach
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "#on_read" do
|
194
|
+
class Echo < Coolio::Socket
|
195
|
+
def initialize(io, cb)
|
196
|
+
super(io)
|
197
|
+
@cb = cb
|
198
|
+
end
|
199
|
+
def on_read(data)
|
200
|
+
@cb.call data
|
201
|
+
size = write(data + "fff")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "server socket received data" do
|
206
|
+
begin
|
207
|
+
data = "aaa"
|
208
|
+
server = Cool.io::TCPServer.new("localhost", port, Echo, proc { |d| data = d })
|
209
|
+
loop.attach server
|
210
|
+
thread = Thread.new { loop.run }
|
211
|
+
s = TCPSocket.open("localhost", port)
|
212
|
+
s.write "zzz"
|
213
|
+
sleep 0.1
|
214
|
+
expect(data).to eq "zzz"
|
215
|
+
expect(s.read 6).to eq "zzzfff"
|
216
|
+
ensure
|
217
|
+
s.close
|
218
|
+
loop.stop
|
219
|
+
server.detach
|
220
|
+
thread.join
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|