cool.io 1.2.3-x86-mingw32 → 1.4.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +3 -3
  4. data/CHANGES.md +35 -0
  5. data/README.md +1 -3
  6. data/Rakefile +11 -13
  7. data/cool.io.gemspec +3 -2
  8. data/examples/callbacked_echo_server.rb +24 -0
  9. data/ext/cool.io/extconf.rb +8 -24
  10. data/ext/cool.io/loop.c +1 -1
  11. data/ext/iobuffer/iobuffer.c +2 -0
  12. data/ext/libev/Changes +123 -4
  13. data/ext/libev/LICENSE +2 -1
  14. data/ext/libev/README +8 -8
  15. data/ext/libev/ev.c +313 -144
  16. data/ext/libev/ev.h +18 -10
  17. data/ext/libev/ev_epoll.c +4 -1
  18. data/ext/libev/ev_kqueue.c +1 -1
  19. data/ext/libev/ev_select.c +3 -4
  20. data/ext/libev/ev_vars.h +3 -2
  21. data/ext/libev/ev_win32.c +1 -1
  22. data/ext/libev/win_select.patch +115 -0
  23. data/lib/cool.io.rb +6 -4
  24. data/lib/cool.io/dns_resolver.rb +4 -10
  25. data/lib/cool.io/dsl.rb +6 -2
  26. data/lib/cool.io/io.rb +36 -16
  27. data/lib/cool.io/loop.rb +3 -11
  28. data/lib/cool.io/meta.rb +2 -2
  29. data/lib/cool.io/version.rb +4 -2
  30. data/spec/async_watcher_spec.rb +5 -5
  31. data/spec/dns_spec.rb +11 -7
  32. data/spec/iobuffer_spec.rb +147 -0
  33. data/spec/spec_helper.rb +2 -2
  34. data/spec/stat_watcher_spec.rb +3 -3
  35. data/spec/tcp_server_spec.rb +98 -5
  36. data/spec/tcp_socket_spec.rb +185 -0
  37. data/spec/timer_watcher_spec.rb +23 -19
  38. data/spec/udp_socket_spec.rb +58 -0
  39. data/spec/unix_listener_spec.rb +7 -7
  40. data/spec/unix_server_spec.rb +7 -7
  41. metadata +83 -103
  42. data/examples/httpclient.rb +0 -38
  43. data/ext/http11_client/.gitignore +0 -5
  44. data/ext/http11_client/LICENSE +0 -31
  45. data/ext/http11_client/ext_help.h +0 -14
  46. data/ext/http11_client/extconf.rb +0 -6
  47. data/ext/http11_client/http11_client.c +0 -300
  48. data/ext/http11_client/http11_parser.c +0 -403
  49. data/ext/http11_client/http11_parser.h +0 -48
  50. data/ext/http11_client/http11_parser.rl +0 -173
  51. data/lib/cool.io/eventmachine.rb +0 -234
  52. data/lib/cool.io/http_client.rb +0 -427
@@ -15,17 +15,9 @@ end
15
15
 
16
16
  module Coolio
17
17
  class Loop
18
- # In Ruby 1.9 we want a Coolio::Loop per thread, but Ruby 1.8 is unithreaded
19
- if RUBY_VERSION >= "1.9.0"
20
- # Retrieve the default event loop for the current thread
21
- def self.default
22
- Thread.current._coolio_loop
23
- end
24
- else
25
- # Retrieve the default event loop
26
- def self.default
27
- @@_coolio_loop ||= Coolio::Loop.new
28
- end
18
+ # Retrieve the default event loop for the current thread
19
+ def self.default
20
+ Thread.current._coolio_loop
29
21
  end
30
22
 
31
23
  # Create a new Coolio::Loop
@@ -11,7 +11,7 @@ module Coolio
11
11
  # an event to occur before the current watcher can be used in earnest,
12
12
  # such as making an outgoing TCP connection.
13
13
  def watcher_delegate(proxy_var)
14
- %w{attach detach enable disable}.each do |method|
14
+ %w{attach attached? detach enable disable}.each do |method|
15
15
  module_eval <<-EOD
16
16
  def #{method}(*args)
17
17
  if defined? #{proxy_var} and #{proxy_var}
@@ -39,7 +39,7 @@ module Coolio
39
39
  end
40
40
 
41
41
  if defined? @#{method}_callback and @#{method}_callback
42
- instance_exec(*args, &@#{method}_callback)
42
+ @#{method}_callback.call(*args)
43
43
  end
44
44
  end
45
45
  EOD
@@ -1,5 +1,7 @@
1
1
  module Coolio
2
- VERSION = "1.2.3"
2
+ VERSION = "1.4.1"
3
3
 
4
- def self.version; VERSION; end
4
+ def self.version
5
+ VERSION
6
+ end
5
7
  end
@@ -2,7 +2,7 @@ require File.expand_path('../spec_helper', __FILE__)
2
2
  require 'tempfile'
3
3
  require 'fcntl'
4
4
 
5
- describe Cool.io::AsyncWatcher, :env => :win do
5
+ describe Cool.io::AsyncWatcher, :env => :exclude_win do
6
6
 
7
7
  it "does not signal on spurious wakeups" do
8
8
  aw = Cool.io::AsyncWatcher.new
@@ -30,7 +30,7 @@ describe Cool.io::AsyncWatcher, :env => :win do
30
30
  end
31
31
 
32
32
  # ensure children are ready
33
- nr_fork.times { rd.sysread(1).should == '.' }
33
+ nr_fork.times { expect(rd.sysread(1)).to eq('.') }
34
34
 
35
35
  # send our signals
36
36
  nr_signal.times { aw.signal }
@@ -41,15 +41,15 @@ describe Cool.io::AsyncWatcher, :env => :win do
41
41
  children.each do |pid|
42
42
  Process.kill(:TERM, pid)
43
43
  _, status = Process.waitpid2(pid)
44
- status.exitstatus.should == 0
44
+ expect(status.exitstatus).to eq(0)
45
45
  end
46
46
 
47
47
  # we should've written a line for every signal we sent
48
48
  lines = tmp.readlines
49
- lines.size.should == nr_signal
49
+ expect(lines.size).to eq(nr_signal)
50
50
 
51
51
  # theoretically a bad kernel scheduler could give us fewer...
52
- lines.sort.uniq.size.should == nr_fork
52
+ expect(lines.sort.uniq.size).to eq(nr_fork)
53
53
 
54
54
  tmp.close!
55
55
  end
@@ -22,18 +22,22 @@ describe "DNS" do
22
22
  end
23
23
 
24
24
  it "connects to valid domains" do
25
- ConnectorThingy.connect(VALID_DOMAIN, 80).attach(@loop)
26
-
27
- proc do
28
- @loop.run
29
- end.should raise_error(ItWorked)
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
30
34
  end
31
35
 
32
36
  it "fires on_resolve_failed for invalid domains" do
33
37
  ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
34
38
 
35
- proc do
39
+ expect do
36
40
  @loop.run
37
- end.should raise_error(WontResolve)
41
+ end.to raise_error(WontResolve)
38
42
  end
39
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
@@ -12,8 +12,8 @@ def unused_port
12
12
  end
13
13
 
14
14
  RSpec.configure do |c|
15
- if RUBY_PLATFORM =~ /mingw|win32/
15
+ if RUBY_PLATFORM =~ /mingw|mswin/
16
16
  $stderr.puts "Skip some specs on Windows"
17
- c.filter_run_excluding :env => :win
17
+ c.filter_run_excluding :env => :exclude_win
18
18
  end
19
19
  end
@@ -62,16 +62,16 @@ describe Cool.io::StatWatcher do
62
62
  end
63
63
 
64
64
  it "fire on_change when the file it is watching is modified" do
65
- watcher.accessed.should eql(true)
65
+ expect(watcher.accessed).to eq(true)
66
66
  end
67
67
 
68
68
  it "should pass previous and current file stat info given a stat watcher" do
69
- watcher.previous.ino.should eql(watcher.current.ino)
69
+ expect(watcher.previous.ino).to eq(watcher.current.ino)
70
70
  end
71
71
 
72
72
  it "should raise when the handler does not take 2 parameters" do
73
73
  class MyStatWatcher < Cool.io::StatWatcher; def on_change; end; end
74
- lambda { watcher.accessed }.should raise_error(ArgumentError)
74
+ expect { watcher.accessed }.to raise_error(ArgumentError)
75
75
  end
76
76
 
77
77
  end
@@ -106,14 +106,14 @@ ensure
106
106
  end
107
107
 
108
108
  # This test should work on Windows
109
- describe Coolio::TCPServer, :env => :win do
109
+ describe Coolio::TCPServer do
110
110
 
111
111
  it '#run' do
112
- test_run("hello").should == "hello"
112
+ expect(test_run("hello")).to eq("hello")
113
113
  end
114
114
 
115
115
  it '#run_once' do
116
- test_run_once("hello").should == "hello"
116
+ expect(test_run_once("hello")).to eq("hello")
117
117
  end
118
118
 
119
119
  it '#run_once(timeout)' do
@@ -125,8 +125,101 @@ describe Coolio::TCPServer, :env => :win do
125
125
  end
126
126
 
127
127
  it '#run(timeout)' do
128
- test_run_timeout("hello").should == "hello"
128
+ expect(test_run_timeout("hello")).to eq("hello")
129
129
  end
130
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
131
225
  end
132
-
@@ -0,0 +1,185 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Coolio::TCPSocket do
4
+ let :loop do
5
+ Coolio::Loop.new
6
+ end
7
+
8
+ before :each do
9
+ @echo = TCPServer.new("127.0.0.1", 0)
10
+ @host = @echo.addr[3]
11
+ @port = @echo.addr[1]
12
+ @running = true
13
+ @echo_thread = Thread.new do
14
+ socks = [@echo]
15
+ begin
16
+ serv socks
17
+ ensure
18
+ socks.each do |s|
19
+ s.close
20
+ end
21
+ end
22
+ Thread.pass
23
+ end
24
+ end
25
+
26
+ def serv(socks)
27
+ while @running
28
+ selected = select(socks, [], [], 0.1)
29
+ next if selected.nil?
30
+ selected[0].each do |s|
31
+ if s == @echo
32
+ socks.push s.accept
33
+ next
34
+ end
35
+ begin
36
+ unless s.eof?
37
+ s.write(s.read_nonblock 1)
38
+ end
39
+ rescue SystemCallError, EOFError, IOError, SocketError
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def shutdown
46
+ if @running
47
+ @running = false
48
+ @echo_thread.join
49
+ end
50
+ end
51
+
52
+ after :each do
53
+ shutdown
54
+ end
55
+
56
+ context "#close" do
57
+ it "detaches all watchers on #close before loop#run" do
58
+ client = Coolio::TCPSocket.connect(@host, @port)
59
+ loop.attach client
60
+ client.close
61
+ expect(loop.watchers.size).to eq 0
62
+ end
63
+ end
64
+
65
+ context "#on_connect" do
66
+ class OnConnect < Cool.io::TCPSocket
67
+ attr :connected
68
+ def on_connect
69
+ @connected = true
70
+ end
71
+ end
72
+
73
+ it "connected client called on_connect" do
74
+ begin
75
+ c = OnConnect.connect(@host, @port)
76
+ loop.attach c
77
+ loop.run_once
78
+ expect(c.connected).to eq true
79
+ ensure
80
+ c.close
81
+ end
82
+ end
83
+ end
84
+
85
+ context "#on_connect_failed" do
86
+ class OnConnectFailed < Cool.io::TCPSocket
87
+ attr :connect_failed
88
+ def on_connect_failed
89
+ @connect_failed = true
90
+ end
91
+ end
92
+
93
+ it "try to connect dead host" do
94
+ serv = TCPServer.new(0)
95
+ dead_host = serv.addr[3]
96
+ dead_port = serv.addr[1]
97
+ serv.close
98
+
99
+ c = OnConnectFailed.connect(dead_host, dead_port)
100
+ loop.attach c
101
+ loop.run_once # on_connect_failed
102
+ expect(c.connect_failed).to eq true
103
+ end
104
+ end
105
+
106
+ context "#on_close" do
107
+ class Closed < StandardError; end
108
+ class OnClose < Cool.io::TCPSocket
109
+ def on_close
110
+ raise Closed
111
+ end
112
+ end
113
+
114
+ let :client do
115
+ OnClose.connect(@host, @port)
116
+ end
117
+
118
+ before :each do
119
+ loop.attach client
120
+ loop.run_once # on_connect
121
+ client.write "0"
122
+ end
123
+
124
+ it "disconnect from client" do
125
+ expect { client.close }.to raise_error(Closed)
126
+ end
127
+
128
+ it "disconnect from server" do
129
+ shutdown
130
+ expect { loop.run }.to raise_error(Closed)
131
+ end
132
+ end
133
+
134
+ context "#on_read" do
135
+ class Finished < StandardError; end
136
+ class OnRead < Cool.io::TCPSocket
137
+ attr :read_data, :times
138
+ def on_connect
139
+ @read_data = ""
140
+ @times = 0
141
+ end
142
+ def on_read(data)
143
+ @read_data += data
144
+ @times += 1
145
+ if @times < 5
146
+ write "#{@times}"
147
+ else
148
+ close
149
+ raise Finished
150
+ end
151
+ end
152
+ end
153
+
154
+ it "receive 5 times" do
155
+ c = OnRead.connect(@host, @port)
156
+ loop.attach c
157
+ loop.run_once # on_connect
158
+ c.write "0"
159
+ expect { loop.run }.to raise_error(Finished)
160
+
161
+ expect(c.times).to eq 5
162
+ expect(c.read_data).to eq "01234"
163
+ end
164
+ end
165
+
166
+ context "#on_write_complete" do
167
+ class WriteComplete < StandardError; end
168
+ class OnWriteComplete < Cool.io::TCPSocket
169
+ attr :called
170
+ def on_write_complete
171
+ @called = true
172
+ close
173
+ raise WriteComplete
174
+ end
175
+ end
176
+
177
+ it "on_write_complete is called" do
178
+ c = OnWriteComplete.connect(@host, @port)
179
+ loop.attach c
180
+ loop.run_once # on_connect
181
+ c.write "aaa"
182
+ expect { loop.run }.to raise_error(WriteComplete)
183
+ end
184
+ end
185
+ end