cool.io 1.3.0 → 1.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 94010c895806ae23b7ac77b906979c31937463f3
4
- data.tar.gz: a73e0f356ee9764a3dd8a3a56c29a187a8ab0693
3
+ metadata.gz: 69788383b1d7d04b499aed3a4c7430bde6af09cb
4
+ data.tar.gz: a5bd943271281ef7e72c886cf07b33ea98a7ca0a
5
5
  SHA512:
6
- metadata.gz: e48dd879dd3a8c76408cbf8569e7fefbf329360cc5b7e95a8f1aeaab2ac647cc9e89d4840fa6b8c86c9eb3cad372f57169303911592914751de1cc94e258569e
7
- data.tar.gz: 1408f73b5abfcf72c6ca5c153aa9f1b72ac7bc1ed549235435c839883c0c8aa00ea375495a7e450f0803a8f75dc8b3212bfa9973509cc3003b27ddbe46d59451
6
+ metadata.gz: 02ff98d0fa4b9b90ed484e5db28c88adcbf4dde3e27ee436282b5a2aab3ea0afe2cfe88d79b10cb643c717e1af0e93736b914112b42061ac640f4ae07a001e84
7
+ data.tar.gz: ec26d9e2759c5b999f82dbf8dcfac2f407aa571bf941df4b0a6761c00787b793d0574429b0be6887316cbe861c7eef661300c50d7a662f69f87618f7be2717e9
data/.gitignore CHANGED
@@ -24,3 +24,6 @@ tmp
24
24
 
25
25
  ## PROJECT::SPECIFIC
26
26
  conftest.dSYM
27
+
28
+ *.lock
29
+ .ruby-version
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ 1.3.1
2
+ -----
3
+
4
+ * Fix several bugs for JRuby support enhancement
5
+ * Fix deadlock bug on Windows environment
6
+ * Use RSpec3
7
+
1
8
  1.3.0
2
9
  -----
3
10
 
@@ -4,25 +4,11 @@ libs = []
4
4
 
5
5
  $defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
6
6
 
7
- if have_func('rb_thread_blocking_region')
8
- $defs << '-DHAVE_RB_THREAD_BLOCKING_REGION'
9
- end
10
-
11
- if have_func('rb_thread_call_without_gvl')
12
- $defs << '-DHAVE_RB_THEREAD_CALL_WITHOUT_GVL'
13
- end
14
-
15
- if have_func('rb_thread_alone')
16
- $defs << '-DHAVE_RB_THREAD_ALONE'
17
- end
18
-
19
- if have_func('rb_str_set_len')
20
- $defs << '-DHAVE_RB_STR_SET_LEN'
21
- end
22
-
23
- if have_library('rt', 'clock_gettime')
24
- libs << "-lrt"
25
- end
7
+ have_func('rb_thread_blocking_region')
8
+ have_func('rb_thread_call_without_gvl')
9
+ have_func('rb_thread_alone')
10
+ have_func('rb_str_set_len')
11
+ have_library('rt', 'clock_gettime')
26
12
 
27
13
  if have_header('sys/select.h')
28
14
  $defs << '-DEV_USE_SELECT'
@@ -44,9 +30,7 @@ if have_header('port.h')
44
30
  $defs << '-DEV_USE_PORT'
45
31
  end
46
32
 
47
- if have_header('sys/resource.h')
48
- $defs << '-DHAVE_SYS_RESOURCE_H'
49
- end
33
+ have_header('sys/resource.h')
50
34
 
51
35
  # ncpu detection specifics
52
36
  case RUBY_PLATFORM
@@ -64,14 +48,14 @@ dir_config('cool.io_ext')
64
48
  create_makefile('cool.io_ext')
65
49
 
66
50
  # win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version. See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
67
- if RUBY_PLATFORM =~ /mingw|win32/
51
+ if RUBY_PLATFORM =~ /mingw|mswin/
68
52
  makefile_contents = File.read 'Makefile'
69
53
 
70
54
  # "Init_cool could not be found" when loading cool.io.so.
71
55
  # I'm not sure why this is needed. But this line causes "1114 A dynamic link library (DLL) initialization routine failed." So I commented out this line.
72
56
  #makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
73
57
 
74
- makefile_contents.gsub! 'LIBS = $(LIBRUBYARG_SHARED)', 'LIBS = -lws2_32 $(LIBRUBYARG_SHARED)'
58
+ makefile_contents.gsub! /LIBS = (.*) (\S*ws2_32\S*)/i, 'LIBS = \\2 \\1'
75
59
  File.open('Makefile', 'w') { |f| f.write makefile_contents }
76
60
  end
77
61
 
data/ext/cool.io/loop.c CHANGED
@@ -81,7 +81,7 @@ static void Coolio_Loop_free(struct Coolio_Loop *loop)
81
81
 
82
82
  static VALUE Coolio_Loop_initialize(VALUE self)
83
83
  {
84
- Coolio_Loop_ev_loop_new(self, INT2NUM(0));
84
+ return Coolio_Loop_ev_loop_new(self, INT2NUM(0));
85
85
  }
86
86
 
87
87
  /* Wrapper for populating a Coolio_Loop struct with a new event loop */
@@ -11,7 +11,9 @@
11
11
 
12
12
  #include <string.h>
13
13
  #include <time.h>
14
+ #ifndef _MSC_VER
14
15
  #include <unistd.h>
16
+ #endif
15
17
  #include <errno.h>
16
18
 
17
19
  /* 1 GiB maximum buffer size */
data/ext/libev/ev.c CHANGED
@@ -1153,8 +1153,8 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () ==
1153
1153
  int m = x & 0x3ff;
1154
1154
  float r;
1155
1155
 
1156
- if (!e ) r = ldexpf (m , -24);
1157
- else if (e != 31) r = ldexpf (m + 0x400, e - 25);
1156
+ if (!e ) r = ldexpf ((float)m , -24);
1157
+ else if (e != 31) r = ldexpf ((float)m + 0x400, e - 25);
1158
1158
  else if (m ) r = ECB_NAN;
1159
1159
  else r = ECB_INFINITY;
1160
1160
 
@@ -2263,7 +2263,7 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
2263
2263
  #ifdef _WIN32
2264
2264
  WSABUF buf;
2265
2265
  DWORD sent;
2266
- buf.buf = &buf;
2266
+ buf.buf = (CHAR*)&buf;
2267
2267
  buf.len = 1;
2268
2268
  WSASend (EV_FD_TO_WIN32_HANDLE (evpipe [1]), &buf, 1, &sent, 0, 0, 0);
2269
2269
  #else
@@ -3343,6 +3343,7 @@ VALUE ev_backend_poll(void **args)
3343
3343
  struct ev_loop *loop = (struct ev_loop *)args[0];
3344
3344
  ev_tstamp waittime = *(ev_tstamp *)args[1];
3345
3345
  backend_poll (EV_A_ waittime);
3346
+ return Qnil;
3346
3347
  }
3347
3348
  #endif
3348
3349
  /* ######################################## */
@@ -106,6 +106,7 @@ if (__i == ((fd_set *)(set))->fd_count) {\
106
106
  } while(0)
107
107
  #define EV_WIN_FD_ZERO(set) (((fd_set *)(set))->fd_count=0)
108
108
  #define EV_WIN_FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set))
109
+ #define EV_WIN_FD_COUNT(set) (((fd_set *)(set))->fd_count)
109
110
  /* ######################################## */
110
111
  #else
111
112
  #define EV_WIN_FD_CLR FD_CLR
@@ -192,6 +193,23 @@ select_poll (EV_P_ ev_tstamp timeout)
192
193
  int res;
193
194
  int fd_setsize;
194
195
 
196
+ #ifdef _WIN32
197
+ /* POSIX defines the case when the readfds, writefds, and errorfds arguments
198
+ * are all null pointers.
199
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html
200
+ *
201
+ * But Windows doesn't define such case; simply say don't so that
202
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx
203
+ * "Any two of the parameters, readfds, writefds, or exceptfds, can be given
204
+ * as null. At least one must be non-null, and any non-null descriptor set
205
+ * must contain at least one handle to a socket."
206
+ * At least on Windows Server 2012 R2 Datacenter with Visual Studio 2013
207
+ * (Visual C++ 12), it cause WaitForMultipleObjects stuck.
208
+ */
209
+ if (EV_WIN_FD_COUNT(vec_ri) == 0 && EV_WIN_FD_COUNT(vec_wi) == 0)
210
+ return;
211
+ #endif
212
+
195
213
  EV_RELEASE_CB;
196
214
  EV_TV_SET (tv, timeout);
197
215
 
@@ -246,7 +264,7 @@ select_poll (EV_P_ ev_tstamp timeout)
246
264
  {
247
265
  if (timeout)
248
266
  {
249
- unsigned long ms = timeout * 1e3;
267
+ unsigned long ms = (unsigned long)(timeout * 1e3);
250
268
  Sleep (ms ? ms : 1);
251
269
  }
252
270
 
@@ -106,9 +106,8 @@ module Coolio
106
106
  def send_request
107
107
  nameserver = @nameservers.shift
108
108
  @nameservers << nameserver # rotate them
109
- @socket.connect @nameservers.first, DNS_PORT
110
109
  begin
111
- @socket.send request_message, 0
110
+ @socket.send request_message, 0, @nameservers.first, DNS_PORT
112
111
  rescue Errno::EHOSTUNREACH # TODO figure out why it has to be wrapper here, when the other wrapper should be wrapping this one!
113
112
  end
114
113
  end
data/lib/cool.io/io.rb CHANGED
@@ -102,7 +102,7 @@ module Coolio
102
102
  def close
103
103
  detach if attached?
104
104
  detach_write_watcher
105
- @_io.close unless @_io.closed?
105
+ @_io.close unless closed?
106
106
 
107
107
  on_close
108
108
  nil
@@ -1,5 +1,5 @@
1
1
  module Coolio
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.1"
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -30,7 +30,7 @@ describe Cool.io::AsyncWatcher, :env => :exclude_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 => :exclude_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
data/spec/dns_spec.rb CHANGED
@@ -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
data/spec/spec_helper.rb CHANGED
@@ -12,7 +12,7 @@ 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
17
  c.filter_run_excluding :env => :exclude_win
18
18
  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
@@ -109,11 +109,11 @@ end
109
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 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
-
@@ -1,27 +1,185 @@
1
1
  require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
3
  describe Coolio::TCPSocket do
4
-
4
+ let :loop do
5
+ Coolio::Loop.new
6
+ end
7
+
5
8
  before :each do
6
- @server = TCPServer.new('127.0.0.1', 0)
7
- @host = @server.addr[3]
8
- @port = @server.addr[1]
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
9
24
  end
10
-
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
+
11
52
  after :each do
12
- @server.close
53
+ shutdown
13
54
  end
14
55
 
15
- describe '#close' do
16
-
17
- it 'detaches all watchers on #close before loop#run' do
18
- reactor = Coolio::Loop.new
56
+ context "#close" do
57
+ it "detaches all watchers on #close before loop#run" do
19
58
  client = Coolio::TCPSocket.connect(@host, @port)
20
- reactor.attach(client)
59
+ loop.attach client
21
60
  client.close
22
- reactor.watchers.size.should == 0
61
+ expect(loop.watchers.size).to eq 0
23
62
  end
24
63
  end
25
64
 
26
- end
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
27
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
@@ -4,15 +4,19 @@ describe Cool.io::TimerWatcher do
4
4
 
5
5
  interval = 0.010
6
6
 
7
+ let :loop do
8
+ Cool.io::Loop.new
9
+ end
10
+
7
11
  it "can have the on_timer callback defined after creation" do
8
12
  @watcher = Cool.io::TimerWatcher.new(interval, true)
9
13
  nr = '0'
10
- @watcher.on_timer { nr.succ! }.should == nil
11
- @watcher.attach(Cool.io::Loop.default).should == @watcher
12
- nr.should == '0'
14
+ expect(@watcher.on_timer { nr.succ! }).to be_nil
15
+ expect(@watcher.attach(loop)).to eq(@watcher)
16
+ expect(nr).to eq('0')
13
17
  sleep interval
14
- Cool.io::Loop.default.run_once
15
- nr.should == '1'
18
+ loop.run_once
19
+ expect(nr).to eq('1')
16
20
  end
17
21
 
18
22
  it "can be subclassed" do
@@ -24,29 +28,29 @@ describe Cool.io::TimerWatcher do
24
28
  end
25
29
  end
26
30
  @watcher = MyTimerWatcher.new(interval, true)
27
- @watcher.attach(Cool.io::Loop.default).should == @watcher
28
- MyTimerWatcher::TMP.should == '0'
31
+ expect(@watcher.attach(loop)).to eq(@watcher)
32
+ expect(MyTimerWatcher::TMP).to eq('0')
29
33
  sleep interval
30
- Cool.io::Loop.default.run_once
31
- MyTimerWatcher::TMP.should == '1'
34
+ loop.run_once
35
+ expect(MyTimerWatcher::TMP).to eq('1')
32
36
  end
33
37
 
34
38
  it "can have the on_timer callback redefined between runs" do
35
39
  @watcher = Cool.io::TimerWatcher.new(interval, true)
36
40
  nr = '0'
37
- @watcher.on_timer { nr.succ! }.should == nil
38
- @watcher.attach(Cool.io::Loop.default).should == @watcher
39
- nr.should == '0'
41
+ expect(@watcher.on_timer { nr.succ! }).to be_nil
42
+ expect(@watcher.attach(loop)).to eq(@watcher)
43
+ expect(nr).to eq('0')
40
44
  sleep interval
41
- Cool.io::Loop.default.run_once
42
- nr.should == '1'
45
+ loop.run_once
46
+ expect(nr).to eq('1')
43
47
  @watcher.detach
44
- @watcher.on_timer { nr = :foo }.should == nil
45
- @watcher.attach(Cool.io::Loop.default).should == @watcher
46
- nr.should == '1'
48
+ expect(@watcher.on_timer { nr = :foo }).to be_nil
49
+ expect(@watcher.attach(loop)).to eq(@watcher)
50
+ expect(nr).to eq('1')
47
51
  sleep interval
48
- Cool.io::Loop.default.run_once
49
- nr.should == :foo
52
+ loop.run_once
53
+ expect(nr).to eq(:foo)
50
54
  end
51
55
 
52
56
  after :each do
@@ -0,0 +1,58 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe "Coolio::UDPSocket" do
4
+ let :loop do
5
+ Coolio::Loop.new
6
+ end
7
+
8
+ before :each do
9
+ @echo = UDPSocket.open
10
+ @echo.bind nil, 0
11
+ @port = @echo.addr[1]
12
+
13
+ @running = true
14
+ @echo_thread = Thread.new do
15
+ while @running
16
+ begin
17
+ msg, sender = @echo.recvfrom_nonblock(3)
18
+ @echo.send(msg + "bbb", 0, sender[3], sender[1])
19
+ rescue IO::WaitReadable
20
+ end
21
+ Thread.pass
22
+ end
23
+ end
24
+ end
25
+
26
+ after :each do
27
+ @running = false
28
+ @echo_thread.join
29
+ @echo.close
30
+ end
31
+
32
+ class Readable < Cool.io::IOWatcher
33
+ attr :socket, :received
34
+ def initialize
35
+ @socket = UDPSocket.new
36
+ super(@socket)
37
+ end
38
+
39
+ def on_readable
40
+ @received = @socket.recvfrom_nonblock(6).first
41
+ end
42
+ end
43
+
44
+ it "receive message #on_readable 5 times" do
45
+ 5.times do
46
+ begin
47
+ r = Readable.new
48
+ r.socket.send "aaa", 0, "localhost", @port
49
+
50
+ loop.attach r
51
+ loop.run_once
52
+ expect(r.received).to eq "aaabbb"
53
+ ensure
54
+ r.detach
55
+ end
56
+ end
57
+ end
58
+ end
@@ -5,21 +5,21 @@ describe Cool.io::UNIXListener, :env => :exclude_win do
5
5
 
6
6
  before :each do
7
7
  @tmp = Tempfile.new('coolio_unix_listener_spec')
8
- File.unlink(@tmp.path).should == 1
9
- File.exist?(@tmp.path).should == false
8
+ expect(File.unlink(@tmp.path)).to eq(1)
9
+ expect(File.exist?(@tmp.path)).to eq(false)
10
10
  end
11
11
 
12
12
  it "creates a new UNIXListener" do
13
13
  listener = Cool.io::UNIXListener.new(@tmp.path)
14
- File.socket?(@tmp.path).should == true
14
+ expect(File.socket?(@tmp.path)).to eq(true)
15
15
  end
16
16
 
17
17
  it "builds off an existing UNIXServer" do
18
18
  unix_server = UNIXServer.new(@tmp.path)
19
- File.socket?(@tmp.path).should == true
19
+ expect(File.socket?(@tmp.path)).to eq(true)
20
20
  listener = Cool.io::UNIXListener.new(unix_server)
21
- File.socket?(@tmp.path).should == true
22
- listener.fileno.should == unix_server.fileno
21
+ expect(File.socket?(@tmp.path)).to eq(true)
22
+ expect(listener.fileno).to eq(unix_server.fileno)
23
23
  end
24
24
 
25
25
  end
@@ -5,23 +5,23 @@ describe Cool.io::UNIXServer, :env => :exclude_win do
5
5
 
6
6
  before :each do
7
7
  @tmp = Tempfile.new('coolio_unix_server_spec')
8
- File.unlink(@tmp.path).should == 1
9
- File.exist?(@tmp.path).should == false
8
+ expect(File.unlink(@tmp.path)).to eq(1)
9
+ expect(File.exist?(@tmp.path)).to eq(false)
10
10
  end
11
11
 
12
12
  it "creates a new Cool.io::UNIXServer" do
13
13
  listener = Cool.io::UNIXListener.new(@tmp.path)
14
14
  listener.listen(24)
15
- File.socket?(@tmp.path).should == true
15
+ expect(File.socket?(@tmp.path)).to eq(true)
16
16
  end
17
17
 
18
18
  it "builds off an existing ::UNIXServer" do
19
19
  unix_server = ::UNIXServer.new(@tmp.path)
20
- File.socket?(@tmp.path).should == true
20
+ expect(File.socket?(@tmp.path)).to eq(true)
21
21
  listener = Cool.io::UNIXServer.new(unix_server, Coolio::UNIXSocket)
22
22
  listener.listen(24)
23
- File.socket?(@tmp.path).should == true
24
- listener.fileno.should == unix_server.fileno
23
+ expect(File.socket?(@tmp.path)).to eq(true)
24
+ expect(listener.fileno).to eq(unix_server.fileno)
25
25
  end
26
26
 
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cool.io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-21 00:00:00.000000000 Z
12
+ date: 2015-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -129,11 +129,13 @@ files:
129
129
  - lib/coolio.rb
130
130
  - spec/async_watcher_spec.rb
131
131
  - spec/dns_spec.rb
132
+ - spec/iobuffer_spec.rb
132
133
  - spec/spec_helper.rb
133
134
  - spec/stat_watcher_spec.rb
134
135
  - spec/tcp_server_spec.rb
135
136
  - spec/tcp_socket_spec.rb
136
137
  - spec/timer_watcher_spec.rb
138
+ - spec/udp_socket_spec.rb
137
139
  - spec/unix_listener_spec.rb
138
140
  - spec/unix_server_spec.rb
139
141
  homepage: http://coolio.github.com
@@ -155,17 +157,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  version: '0'
156
158
  requirements: []
157
159
  rubyforge_project:
158
- rubygems_version: 2.4.5
160
+ rubygems_version: 2.2.2
159
161
  signing_key:
160
162
  specification_version: 4
161
163
  summary: A cool framework for doing high performance I/O in Ruby
162
164
  test_files:
163
165
  - spec/async_watcher_spec.rb
164
166
  - spec/dns_spec.rb
167
+ - spec/iobuffer_spec.rb
165
168
  - spec/spec_helper.rb
166
169
  - spec/stat_watcher_spec.rb
167
170
  - spec/tcp_server_spec.rb
168
171
  - spec/tcp_socket_spec.rb
169
172
  - spec/timer_watcher_spec.rb
173
+ - spec/udp_socket_spec.rb
170
174
  - spec/unix_listener_spec.rb
171
175
  - spec/unix_server_spec.rb