fluentd 1.15.2-x86-mingw32 → 1.16.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.yaml +1 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.yaml +1 -0
  4. data/.github/workflows/linux-test.yaml +2 -2
  5. data/.github/workflows/macos-test.yaml +2 -2
  6. data/.github/workflows/stale-actions.yml +11 -9
  7. data/.github/workflows/windows-test.yaml +2 -2
  8. data/CHANGELOG.md +133 -0
  9. data/CONTRIBUTING.md +1 -1
  10. data/MAINTAINERS.md +5 -3
  11. data/README.md +0 -1
  12. data/SECURITY.md +5 -9
  13. data/fluentd.gemspec +2 -2
  14. data/lib/fluent/command/fluentd.rb +55 -64
  15. data/lib/fluent/config/yaml_parser/loader.rb +18 -1
  16. data/lib/fluent/daemon.rb +2 -4
  17. data/lib/fluent/event.rb +2 -2
  18. data/lib/fluent/file_wrapper.rb +137 -0
  19. data/lib/fluent/log/console_adapter.rb +66 -0
  20. data/lib/fluent/log.rb +35 -5
  21. data/lib/fluent/oj_options.rb +1 -2
  22. data/lib/fluent/plugin/base.rb +5 -7
  23. data/lib/fluent/plugin/buf_file.rb +32 -3
  24. data/lib/fluent/plugin/buf_file_single.rb +32 -3
  25. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  26. data/lib/fluent/plugin/buffer.rb +21 -0
  27. data/lib/fluent/plugin/in_tail.rb +1 -6
  28. data/lib/fluent/plugin/in_tcp.rb +47 -2
  29. data/lib/fluent/plugin/out_file.rb +0 -4
  30. data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
  31. data/lib/fluent/plugin/out_forward.rb +2 -2
  32. data/lib/fluent/plugin/out_secondary_file.rb +39 -22
  33. data/lib/fluent/plugin/output.rb +49 -12
  34. data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
  35. data/lib/fluent/plugin_helper/server.rb +8 -0
  36. data/lib/fluent/supervisor.rb +157 -232
  37. data/lib/fluent/test/driver/base.rb +11 -5
  38. data/lib/fluent/test/driver/filter.rb +4 -0
  39. data/lib/fluent/test/startup_shutdown.rb +6 -8
  40. data/lib/fluent/version.rb +1 -1
  41. data/templates/new_gem/test/helper.rb.erb +0 -1
  42. data/test/command/test_ctl.rb +1 -1
  43. data/test/command/test_fluentd.rb +168 -22
  44. data/test/command/test_plugin_config_formatter.rb +0 -1
  45. data/test/compat/test_parser.rb +5 -5
  46. data/test/config/test_system_config.rb +0 -8
  47. data/test/log/test_console_adapter.rb +110 -0
  48. data/test/plugin/out_forward/test_ack_handler.rb +39 -0
  49. data/test/plugin/test_base.rb +98 -0
  50. data/test/plugin/test_buf_file.rb +62 -23
  51. data/test/plugin/test_buf_file_single.rb +65 -0
  52. data/test/plugin/test_in_http.rb +2 -3
  53. data/test/plugin/test_in_monitor_agent.rb +2 -3
  54. data/test/plugin/test_in_tail.rb +105 -103
  55. data/test/plugin/test_in_tcp.rb +87 -2
  56. data/test/plugin/test_in_udp.rb +28 -0
  57. data/test/plugin/test_out_file.rb +3 -2
  58. data/test/plugin/test_out_forward.rb +14 -18
  59. data/test/plugin/test_out_http.rb +1 -0
  60. data/test/plugin/test_output.rb +269 -0
  61. data/test/plugin/test_output_as_buffered_compress.rb +32 -18
  62. data/test/plugin/test_parser_regexp.rb +1 -6
  63. data/test/plugin_helper/test_http_server_helper.rb +1 -1
  64. data/test/plugin_helper/test_server.rb +59 -5
  65. data/test/test_config.rb +57 -21
  66. data/test/{plugin/test_file_wrapper.rb → test_file_wrapper.rb} +2 -2
  67. data/test/test_formatter.rb +23 -20
  68. data/test/test_log.rb +85 -40
  69. data/test/test_supervisor.rb +300 -283
  70. metadata +15 -23
  71. data/.drone.yml +0 -35
  72. data/.github/workflows/issue-auto-closer.yml +0 -12
  73. data/.gitlab-ci.yml +0 -103
  74. data/lib/fluent/plugin/file_wrapper.rb +0 -131
  75. data/test/test_logger_initializer.rb +0 -46
@@ -16,14 +16,20 @@ class ServerPluginHelperTest < Test::Unit::TestCase
16
16
 
17
17
  setup do
18
18
  @port = unused_port
19
- @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
20
- if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
21
- FileUtils.rm_f @socket_manager_path
19
+ if Fluent.windows?
20
+ @socket_manager_server = ServerEngine::SocketManager::Server.open
21
+ @socket_manager_path = @socket_manager_server.path
22
+ else
23
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
24
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
25
+ FileUtils.rm_f @socket_manager_path
26
+ end
27
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
22
28
  end
23
- @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
24
29
  ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
25
30
 
26
31
  @d = Dummy.new
32
+ @d.under_plugin_development = true
27
33
  @d.start
28
34
  @d.after_start
29
35
  end
@@ -37,7 +43,7 @@ class ServerPluginHelperTest < Test::Unit::TestCase
37
43
  (@d.terminated? || @d.terminate) rescue nil
38
44
 
39
45
  @socket_manager_server.close
40
- if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
46
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
41
47
  FileUtils.rm_f @socket_manager_path
42
48
  end
43
49
  end
@@ -789,6 +795,50 @@ class ServerPluginHelperTest < Test::Unit::TestCase
789
795
  end
790
796
  end
791
797
  end
798
+
799
+ sub_test_case 'over max_bytes' do
800
+ data("cut off on Non-Windows", { max_bytes: 32, records: ["a" * 40], expected: ["a" * 32] }, keep: true) unless Fluent.windows?
801
+ data("drop on Windows", { max_bytes: 32, records: ["a" * 40], expected: [] }, keep: true) if Fluent.windows?
802
+ test 'with sock' do |data|
803
+ max_bytes, records, expected = data.values
804
+
805
+ actual_records = []
806
+ @d.server_create_udp(:myserver, @port, max_bytes: max_bytes) do |data, sock|
807
+ actual_records << data
808
+ end
809
+
810
+ open_client(:udp, "127.0.0.1", @port) do |sock|
811
+ records.each do |record|
812
+ sock.send(record, 0)
813
+ end
814
+ end
815
+
816
+ waiting(10) { sleep 0.1 until actual_records.size >= expected.size }
817
+ sleep 1 if expected.size == 0 # To confirm no record recieved.
818
+
819
+ assert_equal expected, actual_records
820
+ end
821
+
822
+ test 'without sock' do |data|
823
+ max_bytes, records, expected = data.values
824
+
825
+ actual_records = []
826
+ @d.server_create_udp(:myserver, @port, max_bytes: max_bytes) do |data|
827
+ actual_records << data
828
+ end
829
+
830
+ open_client(:udp, "127.0.0.1", @port) do |sock|
831
+ records.each do |record|
832
+ sock.send(record, 0)
833
+ end
834
+ end
835
+
836
+ waiting(10) { sleep 0.1 until actual_records.size >= expected.size }
837
+ sleep 1 if expected.size == 0 # To confirm no record recieved.
838
+
839
+ assert_equal expected, actual_records
840
+ end
841
+ end
792
842
  end
793
843
 
794
844
  module CertUtil
@@ -1570,6 +1620,10 @@ class ServerPluginHelperTest < Test::Unit::TestCase
1570
1620
 
1571
1621
  def open_client(proto, addr, port)
1572
1622
  client = case proto
1623
+ when :udp
1624
+ c = UDPSocket.open
1625
+ c.connect(addr, port)
1626
+ c
1573
1627
  when :tcp
1574
1628
  TCPSocket.open(addr, port)
1575
1629
  when :tls
data/test/test_config.rb CHANGED
@@ -237,6 +237,63 @@ class ConfigTest < Test::Unit::TestCase
237
237
  ])
238
238
  end
239
239
 
240
+ def test_included_glob
241
+ write_config "#{TMP_DIR}/config.yaml", <<-EOS
242
+ config:
243
+ - !include "include/*.yaml"
244
+ EOS
245
+ write_config "#{TMP_DIR}/include/02_source2.yaml", <<-EOS
246
+ - source:
247
+ $type: dummy
248
+ tag: tag.dummy
249
+ EOS
250
+ write_config "#{TMP_DIR}/include/01_source1.yaml", <<-EOS
251
+ - source:
252
+ $type: tcp
253
+ tag: tag.tcp
254
+ parse:
255
+ $arg:
256
+ - why.parse.section.doesnot.have.arg
257
+ - huh
258
+ $type: none
259
+ EOS
260
+ write_config "#{TMP_DIR}/include/03_match1.yaml", <<-EOS
261
+ - match:
262
+ $tag: tag.*
263
+ $type: stdout
264
+ buffer:
265
+ $type: memory
266
+ flush_interval: 1s
267
+ EOS
268
+ root_conf = read_config("#{TMP_DIR}/config.yaml", use_yaml: true)
269
+ tcp_source_conf = root_conf.elements.first
270
+ dummy_source_conf = root_conf.elements[1]
271
+ parse_tcp_conf = tcp_source_conf.elements.first
272
+ match_conf = root_conf.elements[2]
273
+
274
+ assert_equal(
275
+ [
276
+ 'tcp',
277
+ 'tag.tcp',
278
+ 'none',
279
+ 'why.parse.section.doesnot.have.arg,huh',
280
+ 'dummy',
281
+ 'tag.dummy',
282
+ 'stdout',
283
+ 'tag.*',
284
+ ],
285
+ [
286
+ tcp_source_conf['@type'],
287
+ tcp_source_conf['tag'],
288
+ parse_tcp_conf['@type'],
289
+ parse_tcp_conf.arg,
290
+ dummy_source_conf['@type'],
291
+ dummy_source_conf['tag'],
292
+ match_conf['@type'],
293
+ match_conf.arg,
294
+ ])
295
+ end
296
+
240
297
  def test_check_not_fetchd
241
298
  write_config "#{TMP_DIR}/config_test_not_fetched.yaml", <<-EOS
242
299
  config:
@@ -287,27 +344,6 @@ class ConfigTest < Test::Unit::TestCase
287
344
  File.open(path, "w:#{encoding}:utf-8") {|f| f.write data }
288
345
  end
289
346
 
290
- def test_inline
291
- prepare_config
292
- opts = {
293
- :config_path => "#{TMP_DIR}/config_test_1.conf",
294
- :inline_config => "<source>\n type http\n port 2222\n </source>",
295
- :use_v1_config => false
296
- }
297
- assert_nothing_raised do
298
- Fluent::Supervisor.new(opts)
299
- end
300
- create_warn_dummy_logger
301
- end
302
-
303
- def create_warn_dummy_logger
304
- dl_opts = {}
305
- dl_opts[:log_level] = ServerEngine::DaemonLogger::WARN
306
- logdev = Fluent::Test::DummyLogDevice.new
307
- logger = ServerEngine::DaemonLogger.new(logdev, dl_opts)
308
- $log = Fluent::Log.new(logger)
309
- end
310
-
311
347
  sub_test_case '.build' do
312
348
  test 'read config' do
313
349
  write_config("#{TMP_DIR}/build/config_build.conf", 'key value')
@@ -1,5 +1,5 @@
1
- require_relative '../helper'
2
- require 'fluent/plugin/file_wrapper'
1
+ require_relative 'helper'
2
+ require 'fluent/file_wrapper'
3
3
 
4
4
  class FileWrapperTest < Test::Unit::TestCase
5
5
  TMP_DIR = File.dirname(__FILE__) + "/../tmp/file_wrapper#{ENV['TEST_ENV_NUMBER']}"
@@ -18,7 +18,7 @@ module FormatterTest
18
18
 
19
19
  def test_call
20
20
  formatter = Formatter.new
21
- formatter.configure({})
21
+ formatter.configure(config_element())
22
22
  assert_raise NotImplementedError do
23
23
  formatter.format('tag', Engine.now, {})
24
24
  end
@@ -130,7 +130,7 @@ module FormatterTest
130
130
  include FormatterTest
131
131
 
132
132
  def setup
133
- @formatter = TextFormatter::MessagePackFormatter.new
133
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::MessagePackFormatter)
134
134
  @time = Engine.now
135
135
  end
136
136
 
@@ -146,7 +146,7 @@ module FormatterTest
146
146
  include FormatterTest
147
147
 
148
148
  def setup
149
- @formatter = TextFormatter::LabeledTSVFormatter.new
149
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::LabeledTSVFormatter)
150
150
  @time = Engine.now
151
151
  @newline = if Fluent.windows?
152
152
  "\r\n"
@@ -156,16 +156,16 @@ module FormatterTest
156
156
  end
157
157
 
158
158
  def test_config_params
159
- assert_equal "\t", @formatter.delimiter
160
- assert_equal ":", @formatter.label_delimiter
159
+ assert_equal "\t", @formatter.instance.delimiter
160
+ assert_equal ":", @formatter.instance.label_delimiter
161
161
 
162
162
  @formatter.configure(
163
163
  'delimiter' => ',',
164
164
  'label_delimiter' => '=',
165
165
  )
166
166
 
167
- assert_equal ",", @formatter.delimiter
168
- assert_equal "=", @formatter.label_delimiter
167
+ assert_equal ",", @formatter.instance.delimiter
168
+ assert_equal "=", @formatter.instance.label_delimiter
169
169
  end
170
170
 
171
171
  def test_format
@@ -220,14 +220,14 @@ module FormatterTest
220
220
  include FormatterTest
221
221
 
222
222
  def setup
223
- @formatter = TextFormatter::CsvFormatter.new
223
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::CsvFormatter)
224
224
  @time = Engine.now
225
225
  end
226
226
 
227
227
  def test_config_params
228
- assert_equal ',', @formatter.delimiter
229
- assert_equal true, @formatter.force_quotes
230
- assert_nil @formatter.fields
228
+ assert_equal ',', @formatter.instance.delimiter
229
+ assert_equal true, @formatter.instance.force_quotes
230
+ assert_nil @formatter.instance.fields
231
231
  end
232
232
 
233
233
  data(
@@ -237,8 +237,8 @@ module FormatterTest
237
237
  def test_config_params_with_customized_delimiters(data)
238
238
  expected, target = data
239
239
  @formatter.configure('delimiter' => target, 'fields' => 'a,b,c')
240
- assert_equal expected, @formatter.delimiter
241
- assert_equal ['a', 'b', 'c'], @formatter.fields
240
+ assert_equal expected, @formatter.instance.delimiter
241
+ assert_equal ['a', 'b', 'c'], @formatter.instance.fields
242
242
  end
243
243
 
244
244
  def test_format
@@ -299,7 +299,7 @@ module FormatterTest
299
299
  'blank' => 'one,,two,three')
300
300
  def test_config_params_with_fields(data)
301
301
  @formatter.configure('fields' => data)
302
- assert_equal %w(one two three), @formatter.fields
302
+ assert_equal %w(one two three), @formatter.instance.fields
303
303
  end
304
304
  end
305
305
 
@@ -313,31 +313,34 @@ module FormatterTest
313
313
  end
314
314
  end
315
315
 
316
+ def create_driver(klass_or_str)
317
+ Fluent::Test::FormatterTestDriver.new(klass_or_str)
318
+ end
316
319
 
317
320
  def test_config_params
318
- formatter = TextFormatter::SingleValueFormatter.new
319
- assert_equal "message", formatter.message_key
321
+ formatter = create_driver(TextFormatter::SingleValueFormatter)
322
+ assert_equal "message", formatter.instance.message_key
320
323
 
321
324
  formatter.configure('message_key' => 'foobar')
322
- assert_equal "foobar", formatter.message_key
325
+ assert_equal "foobar", formatter.instance.message_key
323
326
  end
324
327
 
325
328
  def test_format
326
- formatter = Fluent::Plugin.new_formatter('single_value')
329
+ formatter = create_driver('single_value')
327
330
  formatter.configure({})
328
331
  formatted = formatter.format('tag', Engine.now, {'message' => 'awesome'})
329
332
  assert_equal("awesome#{@newline}", formatted)
330
333
  end
331
334
 
332
335
  def test_format_without_newline
333
- formatter = Fluent::Plugin.new_formatter('single_value')
336
+ formatter = create_driver('single_value')
334
337
  formatter.configure('add_newline' => 'false')
335
338
  formatted = formatter.format('tag', Engine.now, {'message' => 'awesome'})
336
339
  assert_equal("awesome", formatted)
337
340
  end
338
341
 
339
342
  def test_format_with_message_key
340
- formatter = TextFormatter::SingleValueFormatter.new
343
+ formatter = create_driver(TextFormatter::SingleValueFormatter)
341
344
  formatter.configure('message_key' => 'foobar')
342
345
  formatted = formatter.format('tag', Engine.now, {'foobar' => 'foo'})
343
346
 
data/test/test_log.rb CHANGED
@@ -4,13 +4,17 @@ require 'fluent/engine'
4
4
  require 'fluent/log'
5
5
  require 'timecop'
6
6
  require 'logger'
7
+ require 'securerandom'
8
+ require 'pathname'
7
9
 
8
10
  class LogTest < Test::Unit::TestCase
9
- TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/tmp/log/#{ENV['TEST_ENV_NUMBER']}")
11
+ def tmp_dir
12
+ File.join(File.dirname(__FILE__), "tmp", "log", "#{ENV['TEST_ENV_NUMBER']}", SecureRandom.hex(10))
13
+ end
10
14
 
11
15
  def setup
12
- FileUtils.rm_rf(TMP_DIR)
13
- FileUtils.mkdir_p(TMP_DIR)
16
+ @tmp_dir = tmp_dir
17
+ FileUtils.mkdir_p(@tmp_dir)
14
18
  @log_device = Fluent::Test::DummyLogDevice.new
15
19
  @timestamp = Time.parse("2016-04-21 02:58:41 +0000")
16
20
  @timestamp_str = @timestamp.strftime("%Y-%m-%d %H:%M:%S %z")
@@ -21,6 +25,21 @@ class LogTest < Test::Unit::TestCase
21
25
  @log_device.reset
22
26
  Timecop.return
23
27
  Thread.current[:last_repeated_stacktrace] = nil
28
+ begin
29
+ FileUtils.rm_rf(@tmp_dir)
30
+ rescue Errno::EACCES
31
+ # It may occur on Windows because of delete pending state due to delayed GC.
32
+ # Ruby 3.2 or later doesn't ignore Errno::EACCES:
33
+ # https://github.com/ruby/ruby/commit/983115cf3c8f75b1afbe3274f02c1529e1ce3a81
34
+ end
35
+ end
36
+
37
+ def test_per_process_path
38
+ path = Fluent::Log.per_process_path("C:/tmp/test.log", :supervisor, 0)
39
+ assert_equal(path, "C:/tmp/test-supervisor-0.log")
40
+
41
+ path = Fluent::Log.per_process_path("C:/tmp/test.log", :worker, 1)
42
+ assert_equal(path, "C:/tmp/test-1.log")
24
43
  end
25
44
 
26
45
  sub_test_case "log level" do
@@ -560,7 +579,7 @@ class LogTest < Test::Unit::TestCase
560
579
  Timecop.freeze(@timestamp)
561
580
 
562
581
  rotate_age, rotate_size, travel_term = expected
563
- path = "#{TMP_DIR}/log-dev-io-#{rotate_size}-#{rotate_age}"
582
+ path = "#{@tmp_dir}/log-dev-io-#{rotate_size}-#{rotate_age}"
564
583
 
565
584
  logdev = Fluent::LogDeviceIO.new(path, shift_age: rotate_age, shift_size: rotate_size)
566
585
  logger = ServerEngine::DaemonLogger.new(logdev)
@@ -583,45 +602,71 @@ class LogTest < Test::Unit::TestCase
583
602
 
584
603
  def test_log_rotates_specified_size_with_logdevio
585
604
  with_timezone('utc') do
586
- rotate_age = 2
587
- rotate_size = 100
588
- path = "#{TMP_DIR}/log-dev-io-#{rotate_size}-#{rotate_age}"
589
- path0 = path + '.0'
590
- path1 = path + '.1'
605
+ begin
606
+ rotate_age = 2
607
+ rotate_size = 100
608
+ path = "#{@tmp_dir}/log-dev-io-#{rotate_size}-#{rotate_age}"
609
+ path0 = path + '.0'
610
+ path1 = path + '.1'
611
+
612
+ logdev = Fluent::LogDeviceIO.new(path, shift_age: rotate_age, shift_size: rotate_size)
613
+ logger = ServerEngine::DaemonLogger.new(logdev)
614
+ log = Fluent::Log.new(logger)
615
+
616
+ msg = 'a' * 101
617
+ log.info msg
618
+ assert_match msg, File.read(path)
619
+ assert_true File.exist?(path)
620
+ assert_true !File.exist?(path0)
621
+ assert_true !File.exist?(path1)
622
+
623
+ # create log.0
624
+ msg2 = 'b' * 101
625
+ log.info msg2
626
+ c = File.read(path)
627
+ c0 = File.read(path0)
628
+ assert_match msg2, c
629
+ assert_match msg, c0
630
+ assert_true File.exist?(path)
631
+ assert_true File.exist?(path0)
632
+ assert_true !File.exist?(path1)
633
+
634
+ # rotate
635
+ msg3 = 'c' * 101
636
+ log.info msg3
637
+ c = File.read(path)
638
+ c0 = File.read(path0)
639
+ assert_match msg3, c
640
+ assert_match msg2, c0
641
+ assert_true File.exist?(path)
642
+ assert_true File.exist?(path0)
643
+ assert_true !File.exist?(path1)
644
+ ensure
645
+ logdev&.close
646
+ end
647
+ end
648
+ end
591
649
 
592
- logdev = Fluent::LogDeviceIO.new(path, shift_age: rotate_age, shift_size: rotate_size)
593
- logger = ServerEngine::DaemonLogger.new(logdev)
594
- log = Fluent::Log.new(logger)
650
+ def test_reopen
651
+ path = Pathname(@tmp_dir) + "fluent.log"
595
652
 
596
- msg = 'a' * 101
597
- log.info msg
598
- assert_match msg, File.read(path)
599
- assert_true File.exist?(path)
600
- assert_true !File.exist?(path0)
601
- assert_true !File.exist?(path1)
653
+ logdev = Fluent::LogDeviceIO.new(path.to_s)
654
+ logger = ServerEngine::DaemonLogger.new(logdev)
655
+ log = Fluent::Log.new(logger, path: path)
602
656
 
603
- # create log.0
604
- msg2 = 'b' * 101
605
- log.info msg2
606
- c = File.read(path)
607
- c0 = File.read(path0)
608
- assert_match msg2, c
609
- assert_match msg, c0
610
- assert_true File.exist?(path)
611
- assert_true File.exist?(path0)
612
- assert_true !File.exist?(path1)
613
-
614
- # rotate
615
- msg3 = 'c' * 101
616
- log.info msg3
617
- c = File.read(path)
618
- c0 = File.read(path0)
619
- assert_match msg3, c
620
- assert_match msg2, c0
621
- assert_true File.exist?(path)
622
- assert_true File.exist?(path0)
623
- assert_true !File.exist?(path1)
624
- end
657
+ message = "This is test message."
658
+
659
+ log.info message
660
+ log.reopen!
661
+ log.info message
662
+
663
+ assert { path.read.lines.select{ |line| line.include?(message) }.size == 2 }
664
+ # Assert reopening the same file.
665
+ # Especially, on Windows, the filepath is fixed for each process with rotate,
666
+ # so we need to care about this.
667
+ assert { path.parent.entries.size == 3 } # [".", "..", "fluent.log"]
668
+ ensure
669
+ logdev&.close
625
670
  end
626
671
  end
627
672