fluentd 0.14.9 → 0.14.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/ChangeLog +44 -0
  4. data/appveyor.yml +1 -0
  5. data/code-of-conduct.md +3 -0
  6. data/fluentd.gemspec +1 -1
  7. data/lib/fluent/command/cat.rb +11 -3
  8. data/lib/fluent/compat/output.rb +6 -3
  9. data/lib/fluent/compat/parser.rb +2 -0
  10. data/lib/fluent/config/section.rb +1 -1
  11. data/lib/fluent/env.rb +1 -1
  12. data/lib/fluent/plugin/filter_record_transformer.rb +12 -30
  13. data/lib/fluent/plugin/in_forward.rb +50 -169
  14. data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
  15. data/lib/fluent/plugin/in_syslog.rb +13 -7
  16. data/lib/fluent/plugin/in_tail.rb +29 -14
  17. data/lib/fluent/plugin/in_tcp.rb +54 -14
  18. data/lib/fluent/plugin/in_udp.rb +49 -13
  19. data/lib/fluent/plugin/out_file.rb +30 -14
  20. data/lib/fluent/plugin/out_forward.rb +199 -173
  21. data/lib/fluent/plugin/output.rb +71 -46
  22. data/lib/fluent/plugin/parser_json.rb +1 -1
  23. data/lib/fluent/plugin_helper.rb +2 -0
  24. data/lib/fluent/plugin_helper/event_loop.rb +24 -6
  25. data/lib/fluent/plugin_helper/inject.rb +12 -1
  26. data/lib/fluent/plugin_helper/server.rb +494 -0
  27. data/lib/fluent/plugin_helper/socket.rb +101 -0
  28. data/lib/fluent/plugin_helper/socket_option.rb +84 -0
  29. data/lib/fluent/plugin_helper/timer.rb +1 -0
  30. data/lib/fluent/test/driver/base.rb +45 -13
  31. data/lib/fluent/version.rb +1 -1
  32. data/lib/fluent/winsvc.rb +1 -1
  33. data/test/compat/test_parser.rb +10 -0
  34. data/test/config/test_configurable.rb +20 -0
  35. data/test/helper.rb +36 -1
  36. data/test/plugin/test_filter_record_transformer.rb +31 -103
  37. data/test/plugin/test_in_forward.rb +13 -75
  38. data/test/plugin/test_in_monitor_agent.rb +65 -35
  39. data/test/plugin/test_in_syslog.rb +39 -3
  40. data/test/plugin/test_in_tcp.rb +78 -62
  41. data/test/plugin/test_in_udp.rb +101 -80
  42. data/test/plugin/test_out_file.rb +17 -0
  43. data/test/plugin/test_out_forward.rb +155 -125
  44. data/test/plugin/test_output_as_buffered.rb +4 -2
  45. data/test/plugin_helper/test_inject.rb +21 -0
  46. data/test/plugin_helper/test_server.rb +905 -0
  47. data/test/test_event_time.rb +3 -1
  48. data/test/test_output.rb +30 -1
  49. data/test/test_test_drivers.rb +5 -2
  50. metadata +19 -6
@@ -1460,6 +1460,7 @@ class BufferedOutputTest < Test::Unit::TestCase
1460
1460
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
1461
1461
  @i.start
1462
1462
  @i.after_start
1463
+ @i.log = Fluent::Test::TestLogger.new
1463
1464
  end
1464
1465
 
1465
1466
  test '#format is called for each event streams' do
@@ -1740,8 +1741,9 @@ class BufferedOutputTest < Test::Unit::TestCase
1740
1741
 
1741
1742
  assert{ chunks[0...3].all?{|c| !c.empty? } }
1742
1743
 
1743
- # rollback is in progress, but some may be flushed again after rollback
1744
- Timecop.freeze( Time.parse('2016-04-13 14:04:46 +0900') )
1744
+ # rollback is in progress, but some may be flushed again in retry state, after rollback
1745
+ # retry.next_time is 14:04:49
1746
+ Timecop.freeze( Time.parse('2016-04-13 14:04:51 +0900') )
1745
1747
  @i.enqueue_thread_wait
1746
1748
  @i.flush_thread_wakeup
1747
1749
 
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
2
  require 'fluent/plugin_helper/inject'
3
+ require 'fluent/plugin/output'
3
4
  require 'fluent/event'
4
5
  require 'time'
5
6
 
@@ -15,6 +16,13 @@ class InjectHelperTest < Test::Unit::TestCase
15
16
  end
16
17
  end
17
18
 
19
+ class Dummy3 < Fluent::Plugin::Output
20
+ helpers :inject
21
+ def write(chunk)
22
+ # dummy
23
+ end
24
+ end
25
+
18
26
  def config_inject_section(hash = {})
19
27
  config_element('ROOT', '', {}, [config_element('inject', '', hash)])
20
28
  end
@@ -27,7 +35,9 @@ class InjectHelperTest < Test::Unit::TestCase
27
35
  teardown do
28
36
  if @d
29
37
  @d.stop unless @d.stopped?
38
+ @d.before_shutdown unless @d.before_shutdown?
30
39
  @d.shutdown unless @d.shutdown?
40
+ @d.after_shutdown unless @d.after_shutdown?
31
41
  @d.close unless @d.closed?
32
42
  @d.terminate unless @d.terminated?
33
43
  end
@@ -93,6 +103,17 @@ class InjectHelperTest < Test::Unit::TestCase
93
103
  assert_not_nil @d.instance_eval{ @_inject_time_formatter }
94
104
  end
95
105
 
106
+ test 'raise an error when injected hostname is used in buffer chunk key too' do
107
+ @d = Dummy3.new
108
+ conf = config_element('ROOT', '', {}, [
109
+ config_element('inject', '', {'hostname_key' => 'h'}),
110
+ config_element('buffer', 'tag,h'),
111
+ ])
112
+ assert_raise Fluent::ConfigError.new("the key specified by 'hostname_key' in <inject> cannot be used in buffering chunk key.") do
113
+ @d.configure(conf)
114
+ end
115
+ end
116
+
96
117
  sub_test_case 'using inject_values_to_record' do
97
118
  test 'injects hostname automatically detected' do
98
119
  detected_hostname = `hostname`.chomp
@@ -0,0 +1,905 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin_helper/server'
3
+ require 'fluent/plugin/base'
4
+ require 'timeout'
5
+
6
+ require 'serverengine'
7
+ require 'fileutils'
8
+
9
+ class ServerPluginHelperTest < Test::Unit::TestCase
10
+ class Dummy < Fluent::Plugin::TestBase
11
+ helpers :server
12
+ end
13
+
14
+ PORT = unused_port
15
+
16
+ setup do
17
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
18
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
19
+ FileUtils.rm_f @socket_manager_path
20
+ end
21
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
22
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
23
+
24
+ @d = Dummy.new
25
+ @d.start
26
+ @d.after_start
27
+ end
28
+
29
+ teardown do
30
+ @d.stopped? || @d.stop
31
+ @d.before_shutdown? || @d.before_shutdown
32
+ @d.shutdown? || @d.shutdown
33
+ @d.after_shutdown? || @d.after_shutdown
34
+ @d.closed? || @d.close
35
+ @d.terminated? || @d.terminate
36
+
37
+ @socket_manager_server.close
38
+ if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
39
+ FileUtils.rm_f @socket_manager_path
40
+ end
41
+ end
42
+
43
+ sub_test_case 'plugin instance' do
44
+ test 'can be instantiated to be able to create threads' do
45
+ d = Dummy.new
46
+ assert d.respond_to?(:_servers)
47
+ assert d._servers.empty?
48
+
49
+ assert d.respond_to?(:server_wait_until_start)
50
+ assert d.respond_to?(:server_wait_until_stop)
51
+ assert d.respond_to?(:server_create_connection)
52
+ assert d.respond_to?(:server_create)
53
+ assert d.respond_to?(:server_create_tcp)
54
+ assert d.respond_to?(:server_create_udp)
55
+ assert d.respond_to?(:server_create_tls)
56
+ end
57
+
58
+ test 'can be configured' do
59
+ d = Dummy.new
60
+ assert_nothing_raised do
61
+ d.configure(config_element())
62
+ end
63
+ assert d.plugin_id
64
+ assert d.log
65
+ end
66
+ end
67
+
68
+ # run tests for tcp, udp, tls and unix
69
+ sub_test_case '#server_create and #server_create_connection' do
70
+ methods = {server_create: :server_create, server_create_connection: :server_create_connection}
71
+
72
+ data(methods)
73
+ test 'raise error if title is not specified or not a symbol' do |m|
74
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
75
+ @d.__send__(m, nil, PORT){|x| x }
76
+ end
77
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
78
+ @d.__send__(m, "", PORT){|x| x }
79
+ end
80
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
81
+ @d.__send__(m, "title", PORT){|x| x }
82
+ end
83
+ assert_nothing_raised do
84
+ @d.__send__(m, :myserver, PORT){|x| x }
85
+ end
86
+ end
87
+
88
+ data(methods)
89
+ test 'raise error if port is not specified or not an integer' do |m|
90
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
91
+ @d.__send__(m, :myserver, nil){|x| x }
92
+ end
93
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
94
+ @d.__send__(m, :myserver, "1"){|x| x }
95
+ end
96
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
97
+ @d.__send__(m, :myserver, 1.5){|x| x }
98
+ end
99
+ assert_nothing_raised do
100
+ @d.__send__(m, :myserver, PORT){|x| x }
101
+ end
102
+ end
103
+
104
+ data(methods)
105
+ test 'raise error if block is not specified' do |m|
106
+ assert_raise(ArgumentError) do
107
+ @d.__send__(m, :myserver, PORT)
108
+ end
109
+ assert_nothing_raised do
110
+ @d.__send__(m, :myserver, PORT){|x| x }
111
+ end
112
+ end
113
+
114
+ data(methods)
115
+ test 'creates tcp server, binds 0.0.0.0 in default' do |m|
116
+ @d.__send__(m, :myserver, PORT){|x| x }
117
+
118
+ assert_equal 1, @d._servers.size
119
+
120
+ created_server_info = @d._servers.first
121
+
122
+ assert_equal :myserver, created_server_info.title
123
+ assert_equal PORT, created_server_info.port
124
+
125
+ assert_equal :tcp, created_server_info.proto
126
+ assert_equal "0.0.0.0", created_server_info.bind
127
+
128
+ created_server = created_server_info.server
129
+
130
+ assert created_server.is_a?(Coolio::TCPServer)
131
+ assert_equal "0.0.0.0", created_server.instance_eval{ @listen_socket }.addr[3]
132
+ end
133
+
134
+ data(methods)
135
+ test 'creates tcp server if specified in proto' do |m|
136
+ @d.__send__(m, :myserver, PORT, proto: :tcp){|x| x }
137
+
138
+ created_server_info = @d._servers.first
139
+ assert_equal :tcp, created_server_info.proto
140
+ created_server = created_server_info.server
141
+ assert created_server.is_a?(Coolio::TCPServer)
142
+ end
143
+
144
+ # tests about "proto: :udp" is in #server_create
145
+
146
+ data(methods)
147
+ test 'creates tls server if specified in proto' do |m|
148
+ # pend "not implemented yet"
149
+ end
150
+
151
+ data(methods)
152
+ test 'creates unix server if specified in proto' do |m|
153
+ # pend "not implemented yet"
154
+ end
155
+
156
+ data(methods)
157
+ test 'raise error if unknown protocol specified' do |m|
158
+ assert_raise(ArgumentError.new("BUG: invalid protocol name")) do
159
+ @d.__send__(m, :myserver, PORT, proto: :quic){|x| x }
160
+ end
161
+ end
162
+
163
+ data(
164
+ 'server_create tcp' => [:server_create, :tcp],
165
+ # 'server_create tls' => [:server_create, :tls],
166
+ # 'server_create unix' => [:server_create, :unix],
167
+ 'server_create_connection tcp' => [:server_create_connection, :tcp],
168
+ # 'server_create_connection tcp' => [:server_create_connection, :tls],
169
+ # 'server_create_connection tcp' => [:server_create_connection, :unix],
170
+ )
171
+ test 'raise error if udp options specified for tcp/tls/unix' do |(m, proto)|
172
+ assert_raise ArgumentError do
173
+ @d.__send__(m, :myserver, PORT, proto: proto, max_bytes: 128){|x| x }
174
+ end
175
+ assert_raise ArgumentError do
176
+ @d.__send__(m, :myserver, PORT, proto: proto, flags: 1){|x| x }
177
+ end
178
+ end
179
+
180
+ data(
181
+ 'server_create udp' => [:server_create, :udp],
182
+ )
183
+ test 'raise error if tcp/tls options specified for udp' do |(m, proto)|
184
+ assert_raise(ArgumentError.new("BUG: linger_timeout is available for tcp/tls")) do
185
+ @d.__send__(m, :myserver, PORT, proto: proto, linger_timeout: 1, max_bytes: 128){|x| x }
186
+ end
187
+ end
188
+
189
+ data(
190
+ 'server_create udp' => [:server_create, :udp],
191
+ )
192
+ test 'raise error if tcp/tls/unix options specified for udp' do |(m, proto)|
193
+ assert_raise(ArgumentError.new("BUG: backlog is available for tcp/tls")) do
194
+ @d.__send__(m, :myserver, PORT, proto: proto, backlog: 500){|x| x }
195
+ end
196
+ end
197
+
198
+ data(
199
+ 'server_create tcp' => [:server_create, :tcp, {}],
200
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
201
+ # 'server_create unix' => [:server_create, :unix, {}],
202
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
203
+ # 'server_create_connection unix' => [:server_create_connection, :unix, {}],
204
+ )
205
+ test 'raise error if tls options specified for tcp/udp/unix' do |(m, proto, kwargs)|
206
+ assert_raise(ArgumentError.new("BUG: certopts is available only for tls")) do
207
+ @d.__send__(m, :myserver, PORT, proto: proto, certopts: {}, **kwargs){|x| x }
208
+ end
209
+ end
210
+
211
+ data(
212
+ 'server_create tcp' => [:server_create, :tcp, {}],
213
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
214
+ # 'server_create tls' => [:server_create, :tls, {}],
215
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
216
+ # 'server_create_connection tls' => [:server_create_connection, :tls, {}],
217
+ )
218
+ test 'can bind specified IPv4 address' do |(m, proto, kwargs)|
219
+ @d.__send__(m, :myserver, PORT, proto: proto, bind: "127.0.0.1", **kwargs){|x| x }
220
+ assert_equal "127.0.0.1", @d._servers.first.bind
221
+ assert_equal "127.0.0.1", @d._servers.first.server.instance_eval{ instance_variable_defined?(:@listen_socket) ? @listen_socket : @_io }.addr[3]
222
+ end
223
+
224
+ data(
225
+ 'server_create tcp' => [:server_create, :tcp, {}],
226
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
227
+ # 'server_create tls' => [:server_create, :tls, {}],
228
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
229
+ # 'server_create_connection tls' => [:server_create_connection, :tls, {}],
230
+ )
231
+ test 'can bind specified IPv6 address' do |(m, proto, kwargs)| # if available
232
+ omit "IPv6 unavailable here" unless ipv6_enabled?
233
+ @d.__send__(m, :myserver, PORT, proto: proto, bind: "::1", **kwargs){|x| x }
234
+ assert_equal "::1", @d._servers.first.bind
235
+ assert_equal "::1", @d._servers.first.server.instance_eval{ instance_variable_defined?(:@listen_socket) ? @listen_socket : @_io }.addr[3]
236
+ end
237
+
238
+ data(
239
+ 'server_create tcp' => [:server_create, :tcp, {}],
240
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
241
+ # 'server_create tls' => [:server_create, :tls, {}],
242
+ # 'server_create unix' => [:server_create, :unix, {}],
243
+ 'server_create_connection tcp' => [:server_create, :tcp, {}],
244
+ # 'server_create_connection tls' => [:server_create, :tls, {}],
245
+ # 'server_create_connection unix' => [:server_create, :unix, {}],
246
+ )
247
+ test 'can create 2 or more servers which share same bind address and port if shared option is true' do |(m, proto, kwargs)|
248
+ begin
249
+ d2 = Dummy.new; d2.start; d2.after_start
250
+
251
+ assert_nothing_raised do
252
+ @d.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
253
+ d2.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
254
+ end
255
+ ensure
256
+ d2.stop; d2.before_shutdown; d2.shutdown; d2.after_shutdown; d2.close; d2.terminate
257
+ end
258
+ end
259
+
260
+ data(
261
+ 'server_create tcp' => [:server_create, :tcp, {}],
262
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
263
+ # 'server_create tls' => [:server_create, :tls, {}],
264
+ # 'server_create unix' => [:server_create, :unix, {}],
265
+ 'server_create_connection tcp' => [:server_create, :tcp, {}],
266
+ # 'server_create_connection tls' => [:server_create, :tls, {}],
267
+ # 'server_create_connection unix' => [:server_create, :unix, {}],
268
+ )
269
+ test 'cannot create 2 or more servers using same bind address and port if shared option is false' do |(m, proto, kwargs)|
270
+ begin
271
+ d2 = Dummy.new; d2.start; d2.after_start
272
+
273
+ assert_nothing_raised do
274
+ @d.__send__(m, :myserver, PORT, proto: proto, shared: false, **kwargs){|x| x }
275
+ end
276
+ assert_raise(Errno::EADDRINUSE, Errno::EACCES) do
277
+ d2.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
278
+ end
279
+ ensure
280
+ d2.stop; d2.before_shutdown; d2.shutdown; d2.after_shutdown; d2.close; d2.terminate
281
+ end
282
+ end
283
+ end
284
+
285
+ sub_test_case '#server_create' do
286
+ data(
287
+ 'tcp' => [:tcp, {}],
288
+ 'udp' => [:udp, {max_bytes: 128}],
289
+ # 'tls' => [:tls, {}],
290
+ # 'unix' => [:unix, {}],
291
+ )
292
+ test 'raise error if block argument is not specified or too many' do |(proto, kwargs)|
293
+ assert_raise(ArgumentError.new("BUG: block must have 1 or 2 arguments")) do
294
+ @d.server_create(:myserver, PORT, proto: proto, **kwargs){ 1 }
295
+ end
296
+ assert_raise(ArgumentError.new("BUG: block must have 1 or 2 arguments")) do
297
+ @d.server_create(:myserver, PORT, proto: proto, **kwargs){|sock, conn, what_is_this| 1 }
298
+ end
299
+ end
300
+
301
+ test 'creates udp server if specified in proto' do
302
+ @d.server_create(:myserver, PORT, proto: :udp, max_bytes: 512){|x| x }
303
+
304
+ created_server_info = @d._servers.first
305
+ assert_equal :udp, created_server_info.proto
306
+ created_server = created_server_info.server
307
+ assert created_server.is_a?(Fluent::PluginHelper::Server::EventHandler::UDPServer)
308
+ end
309
+ end
310
+
311
+ sub_test_case '#server_create_tcp' do
312
+ test 'can accept all keyword arguments valid for tcp server' do
313
+ assert_nothing_raised do
314
+ @d.server_create_tcp(:s, PORT, bind: '127.0.0.1', shared: false, resolve_name: true, linger_timeout: 10, backlog: 500) do |data, conn|
315
+ # ...
316
+ end
317
+ end
318
+ end
319
+
320
+ test 'creates a tcp server just to read data' do
321
+ received = ""
322
+ @d.server_create_tcp(:s, PORT) do |data|
323
+ received << data
324
+ end
325
+ 3.times do
326
+ sock = TCPSocket.new("127.0.0.1", PORT)
327
+ sock.puts "yay"
328
+ sock.puts "foo"
329
+ sock.close
330
+ end
331
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
332
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
333
+ end
334
+
335
+ test 'creates a tcp server to read and write data' do
336
+ received = ""
337
+ responses = []
338
+ @d.server_create_tcp(:s, PORT) do |data, conn|
339
+ received << data
340
+ conn.write "ack\n"
341
+ end
342
+ 3.times do
343
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
344
+ sock.puts "yay"
345
+ sock.puts "foo"
346
+ responses << sock.readline
347
+ end
348
+ end
349
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
350
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
351
+ assert_equal ["ack\n","ack\n","ack\n"], responses
352
+ end
353
+
354
+ test 'creates a tcp server to read and write data using IPv6' do
355
+ omit "IPv6 unavailable here" unless ipv6_enabled?
356
+
357
+ received = ""
358
+ responses = []
359
+ @d.server_create_tcp(:s, PORT, bind: "::1") do |data, conn|
360
+ received << data
361
+ conn.write "ack\n"
362
+ end
363
+ 3.times do
364
+ TCPSocket.open("::1", PORT) do |sock|
365
+ sock.puts "yay"
366
+ sock.puts "foo"
367
+ responses << sock.readline
368
+ end
369
+ end
370
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
371
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
372
+ assert_equal ["ack\n","ack\n","ack\n"], responses
373
+ end
374
+
375
+ test 'does not resolve name of client address in default' do
376
+ received = ""
377
+ sources = []
378
+ @d.server_create_tcp(:s, PORT) do |data, conn|
379
+ received << data
380
+ sources << conn.remote_host
381
+ end
382
+ 3.times do
383
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
384
+ sock.puts "yay"
385
+ end
386
+ end
387
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
388
+ assert_equal "yay\nyay\nyay\n", received
389
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
390
+ end
391
+
392
+ test 'does resolve name of client address if resolve_name is true' do
393
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
394
+
395
+ received = ""
396
+ sources = []
397
+ @d.server_create_tcp(:s, PORT, resolve_name: true) do |data, conn|
398
+ received << data
399
+ sources << conn.remote_host
400
+ end
401
+ 3.times do
402
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
403
+ sock.puts "yay"
404
+ end
405
+ end
406
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
407
+ assert_equal "yay\nyay\nyay\n", received
408
+ assert{ sources.all?{|s| s == hostname } }
409
+ end
410
+
411
+ test 'can keep connections alive for tcp if keepalive specified' do
412
+ # pend "not implemented yet"
413
+ end
414
+
415
+ test 'raises error if plugin registers data callback for connection object from #server_create' do
416
+ received = ""
417
+ errors = []
418
+ @d.server_create_tcp(:s, PORT) do |data, conn|
419
+ received << data
420
+ begin
421
+ conn.data{|d| received << d.upcase }
422
+ rescue => e
423
+ errors << e
424
+ end
425
+ end
426
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
427
+ sock.puts "foo"
428
+ end
429
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
430
+ assert_equal "foo\n", received
431
+ assert_equal 1, errors.size
432
+ assert_equal "data callback can be registered just once, but registered twice", errors.first.message
433
+ end
434
+
435
+ test 'can call write_complete callback if registered' do
436
+ buffer = ""
437
+ lines = []
438
+ responses = []
439
+ response_completes = []
440
+ @d.server_create_tcp(:s, PORT) do |data, conn|
441
+ conn.on(:write_complete){|c| response_completes << true }
442
+ buffer << data
443
+ if idx = buffer.index("\n")
444
+ lines << buffer.slice!(0,idx+1)
445
+ conn.write "ack\n"
446
+ end
447
+ end
448
+ 3.times do
449
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
450
+ sock.write "yay"
451
+ sock.write "foo\n"
452
+ begin
453
+ responses << sock.readline
454
+ rescue EOFError, IOError, Errno::ECONNRESET
455
+ # ignore
456
+ end
457
+ sock.close
458
+ end
459
+ end
460
+ waiting(10){ sleep 0.1 until lines.size == 3 && response_completes.size == 3 }
461
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
462
+ assert_equal ["ack\n","ack\n","ack\n"], responses
463
+ assert_equal [true, true, true], response_completes
464
+ end
465
+
466
+ test 'can call close callback if registered' do
467
+ buffer = ""
468
+ lines = []
469
+ callback_results = []
470
+ @d.server_create_tcp(:s, PORT) do |data, conn|
471
+ conn.on(:close){|c| callback_results << "closed" }
472
+ buffer << data
473
+ if idx = buffer.index("\n")
474
+ lines << buffer.slice!(0,idx+1)
475
+ conn.write "ack\n"
476
+ end
477
+ end
478
+ 3.times do
479
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
480
+ sock.write "yay"
481
+ sock.write "foo\n"
482
+ begin
483
+ while line = sock.readline
484
+ if line == "ack\n"
485
+ sock.close
486
+ end
487
+ end
488
+ rescue EOFError, IOError, Errno::ECONNRESET
489
+ # ignore
490
+ end
491
+ end
492
+ end
493
+ waiting(10){ sleep 0.1 until lines.size == 3 && callback_results.size == 3 }
494
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
495
+ assert_equal ["closed", "closed", "closed"], callback_results
496
+ end
497
+ end
498
+
499
+ sub_test_case '#server_create_udp' do
500
+ test 'can accept all keyword arguments valid for udp server' do
501
+ assert_nothing_raised do
502
+ @d.server_create_udp(:s, PORT, bind: '127.0.0.1', shared: false, resolve_name: true, max_bytes: 100, flags: 1) do |data, conn|
503
+ # ...
504
+ end
505
+ end
506
+ end
507
+
508
+ test 'creates a udp server just to read data' do
509
+ received = ""
510
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data|
511
+ received << data
512
+ end
513
+ bind_port = unused_port(protocol: :udp, bind: "127.0.0.1")
514
+ 3.times do
515
+ sock = UDPSocket.new(Socket::AF_INET)
516
+ sock.bind("127.0.0.1", bind_port)
517
+ sock.connect("127.0.0.1", PORT)
518
+ sock.puts "yay"
519
+ sock.puts "foo"
520
+ sock.close
521
+ end
522
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
523
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
524
+ end
525
+
526
+ test 'creates a udp server to read and write data' do
527
+ received = ""
528
+ responses = []
529
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
530
+ received << data
531
+ sock.write "ack\n"
532
+ end
533
+ bind_port = unused_port
534
+ 3.times do
535
+ begin
536
+ sock = UDPSocket.new(Socket::AF_INET)
537
+ sock.bind("127.0.0.1", bind_port)
538
+ sock.connect("127.0.0.1", PORT)
539
+ th = Thread.new do
540
+ while true
541
+ begin
542
+ in_data, _addr = sock.recvfrom_nonblock(16)
543
+ if in_data
544
+ responses << in_data
545
+ break
546
+ end
547
+ rescue IO::WaitReadable
548
+ IO.select([sock])
549
+ end
550
+ end
551
+ true
552
+ end
553
+ sock.write "yay\nfoo\n"
554
+ th.join(5)
555
+ ensure
556
+ sock.close
557
+ end
558
+ end
559
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
560
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
561
+ assert_equal ["ack\n","ack\n","ack\n"], responses
562
+ end
563
+
564
+ test 'creates a udp server to read and write data using IPv6' do
565
+ omit "IPv6 unavailable here" unless ipv6_enabled?
566
+
567
+ received = ""
568
+ responses = []
569
+ @d.server_create_udp(:s, PORT, bind: "::1", max_bytes: 128) do |data, sock|
570
+ received << data
571
+ sock.write "ack\n"
572
+ end
573
+ bind_port = unused_port
574
+ 3.times do
575
+ begin
576
+ sock = UDPSocket.new(Socket::AF_INET6)
577
+ sock.bind("::1", bind_port)
578
+ th = Thread.new do
579
+ responses << sock.recv(16)
580
+ true
581
+ end
582
+ sock.connect("::1", PORT)
583
+ sock.write "yay\nfoo\n"
584
+ th.join(5)
585
+ ensure
586
+ sock.close
587
+ end
588
+ end
589
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
590
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
591
+ assert_equal ["ack\n","ack\n","ack\n"], responses
592
+ end
593
+
594
+ test 'does not resolve name of client address in default' do
595
+ received = ""
596
+ sources = []
597
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
598
+ received << data
599
+ sources << sock.remote_host
600
+ end
601
+ 3.times do
602
+ sock = UDPSocket.new(Socket::AF_INET)
603
+ sock.connect("127.0.0.1", PORT)
604
+ sock.puts "yay"
605
+ sock.close
606
+ end
607
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
608
+ assert_equal "yay\nyay\nyay\n", received
609
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
610
+ end
611
+
612
+ test 'does resolve name of client address if resolve_name is true' do
613
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
614
+
615
+ received = ""
616
+ sources = []
617
+ @d.server_create_udp(:s, PORT, resolve_name: true, max_bytes: 128) do |data, sock|
618
+ received << data
619
+ sources << sock.remote_host
620
+ end
621
+ 3.times do
622
+ sock = UDPSocket.new(Socket::AF_INET)
623
+ sock.connect("127.0.0.1", PORT)
624
+ sock.puts "yay"
625
+ sock.close
626
+ end
627
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
628
+ assert_equal "yay\nyay\nyay\n", received
629
+ assert{ sources.all?{|s| s == hostname } }
630
+ end
631
+
632
+ test 'raises error if plugin registers data callback for connection object from #server_create' do
633
+ received = ""
634
+ errors = []
635
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
636
+ received << data
637
+ begin
638
+ sock.data{|d| received << d.upcase }
639
+ rescue => e
640
+ errors << e
641
+ end
642
+ end
643
+ sock = UDPSocket.new(Socket::AF_INET)
644
+ sock.connect("127.0.0.1", PORT)
645
+ sock.write "foo\n"
646
+ sock.close
647
+
648
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
649
+ assert_equal "foo\n", received
650
+ assert_equal 1, errors.size
651
+ assert_equal "BUG: this event is disabled for udp: data", errors.first.message
652
+ end
653
+
654
+ test 'raise error if plugin registers write_complete callback for udp' do
655
+ received = ""
656
+ errors = []
657
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
658
+ received << data
659
+ begin
660
+ sock.on(:write_complete){|conn| "" }
661
+ rescue => e
662
+ errors << e
663
+ end
664
+ end
665
+ sock = UDPSocket.new(Socket::AF_INET)
666
+ sock.connect("127.0.0.1", PORT)
667
+ sock.write "foo\n"
668
+ sock.close
669
+
670
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
671
+ assert_equal "foo\n", received
672
+ assert_equal 1, errors.size
673
+ assert_equal "BUG: this event is disabled for udp: write_complete", errors.first.message
674
+ end
675
+
676
+ test 'raises error if plugin registers close callback for udp' do
677
+ received = ""
678
+ errors = []
679
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
680
+ received << data
681
+ begin
682
+ sock.on(:close){|d| "" }
683
+ rescue => e
684
+ errors << e
685
+ end
686
+ end
687
+ sock = UDPSocket.new(Socket::AF_INET)
688
+ sock.connect("127.0.0.1", PORT)
689
+ sock.write "foo\n"
690
+ sock.close
691
+
692
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
693
+ assert_equal "foo\n", received
694
+ assert_equal 1, errors.size
695
+ assert_equal "BUG: this event is disabled for udp: close", errors.first.message
696
+ end
697
+ end
698
+
699
+ sub_test_case '#server_create_tls' do
700
+ # not implemented yet
701
+
702
+ # test 'can accept all keyword arguments valid for tcp/tls server'
703
+ # test 'creates a tls server just to read data'
704
+ # test 'creates a tls server to read and write data'
705
+ # test 'creates a tls server to read and write data using IPv6'
706
+
707
+ # many tests about certops
708
+
709
+ # test 'does not resolve name of client address in default'
710
+ # test 'does resolve name of client address if resolve_name is true'
711
+ # test 'can keep connections alive for tls if keepalive specified' do
712
+ # pend "not implemented yet"
713
+ # end
714
+
715
+ # test 'raises error if plugin registers data callback for connection object from #server_create'
716
+ # test 'can call write_complete callback if registered'
717
+ # test 'can call close callback if registered'
718
+ end
719
+
720
+ sub_test_case '#server_create_unix' do
721
+ # not implemented yet
722
+
723
+ # test 'can accept all keyword arguments valid for unix server'
724
+ # test 'creates a unix server just to read data'
725
+ # test 'creates a unix server to read and write data'
726
+
727
+ # test 'raises error if plugin registers data callback for connection object from #server_create'
728
+ # test 'can call write_complete callback if registered'
729
+ # test 'can call close callback if registered'
730
+ end
731
+
732
+ # run tests for tcp, tls and unix
733
+ sub_test_case '#server_create_connection' do
734
+ test 'raise error if udp is specified in proto' do
735
+ assert_raise(ArgumentError.new("BUG: cannot create connection for UDP")) do
736
+ @d.server_create_connection(:myserver, PORT, proto: :udp){|c| c }
737
+ end
738
+ end
739
+
740
+ # def server_create_connection(title, port, proto: :tcp, bind: '0.0.0.0', shared: true, certopts: nil, resolve_name: false, linger_timeout: 0, backlog: nil, &block)
741
+ protocols = {
742
+ 'tcp' => [:tcp, {}],
743
+ # 'tls' => [:tls, {certopts: {}}],
744
+ # 'unix' => [:unix, {path: ""}],
745
+ }
746
+
747
+ data(protocols)
748
+ test 'raise error if block argument is not specified or too many' do |(proto, kwargs)|
749
+ empty_block = ->(){}
750
+ assert_raise(ArgumentError.new("BUG: block must have just one argument")) do
751
+ @d.server_create_connection(:myserver, PORT, proto: proto, **kwargs, &empty_block)
752
+ end
753
+ assert_raise(ArgumentError.new("BUG: block must have just one argument")) do
754
+ @d.server_create_connection(:myserver, PORT, proto: proto, **kwargs){|conn, what_is_this| [conn, what_is_this] }
755
+ end
756
+ end
757
+
758
+ data(protocols)
759
+ test 'does not resolve name of client address in default' do |(proto, kwargs)|
760
+ received = ""
761
+ sources = []
762
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
763
+ sources << conn.remote_host
764
+ conn.data do |d|
765
+ received << d
766
+ end
767
+ end
768
+ 3.times do
769
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
770
+ sock.puts "yay"
771
+ end
772
+ end
773
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
774
+ assert_equal "yay\nyay\nyay\n", received
775
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
776
+ end
777
+
778
+ data(protocols)
779
+ test 'does resolve name of client address if resolve_name is true' do |(proto, kwargs)|
780
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
781
+
782
+ received = ""
783
+ sources = []
784
+ @d.server_create_connection(:s, PORT, proto: proto, resolve_name: true, **kwargs) do |conn|
785
+ sources << conn.remote_host
786
+ conn.data do |d|
787
+ received << d
788
+ end
789
+ end
790
+ 3.times do
791
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
792
+ sock.puts "yay"
793
+ end
794
+ end
795
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
796
+ assert_equal "yay\nyay\nyay\n", received
797
+ assert{ sources.all?{|s| s == hostname } }
798
+ end
799
+
800
+ data(protocols)
801
+ test 'creates a server to provide connection, which can read, write and close' do |(proto, kwargs)|
802
+ lines = []
803
+ buffer = ""
804
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
805
+ conn.data do |d|
806
+ buffer << d
807
+ if buffer == "x"
808
+ buffer.slice!(0, 1)
809
+ conn.close
810
+ end
811
+ if idx = buffer.index("\n")
812
+ lines << buffer.slice!(0, idx + 1)
813
+ conn.write "foo!\n"
814
+ end
815
+ end
816
+ end
817
+ replied = []
818
+ disconnecteds = []
819
+ 3.times do
820
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
821
+ sock.puts "yay"
822
+ while line = sock.readline
823
+ replied << line
824
+ break
825
+ end
826
+ sock.write "x"
827
+ begin
828
+ sock.read
829
+ rescue => e
830
+ if e.is_a?(Errno::ECONNRESET)
831
+ disconnecteds << e.class
832
+ end
833
+ end
834
+ end
835
+ end
836
+ waiting(10){ sleep 0.1 until lines.size == 3 }
837
+ waiting(10){ sleep 0.1 until replied.size == 3 }
838
+ waiting(10){ sleep 0.1 until disconnecteds.size == 3 }
839
+ assert_equal ["yay\n", "yay\n", "yay\n"], lines
840
+ assert_equal ["foo!\n", "foo!\n", "foo!\n"], replied
841
+ assert_equal [Errno::ECONNRESET, Errno::ECONNRESET, Errno::ECONNRESET], disconnecteds
842
+ end
843
+
844
+ data(protocols)
845
+ test 'creates a server to provide connection, which accepts callbacks for data, write_complete, and close' do |(proto, kwargs)|
846
+ lines = []
847
+ buffer = ""
848
+ written = 0
849
+ closed = 0
850
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
851
+ conn.on(:write_complete){|_conn| written += 1 }
852
+ conn.on(:close){|_conn| closed += 1 }
853
+ conn.on(:data) do |d|
854
+ buffer << d
855
+ if idx = buffer.index("\n")
856
+ lines << buffer.slice!(0, idx + 1)
857
+ conn.write "foo!\n"
858
+ end
859
+ end
860
+ end
861
+ replied = []
862
+ 3.times do
863
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
864
+ sock.puts "yay"
865
+ while line = sock.readline
866
+ replied << line
867
+ break
868
+ end
869
+ end # TCP socket is closed here
870
+ end
871
+ waiting(10){ sleep 0.1 until lines.size == 3 }
872
+ waiting(10){ sleep 0.1 until replied.size == 3 }
873
+ waiting(10){ sleep 0.1 until closed == 3 }
874
+ assert_equal ["yay\n", "yay\n", "yay\n"], lines
875
+ assert_equal 3, written
876
+ assert_equal 3, closed
877
+ assert_equal ["foo!\n", "foo!\n", "foo!\n"], replied
878
+ end
879
+
880
+ data(protocols)
881
+ test 'creates a server, and does not leak connections' do |(proto, kwargs)|
882
+ buffer = ""
883
+ closed = 0
884
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
885
+ conn.on(:close){|_c| closed += 1 }
886
+ conn.on(:data) do |d|
887
+ buffer << d
888
+ end
889
+ end
890
+ 3.times do
891
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
892
+ sock.puts "yay"
893
+ end
894
+ end
895
+ waiting(10){ sleep 0.1 until buffer.bytesize == 12 }
896
+ waiting(10){ sleep 0.1 until closed == 3 }
897
+ assert_equal 0, @d.instance_eval{ @_server_connections.size }
898
+ end
899
+
900
+ test 'can keep connections alive for tcp/tls if keepalive specified' do
901
+ # pend "not implemented yet"
902
+ end
903
+ end
904
+
905
+ end