eventmachine-maglev- 1.0.0.beta.4 → 1.0.0.rc.4

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.
@@ -31,38 +31,38 @@ module EventMachine
31
31
  # Simple SMTP client
32
32
  #
33
33
  # @example
34
- # email = EM::Protocols::SmtpClient.send(
35
- # :domain=>"example.com",
36
- # :host=>'localhost',
37
- # :port=>25, # optional, defaults 25
38
- # :starttls=>true, # use ssl
39
- # :from=>"sender@example.com",
40
- # :to=> ["to_1@example.com", "to_2@example.com"],
41
- # :header=> {"Subject" => "This is a subject line"},
42
- # :body=> "This is the body of the email"
43
- # )
44
- # email.callback{
45
- # puts 'Email sent!'
46
- # }
47
- # email.errback{ |e|
48
- # puts 'Email failed!'
49
- # }
34
+ # email = EM::Protocols::SmtpClient.send(
35
+ # :domain=>"example.com",
36
+ # :host=>'localhost',
37
+ # :port=>25, # optional, defaults 25
38
+ # :starttls=>true, # use ssl
39
+ # :from=>"sender@example.com",
40
+ # :to=> ["to_1@example.com", "to_2@example.com"],
41
+ # :header=> {"Subject" => "This is a subject line"},
42
+ # :body=> "This is the body of the email"
43
+ # )
44
+ # email.callback{
45
+ # puts 'Email sent!'
46
+ # }
47
+ # email.errback{ |e|
48
+ # puts 'Email failed!'
49
+ # }
50
50
  #
51
51
  # Sending generated emails (using mailfactory)
52
52
  #
53
- # mail = MailFactory.new
54
- # mail.to = 'someone@site.co'
55
- # mail.from = 'me@site.com'
56
- # mail.subject = 'hi!'
57
- # mail.text = 'hello world'
58
- # mail.html = '<h1>hello world</h1>'
53
+ # mail = MailFactory.new
54
+ # mail.to = 'someone@site.co'
55
+ # mail.from = 'me@site.com'
56
+ # mail.subject = 'hi!'
57
+ # mail.text = 'hello world'
58
+ # mail.html = '<h1>hello world</h1>'
59
59
  #
60
- # email = EM::P::SmtpClient.send(
61
- # :domain=>'site.com',
62
- # :from=>mail.from,
63
- # :to=>mail.to,
64
- # :content=>"#{mail.to_s}\r\n.\r\n"
65
- # )
60
+ # email = EM::P::SmtpClient.send(
61
+ # :domain=>'site.com',
62
+ # :from=>mail.from,
63
+ # :to=>mail.to,
64
+ # :content=>"#{mail.to_s}\r\n.\r\n"
65
+ # )
66
66
  #
67
67
  class SmtpClient < Connection
68
68
  include EventMachine::Deferrable
data/lib/em/pure_ruby.rb CHANGED
@@ -177,6 +177,18 @@ module EventMachine
177
177
  def set_max_timer_count n
178
178
  end
179
179
 
180
+ # @private
181
+ def get_sock_opt signature, level, optname
182
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
183
+ selectable.getsockopt level, optname
184
+ end
185
+
186
+ # @private
187
+ def set_sock_opt signature, level, optname, optval
188
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
189
+ selectable.setsockopt level, optname, optval
190
+ end
191
+
180
192
  # @private
181
193
  def send_file_data sig, filename
182
194
  sz = File.size(filename)
@@ -29,7 +29,7 @@ module EventMachine
29
29
  #
30
30
  # # If we don't care about the result:
31
31
  # pool.perform do |dispatcher|
32
- # # The following blcok executes inside a dedicated thread, and should not
32
+ # # The following block executes inside a dedicated thread, and should not
33
33
  # # access EventMachine things:
34
34
  # dispatcher.dispatch do |cassandra|
35
35
  # cassandra.insert(:Things, '10', 'stuff' => 'things')
data/lib/em/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.0.beta.4"
2
+ VERSION = "1.0.0.rc.4"
3
3
  end
data/lib/eventmachine.rb CHANGED
@@ -82,7 +82,8 @@ module EventMachine
82
82
  @reactor_running = false
83
83
  @next_tick_queue = []
84
84
  @tails = []
85
- @threadpool = nil
85
+ @threadpool = @threadqueue = @resultqueue = nil
86
+ @all_threads_spawned = false
86
87
 
87
88
  # System errnos
88
89
  # @private
@@ -157,7 +158,13 @@ module EventMachine
157
158
  # will start without release_machine being called and will immediately throw
158
159
 
159
160
  #
160
-
161
+ if reactor_running? and @reactor_pid != Process.pid
162
+ # Reactor was started in a different parent, meaning we have forked.
163
+ # Clean up reactor state so a new reactor boots up in this child.
164
+ stop_event_loop
165
+ release_machine
166
+ @reactor_running = false
167
+ end
161
168
 
162
169
  tail and @tails.unshift(tail)
163
170
 
@@ -171,6 +178,7 @@ module EventMachine
171
178
  @next_tick_queue ||= []
172
179
  @tails ||= []
173
180
  begin
181
+ @reactor_pid = Process.pid
174
182
  @reactor_running = true
175
183
  initialize_event_machine
176
184
  (b = blk || block) and add_timer(0, b)
@@ -203,6 +211,7 @@ module EventMachine
203
211
  @threadqueue = nil
204
212
  @resultqueue = nil
205
213
  @threadpool = nil
214
+ @all_threads_spawned = false
206
215
  end
207
216
 
208
217
  @next_tick_queue = []
@@ -254,7 +263,7 @@ module EventMachine
254
263
  if self.reactor_running?
255
264
  self.stop_event_loop
256
265
  self.release_machine
257
- self.instance_variable_set( '@reactor_running', false )
266
+ @reactor_running = false
258
267
  end
259
268
  self.run block
260
269
  end
@@ -427,7 +436,8 @@ module EventMachine
427
436
  # that you must define. When the network server that is started by
428
437
  # start_server accepts a new connection, it instantiates a new
429
438
  # object of an anonymous class that is inherited from {EventMachine::Connection},
430
- # *into which your handler module have been included*.
439
+ # *into which your handler module have been included*. Arguments passed into start_server
440
+ # after the class name are passed into the constructor during the instantiation.
431
441
  #
432
442
  # Your handler module may override any of the methods in {EventMachine::Connection},
433
443
  # such as {EventMachine::Connection#receive_data}, in order to implement the specific behavior
@@ -738,6 +748,7 @@ module EventMachine
738
748
  c = klass.new s, *args
739
749
 
740
750
  c.instance_variable_set(:@io, io)
751
+ c.instance_variable_set(:@watch_mode, watch_mode)
741
752
  c.instance_variable_set(:@fd, fd)
742
753
 
743
754
  @conns[s] = c
@@ -763,7 +774,11 @@ module EventMachine
763
774
  #raise "still connected" if @conns.has_key?(handler.signature)
764
775
  return handler if @conns.has_key?(handler.signature)
765
776
 
766
- s = connect_server server, port
777
+ s = if port
778
+ connect_server server, port
779
+ else
780
+ connect_unix_server server
781
+ end
767
782
  handler.signature = s
768
783
  @conns[s] = handler
769
784
  block_given? and yield handler
@@ -938,10 +953,21 @@ module EventMachine
938
953
  cback.call result if cback
939
954
  end
940
955
 
941
- @next_tick_mutex.synchronize do
942
- jobs, @next_tick_queue = @next_tick_queue, []
943
- jobs
944
- end.each { |j| j.call }
956
+ # Capture the size at the start of this tick...
957
+ size = @next_tick_mutex.synchronize { @next_tick_queue.size }
958
+ size.times do |i|
959
+ callback = @next_tick_mutex.synchronize { @next_tick_queue.shift }
960
+ begin
961
+ callback.call
962
+ ensure
963
+ # This is a little nasty. The problem is, if an exception occurs during
964
+ # the callback, then we need to send a signal to the reactor to actually
965
+ # do some work during the next_tick. The only mechanism we have from the
966
+ # ruby side is next_tick itself, although ideally, we'd just drop a byte
967
+ # on the loopback descriptor.
968
+ EM.next_tick {} if $!
969
+ end
970
+ end
945
971
  end
946
972
 
947
973
 
@@ -993,7 +1019,6 @@ module EventMachine
993
1019
  # has no constructor.
994
1020
 
995
1021
  unless @threadpool
996
- require 'thread'
997
1022
  @threadpool = []
998
1023
  @threadqueue = ::Queue.new
999
1024
  @resultqueue = ::Queue.new
@@ -1018,6 +1043,19 @@ module EventMachine
1018
1043
  end
1019
1044
  @threadpool << thread
1020
1045
  end
1046
+ @all_threads_spawned = true
1047
+ end
1048
+
1049
+ ##
1050
+ # Returns +true+ if all deferred actions are done executing and their
1051
+ # callbacks have been fired.
1052
+ #
1053
+ def self.defers_finished?
1054
+ return false if @threadpool and !@all_threads_spawned
1055
+ return false if @threadqueue and not @threadqueue.empty?
1056
+ return false if @resultqueue and not @resultqueue.empty?
1057
+ return false if @threadpool and @threadqueue.num_waiting != @threadpool.size
1058
+ return true
1021
1059
  end
1022
1060
 
1023
1061
  class << self
@@ -1393,11 +1431,19 @@ module EventMachine
1393
1431
  if opcode == ConnectionUnbound
1394
1432
  if c = @conns.delete( conn_binding )
1395
1433
  begin
1396
- if c.original_method(:unbind).arity == 1
1434
+ if c.original_method(:unbind).arity != 0
1397
1435
  c.unbind(data == 0 ? nil : EventMachine::ERRNOS[data])
1398
1436
  else
1399
1437
  c.unbind
1400
1438
  end
1439
+ # If this is an attached (but not watched) connection, close the underlying io object.
1440
+ if c.instance_variable_defined?(:@io) and !c.instance_variable_get(:@watch_mode)
1441
+ io = c.instance_variable_get(:@io)
1442
+ begin
1443
+ io.close
1444
+ rescue Errno::EBADF, IOError
1445
+ end
1446
+ end
1401
1447
  rescue
1402
1448
  @wrapped_exception = $!
1403
1449
  stop
data/lib/jeventmachine.rb CHANGED
@@ -203,6 +203,11 @@ module EventMachine
203
203
  Socket.pack_sockaddr_in(*peer)
204
204
  end
205
205
  end
206
+ def self.get_sockname sig
207
+ if sockName = @em.getSockName(sig)
208
+ Socket.pack_sockaddr_in(*sockName)
209
+ end
210
+ end
206
211
  # @private
207
212
  def self.attach_fd fileno, watch_mode
208
213
  # 3Aug09: We could pass in the actual SocketChannel, but then it would be modified (set as non-blocking), and
File without changes
File without changes
File without changes
data/tests/test_basic.rb CHANGED
@@ -224,4 +224,71 @@ class TestBasic < Test::Unit::TestCase
224
224
  end
225
225
  end
226
226
  end
227
+
228
+ def test_schedule_close
229
+ localhost, port = '127.0.0.1', 9000
230
+ timer_ran = false
231
+ num_close_scheduled = nil
232
+ EM.run do
233
+ assert_equal 0, EM.num_close_scheduled
234
+ EM.add_timer(1) { timer_ran = true; EM.stop }
235
+ EM.start_server localhost, port do |s|
236
+ s.close_connection
237
+ num_close_scheduled = EM.num_close_scheduled
238
+ end
239
+ EM.connect localhost, port do |c|
240
+ def c.unbind
241
+ EM.stop
242
+ end
243
+ end
244
+ end
245
+ assert !timer_ran
246
+ assert_equal 1, num_close_scheduled
247
+ end
248
+
249
+ def test_fork_safe
250
+ return unless cpid = fork { exit! } rescue false
251
+
252
+ read, write = IO.pipe
253
+ EM.run do
254
+ cpid = fork do
255
+ write.puts "forked"
256
+ EM.run do
257
+ EM.next_tick do
258
+ write.puts "EM ran"
259
+ exit!
260
+ end
261
+ end
262
+ end
263
+ EM.stop
264
+ end
265
+ Process.waitall
266
+ assert_equal "forked\n", read.readline
267
+ assert_equal "EM ran\n", read.readline
268
+ ensure
269
+ read.close rescue nil
270
+ write.close rescue nil
271
+ end
272
+
273
+ def test_error_handler_idempotent # issue 185
274
+ errors = []
275
+ ticks = []
276
+ EM.error_handler do |e|
277
+ errors << e
278
+ end
279
+
280
+ EM.run do
281
+ EM.next_tick do
282
+ ticks << :first
283
+ raise
284
+ end
285
+ EM.next_tick do
286
+ ticks << :second
287
+ end
288
+ EM.add_timer(0.001) { EM.stop }
289
+ end
290
+
291
+ assert_equal 1, errors.size
292
+ assert_equal [:first, :second], ticks
293
+ end
227
294
  end
@@ -0,0 +1,23 @@
1
+ require 'em_test_helper'
2
+
3
+ class TestIdleConnection < Test::Unit::TestCase
4
+ if EM.respond_to?(:get_idle_time)
5
+ def test_idle_time
6
+ EM.run{
7
+ conn = EM.connect 'www.google.com', 80
8
+ EM.add_timer(3){
9
+ $idle_time = conn.get_idle_time
10
+ conn.send_data "GET / HTTP/1.0\r\n\r\n"
11
+ EM.next_tick{
12
+ $idle_time_after_send = conn.get_idle_time
13
+ conn.close_connection
14
+ EM.stop
15
+ }
16
+ }
17
+ }
18
+
19
+ assert_in_delta 3, $idle_time, 0.2
20
+ assert_equal 0, $idle_time_after_send
21
+ end
22
+ end
23
+ end
data/tests/test_pool.rb CHANGED
@@ -115,6 +115,41 @@ class TestPool < Test::Unit::TestCase
115
115
  assert_equal [:res], pool.contents
116
116
  end
117
117
 
118
+ def test_contents_when_perform_errors_and_on_error_is_not_set
119
+ pool.add :res
120
+ assert_equal [:res], pool.contents
121
+
122
+ pool.perform do |r|
123
+ d = EM::DefaultDeferrable.new
124
+ d.fail
125
+ d
126
+ end
127
+
128
+ EM.run { EM.next_tick { EM.stop } }
129
+
130
+ assert_equal [:res], pool.contents
131
+ end
132
+
133
+ def test_contents_when_perform_errors_and_on_error_is_set
134
+ pool.add :res
135
+ res = nil
136
+ pool.on_error do |r|
137
+ res = r
138
+ end
139
+ assert_equal [:res], pool.contents
140
+
141
+ pool.perform do |r|
142
+ d = EM::DefaultDeferrable.new
143
+ d.fail 'foo'
144
+ d
145
+ end
146
+
147
+ EM.run { EM.next_tick { EM.stop } }
148
+
149
+ assert_equal :res, res
150
+ assert_equal [], pool.contents
151
+ end
152
+
118
153
  def test_num_waiting
119
154
  pool.add :res
120
155
  assert_equal 0, pool.num_waiting
@@ -125,4 +160,35 @@ class TestPool < Test::Unit::TestCase
125
160
  assert_equal 10, pool.num_waiting
126
161
  end
127
162
 
128
- end
163
+ def test_exceptions_in_the_work_block_bubble_up_raise_and_fail_the_resource
164
+ pool.add :res
165
+
166
+ res = nil
167
+ pool.on_error { |r| res = r }
168
+ pool.perform { raise 'boom' }
169
+
170
+ assert_raises(RuntimeError) do
171
+ EM.run { EM.next_tick { EM.stop } }
172
+ end
173
+
174
+ assert_equal [], pool.contents
175
+ assert_equal :res, res
176
+ end
177
+
178
+ def test_removed_list_does_not_leak_on_errors
179
+ pool.add :res
180
+
181
+ pool.on_error do |r|
182
+ # This is actually the wrong thing to do, and not required, but some users
183
+ # might do it. When they do, they would find that @removed would cause a
184
+ # slow leak.
185
+ pool.remove r
186
+ end
187
+
188
+ pool.perform { d = EM::DefaultDeferrable.new; d.fail; d }
189
+
190
+ EM.run { EM.next_tick { EM.stop } }
191
+ assert_equal [], pool.instance_variable_get(:@removed)
192
+ end
193
+
194
+ end
@@ -99,6 +99,24 @@ class TestProcesses < Test::Unit::TestCase
99
99
 
100
100
  assert_equal("hello\n", $out)
101
101
  end
102
+
103
+ def test_em_popen_pause_resume
104
+ c_rx = 0
105
+
106
+ test_client = Module.new do
107
+ define_method :receive_data do |data|
108
+ c_rx += 1
109
+ pause
110
+ EM.add_timer(0.5) { EM.stop }
111
+ end
112
+ end
113
+
114
+ EM.run{
115
+ EM.popen('cat /dev/random', test_client)
116
+ }
117
+
118
+ assert_equal 1, c_rx
119
+ end
102
120
  else
103
121
  warn "EM.popen not implemented, skipping tests in #{__FILE__}"
104
122
 
@@ -24,6 +24,7 @@ class TestProxyConnection < Test::Unit::TestCase
24
24
  end
25
25
 
26
26
  def unbind
27
+ $proxied_bytes = self.get_proxied_bytes
27
28
  @client.close_connection_after_writing
28
29
  end
29
30
  end
@@ -94,7 +95,7 @@ class TestProxyConnection < Test::Unit::TestCase
94
95
  end
95
96
 
96
97
  def receive_data(data)
97
- EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
98
+ @proxy = EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
98
99
  end
99
100
  end
100
101
 
@@ -134,6 +135,17 @@ class TestProxyConnection < Test::Unit::TestCase
134
135
  assert_equal("I know!", $client_data)
135
136
  end
136
137
 
138
+ def test_proxied_bytes
139
+ EM.run {
140
+ EM.start_server("127.0.0.1", @port, Server)
141
+ EM.start_server("127.0.0.1", @proxy_port, ProxyServer, @port)
142
+ EM.connect("127.0.0.1", @proxy_port, Client)
143
+ }
144
+
145
+ assert_equal("I know!", $client_data)
146
+ assert_equal("I know!".bytesize, $proxied_bytes)
147
+ end
148
+
137
149
  def test_partial_proxy_connection
138
150
  EM.run {
139
151
  EM.start_server("127.0.0.1", @port, Server)
@@ -0,0 +1,37 @@
1
+ require 'em_test_helper'
2
+ require 'socket'
3
+
4
+ class TestSetSockOpt < Test::Unit::TestCase
5
+
6
+ if EM.respond_to? :set_sock_opt
7
+ def setup
8
+ assert(!EM.reactor_running?)
9
+ end
10
+
11
+ def teardown
12
+ assert(!EM.reactor_running?)
13
+ end
14
+
15
+ #-------------------------------------
16
+
17
+ def test_set_sock_opt
18
+ test = self
19
+ EM.run do
20
+ EM.connect 'google.com', 80, Module.new {
21
+ define_method :post_init do
22
+ val = set_sock_opt Socket::SOL_SOCKET, Socket::SO_DEBUG, true
23
+ test.assert_equal 0, val
24
+ EM.stop
25
+ end
26
+ }
27
+ end
28
+ end
29
+ else
30
+ warn "EM.set_sock_opt not implemented, skipping tests in #{__FILE__}"
31
+
32
+ # Because some rubies will complain if a TestCase class has no tests
33
+ def test_em_set_sock_opt_unsupported
34
+ assert true
35
+ end
36
+ end
37
+ end
@@ -2,6 +2,15 @@ require 'em_test_helper'
2
2
  require 'socket'
3
3
 
4
4
  class TestUnbindReason < Test::Unit::TestCase
5
+
6
+ class StubConnection < EM::Connection
7
+ attr_reader :error
8
+ def unbind(reason = nil)
9
+ @error = reason
10
+ EM.stop
11
+ end
12
+ end
13
+
5
14
  def test_connect_timeout
6
15
  error = nil
7
16
  EM.run {
@@ -13,7 +22,7 @@ class TestUnbindReason < Test::Unit::TestCase
13
22
  }
14
23
  conn.pending_connect_timeout = 0.1
15
24
  }
16
- assert_equal error, Errno::ETIMEDOUT
25
+ assert_equal Errno::ETIMEDOUT, error
17
26
  end
18
27
 
19
28
  def test_connect_refused
@@ -26,6 +35,14 @@ class TestUnbindReason < Test::Unit::TestCase
26
35
  end
27
36
  }
28
37
  }
29
- assert_equal error, Errno::ECONNREFUSED
38
+ assert_equal Errno::ECONNREFUSED, error
39
+ end
40
+
41
+ def test_optional_argument
42
+ conn = nil
43
+ EM.run {
44
+ conn = EM.connect '127.0.0.1', 12388, StubConnection
45
+ }
46
+ assert_equal Errno::ECONNREFUSED, conn.error
30
47
  end
31
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventmachine-maglev-
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta.4
4
+ version: 1.0.0.rc.4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -10,22 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-07-29 00:00:00.000000000 Z
13
+ date: 2012-08-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake-compiler
17
- requirement: &69825862374080 !ruby/object:Gem::Requirement
17
+ requirement: &70169512878700 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
- - - =
20
+ - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: 0.7.6
22
+ version: 0.8.1
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *69825862374080
25
+ version_requirements: *70169512878700
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: yard
28
- requirement: &69825862373380 !ruby/object:Gem::Requirement
28
+ requirement: &70169512877400 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 0.7.2
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *69825862373380
36
+ version_requirements: *70169512877400
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bluecloth
39
- requirement: &69825862372800 !ruby/object:Gem::Requirement
39
+ requirement: &70169512876360 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *69825862372800
47
+ version_requirements: *70169512876360
48
48
  description: ! 'EventMachine implements a fast, single-threaded engine for arbitrary
49
49
  network
50
50
 
@@ -193,9 +193,9 @@ files:
193
193
  - lib/em/version.rb
194
194
  - lib/eventmachine.rb
195
195
  - lib/jeventmachine.rb
196
- - tasks/cpp.rake_example
197
- - tasks/package.rake
198
- - tasks/test.rake
196
+ - rakelib/cpp.rake_example
197
+ - rakelib/package.rake
198
+ - rakelib/test.rake
199
199
  - tests/client.crt
200
200
  - tests/client.key
201
201
  - tests/em_test_helper.rb
@@ -216,6 +216,7 @@ files:
216
216
  - tests/test_hc.rb
217
217
  - tests/test_httpclient.rb
218
218
  - tests/test_httpclient2.rb
219
+ - tests/test_idle_connection.rb
219
220
  - tests/test_inactivity_timeout.rb
220
221
  - tests/test_kb.rb
221
222
  - tests/test_ltp.rb
@@ -235,6 +236,7 @@ files:
235
236
  - tests/test_sasl.rb
236
237
  - tests/test_send_file.rb
237
238
  - tests/test_servers.rb
239
+ - tests/test_set_sock_opt.rb
238
240
  - tests/test_shutdown_hooks.rb
239
241
  - tests/test_smtpclient.rb
240
242
  - tests/test_smtpserver.rb