fluentd 1.12.0.rc2 → 1.12.4

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.deepsource.toml +13 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  4. data/.github/workflows/linux-test.yaml +36 -0
  5. data/.github/workflows/macos-test.yaml +30 -0
  6. data/.github/workflows/windows-test.yaml +35 -0
  7. data/.gitlab-ci.yml +41 -19
  8. data/CHANGELOG.md +157 -0
  9. data/MAINTAINERS.md +5 -2
  10. data/README.md +7 -4
  11. data/fluentd.gemspec +5 -4
  12. data/lib/fluent/command/bundler_injection.rb +1 -1
  13. data/lib/fluent/command/ca_generate.rb +6 -3
  14. data/lib/fluent/command/cat.rb +0 -1
  15. data/lib/fluent/command/fluentd.rb +4 -0
  16. data/lib/fluent/command/plugin_config_formatter.rb +16 -1
  17. data/lib/fluent/command/plugin_generator.rb +31 -1
  18. data/lib/fluent/compat/parser.rb +2 -2
  19. data/lib/fluent/config/section.rb +2 -2
  20. data/lib/fluent/config/types.rb +2 -2
  21. data/lib/fluent/event.rb +3 -13
  22. data/lib/fluent/load.rb +0 -1
  23. data/lib/fluent/plugin/file_wrapper.rb +39 -3
  24. data/lib/fluent/plugin/formatter_ltsv.rb +2 -2
  25. data/lib/fluent/plugin/in_http.rb +1 -1
  26. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  27. data/lib/fluent/plugin/in_tail.rb +35 -15
  28. data/lib/fluent/plugin/in_tail/position_file.rb +15 -1
  29. data/lib/fluent/plugin/in_tcp.rb +1 -0
  30. data/lib/fluent/plugin/out_copy.rb +18 -5
  31. data/lib/fluent/plugin/out_exec_filter.rb +3 -3
  32. data/lib/fluent/plugin/out_forward.rb +61 -28
  33. data/lib/fluent/plugin/out_http.rb +9 -2
  34. data/lib/fluent/plugin/output.rb +11 -9
  35. data/lib/fluent/plugin/parser_csv.rb +2 -2
  36. data/lib/fluent/plugin/parser_syslog.rb +2 -2
  37. data/lib/fluent/plugin/storage_local.rb +4 -4
  38. data/lib/fluent/plugin_helper/inject.rb +4 -2
  39. data/lib/fluent/plugin_helper/server.rb +4 -2
  40. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  41. data/lib/fluent/supervisor.rb +13 -5
  42. data/lib/fluent/system_config.rb +2 -1
  43. data/lib/fluent/time.rb +58 -1
  44. data/lib/fluent/version.rb +1 -1
  45. data/templates/new_gem/fluent-plugin.gemspec.erb +3 -3
  46. data/templates/plugin_config_formatter/param.md-table.erb +10 -0
  47. data/test/command/test_fluentd.rb +38 -0
  48. data/test/command/test_plugin_config_formatter.rb +67 -0
  49. data/test/config/test_configurable.rb +1 -1
  50. data/test/plugin/in_tail/test_position_file.rb +59 -5
  51. data/test/plugin/test_file_wrapper.rb +105 -0
  52. data/test/plugin/test_in_exec.rb +1 -1
  53. data/test/plugin/test_in_tail.rb +87 -26
  54. data/test/plugin/test_out_copy.rb +87 -0
  55. data/test/plugin/test_out_forward.rb +94 -6
  56. data/test/plugin/test_out_http.rb +20 -1
  57. data/test/plugin/test_output.rb +15 -3
  58. data/test/plugin/test_output_as_buffered_backup.rb +2 -0
  59. data/test/plugin/test_parser_csv.rb +14 -0
  60. data/test/plugin/test_parser_syslog.rb +16 -2
  61. data/test/plugin/test_sd_file.rb +1 -1
  62. data/test/plugin_helper/service_discovery/test_manager.rb +1 -1
  63. data/test/plugin_helper/test_child_process.rb +5 -2
  64. data/test/plugin_helper/test_http_server_helper.rb +4 -2
  65. data/test/plugin_helper/test_inject.rb +29 -0
  66. data/test/plugin_helper/test_server.rb +26 -7
  67. data/test/test_event.rb +16 -0
  68. data/test/test_formatter.rb +30 -0
  69. data/test/test_output.rb +2 -2
  70. data/test/test_supervisor.rb +31 -0
  71. data/test/test_time_parser.rb +109 -0
  72. metadata +36 -31
  73. data/.travis.yml +0 -77
  74. data/appveyor.yml +0 -31
@@ -27,7 +27,7 @@ module Fluent
27
27
  :log_event_verbose, :ignore_repeated_log_interval, :ignore_same_log_interval,
28
28
  :without_source, :rpc_endpoint, :enable_get_dump, :process_name,
29
29
  :file_permission, :dir_permission, :counter_server, :counter_client,
30
- :strict_config_value, :enable_msgpack_time_support
30
+ :strict_config_value, :enable_msgpack_time_support, :disable_shared_socket
31
31
  ]
32
32
 
33
33
  config_param :workers, :integer, default: 1
@@ -45,6 +45,7 @@ module Fluent
45
45
  config_param :process_name, :string, default: nil
46
46
  config_param :strict_config_value, :bool, default: nil
47
47
  config_param :enable_msgpack_time_support, :bool, default: nil
48
+ config_param :disable_shared_socket, :bool, default: nil
48
49
  config_param :file_permission, default: nil do |v|
49
50
  v.to_i(8)
50
51
  end
data/lib/fluent/time.rb CHANGED
@@ -50,6 +50,7 @@ module Fluent
50
50
  def to_int
51
51
  @sec
52
52
  end
53
+ alias :to_i :to_int
53
54
 
54
55
  def to_f
55
56
  @sec + @nsec / 1_000_000_000.0
@@ -131,13 +132,14 @@ module Fluent
131
132
  end
132
133
 
133
134
  module TimeMixin
134
- TIME_TYPES = ['string', 'unixtime', 'float']
135
+ TIME_TYPES = ['string', 'unixtime', 'float', 'mixed']
135
136
 
136
137
  TIME_PARAMETERS = [
137
138
  [:time_format, :string, {default: nil}],
138
139
  [:localtime, :bool, {default: true}], # UTC if :localtime is false and :timezone is nil
139
140
  [:utc, :bool, {default: false}], # to turn :localtime false
140
141
  [:timezone, :string, {default: nil}],
142
+ [:time_format_fallbacks, :array, {default: []}], # try time_format, then try fallbacks
141
143
  ]
142
144
  TIME_FULL_PARAMETERS = [
143
145
  # To avoid to define :time_type twice (in plugin_helper/inject)
@@ -169,6 +171,12 @@ module Fluent
169
171
  raise Fluent::ConfigError, "both of utc and localtime are specified, use only one of them"
170
172
  end
171
173
 
174
+ if conf.has_key?('time_type') and @time_type == :mixed
175
+ if @time_format.nil? and @time_format_fallbacks.empty?
176
+ raise Fluent::ConfigError, "time_type is :mixed but time_format and time_format_fallbacks is empty."
177
+ end
178
+ end
179
+
172
180
  Fluent::Timezone.validate!(@timezone) if @timezone
173
181
  end
174
182
  end
@@ -179,6 +187,7 @@ module Fluent
179
187
  end
180
188
 
181
189
  def time_parser_create(type: @time_type, format: @time_format, timezone: @timezone, force_localtime: false)
190
+ return MixedTimeParser.new(type, format, @localtime, timezone, @utc, force_localtime, @time_format_fallbacks) if type == :mixed
182
191
  return NumericTimeParser.new(type) if type != :string
183
192
  return TimeParser.new(format, true, nil) if force_localtime
184
193
 
@@ -451,4 +460,52 @@ module Fluent
451
460
  end
452
461
  end
453
462
  end
463
+
464
+ # MixedTimeParser is available when time_type is set to :mixed
465
+ #
466
+ # Use Case 1: primary format is specified explicitly in time_format
467
+ # time_type mixed
468
+ # time_format %iso8601
469
+ # time_format_fallbacks unixtime
470
+ # Use Case 2: time_format is omitted
471
+ # time_type mixed
472
+ # time_format_fallbacks %iso8601, unixtime
473
+ #
474
+ class MixedTimeParser < TimeParser # to include TimeParseError
475
+ def initialize(type, format = nil, localtime = nil, timezone = nil, utc = nil, force_localtime = nil, fallbacks = [])
476
+ @parsers = []
477
+ fallbacks.unshift(format).each do |fallback|
478
+ next unless fallback
479
+ case fallback
480
+ when 'unixtime', 'float'
481
+ @parsers << NumericTimeParser.new(fallback, localtime, timezone)
482
+ else
483
+ if force_localtime
484
+ @parsers << TimeParser.new(fallback, true, nil)
485
+ else
486
+ localtime = localtime && (timezone.nil? && !utc)
487
+ @parsers << TimeParser.new(fallback, localtime, timezone)
488
+ end
489
+ end
490
+ end
491
+ end
492
+
493
+ def parse(value)
494
+ @parsers.each do |parser|
495
+ begin
496
+ Float(value) if parser.class == Fluent::NumericTimeParser
497
+ rescue
498
+ next
499
+ end
500
+ begin
501
+ return parser.parse(value)
502
+ rescue
503
+ # skip TimeParseError
504
+ end
505
+ end
506
+ fallback_class = @parsers.collect do |parser| parser.class end.join(",")
507
+ raise TimeParseError, "invalid time format: value = #{value}, even though fallbacks: #{fallback_class}"
508
+ end
509
+ end
510
+
454
511
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.12.0.rc2'
19
+ VERSION = '1.12.4'
20
20
 
21
21
  end
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = test_files
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.14"
24
- spec.add_development_dependency "rake", "~> 12.0"
25
- spec.add_development_dependency "test-unit", "~> 3.0"
23
+ spec.add_development_dependency "bundler", "~> <%= bundler_version %>"
24
+ spec.add_development_dependency "rake", "~> <%= rake_version %>"
25
+ spec.add_development_dependency "test-unit", "~> <%= test_unit_version %>"
26
26
  spec.add_runtime_dependency "fluentd", [">= 0.14.10", "< 2"]
27
27
  end
@@ -0,0 +1,10 @@
1
+ <%-
2
+ type = config[:type]
3
+ required_label = config[:required] ? "required" : "optional"
4
+ default = config[:default]
5
+ alias_name = config[:alias]
6
+ deprecated = config[:deprecated]
7
+ obsoleted = config[:obsoleted]
8
+ description = config[:desc]
9
+ -%>
10
+ |<%= name %>|<%= type %> (<%= required_label %>)|<%= description %><%- if type == :enum -%> (<%= config[:list].map{|x| "`#{x}`"}.join(", ") %>)<%- end -%><%- if alias_name -%><br>Alias: <%= alias_name %><%- end -%><%- if deprecated -%><br>Deprecated: <%= deprecated %><%- end -%><%- if obsoleted -%><br>Obsoleted: <%= :obsoleted %><%- end -%>|<%- if default -%>`<%= default %>`<%- end -%>|
@@ -878,6 +878,8 @@ CONF
878
878
  end
879
879
 
880
880
  test "without RUBYOPT" do
881
+ saved_ruby_opt = ENV["RUBYOPT"]
882
+ ENV["RUBYOPT"] = nil
881
883
  conf = <<CONF
882
884
  <source>
883
885
  @type dummy
@@ -889,6 +891,8 @@ CONF
889
891
  CONF
890
892
  conf_path = create_conf_file('rubyopt_test.conf', conf)
891
893
  assert_log_matches(create_cmdline(conf_path), '-Eascii-8bit:ascii-8bit')
894
+ ensure
895
+ ENV["RUBYOPT"] = saved_ruby_opt
892
896
  end
893
897
 
894
898
  test 'invalid values are set to RUBYOPT' do
@@ -912,6 +916,8 @@ CONF
912
916
 
913
917
  # https://github.com/fluent/fluentd/issues/2915
914
918
  test "ruby path contains spaces" do
919
+ saved_ruby_opt = ENV["RUBYOPT"]
920
+ ENV["RUBYOPT"] = nil
915
921
  conf = <<CONF
916
922
  <source>
917
923
  @type dummy
@@ -940,6 +946,8 @@ CONF
940
946
  'spawn command to main:',
941
947
  '-Eascii-8bit:ascii-8bit'
942
948
  )
949
+ ensure
950
+ ENV["RUBYOPT"] = saved_ruby_opt
943
951
  end
944
952
 
945
953
  test 'success to start workers when file buffer is configured in non-workers way only for specific worker' do
@@ -1065,4 +1073,34 @@ CONF
1065
1073
  "secret xxxxxx", patterns_not_match: ["secret secret0", "secret secret1"])
1066
1074
  end
1067
1075
  end
1076
+
1077
+ sub_test_case 'sahred socket options' do
1078
+ test 'enable shared socket by default' do
1079
+ conf = ""
1080
+ conf_path = create_conf_file('empty.conf', conf)
1081
+ assert File.exist?(conf_path)
1082
+ assert_log_matches(create_cmdline(conf_path),
1083
+ patterns_not_match: ["shared socket for multiple workers is disabled"])
1084
+ end
1085
+
1086
+ test 'disable shared socket by command line option' do
1087
+ conf = ""
1088
+ conf_path = create_conf_file('empty.conf', conf)
1089
+ assert File.exist?(conf_path)
1090
+ assert_log_matches(create_cmdline(conf_path, "--disable-shared-socket"),
1091
+ "shared socket for multiple workers is disabled",)
1092
+ end
1093
+
1094
+ test 'disable shared socket by system config' do
1095
+ conf = <<CONF
1096
+ <system>
1097
+ disable_shared_socket
1098
+ </system>
1099
+ CONF
1100
+ conf_path = create_conf_file('empty.conf', conf)
1101
+ assert File.exist?(conf_path)
1102
+ assert_log_matches(create_cmdline(conf_path, "--disable-shared-socket"),
1103
+ "shared socket for multiple workers is disabled",)
1104
+ end
1105
+ end
1068
1106
  end
@@ -225,6 +225,30 @@ TEXT
225
225
  path to something
226
226
 
227
227
 
228
+ TEXT
229
+ assert_equal(expected, dumped_config)
230
+ end
231
+
232
+ test "input simple (table)" do
233
+ dumped_config = capture_stdout do
234
+ FluentPluginConfigFormatter.new(["--format=markdown", "--table", "input", "simple"]).call
235
+ end
236
+ expected = <<TEXT
237
+ ## Plugin helpers
238
+
239
+ * [inject](https://docs.fluentd.org/v/1.0/plugin-helper-overview/api-plugin-helper-inject)
240
+ * [compat_parameters](https://docs.fluentd.org/v/1.0/plugin-helper-overview/api-plugin-helper-compat_parameters)
241
+
242
+ * See also: [Input Plugin Overview](https://docs.fluentd.org/v/1.0/input#overview)
243
+
244
+ ## TestFluentPluginConfigFormatter::SimpleInput
245
+
246
+ ### Configuration
247
+
248
+ |parameter|type|description|default|
249
+ |---|---|---|---|
250
+ |path|string (required)|path to something||
251
+
228
252
  TEXT
229
253
  assert_equal(expected, dumped_config)
230
254
  end
@@ -298,6 +322,49 @@ Default value: `normal`.
298
322
 
299
323
 
300
324
 
325
+ TEXT
326
+ assert_equal(expected, dumped_config)
327
+ end
328
+
329
+ test "output complex (table)" do
330
+ dumped_config = capture_stdout do
331
+ FluentPluginConfigFormatter.new(["--format=markdown", "--table", "output", "complex"]).call
332
+ end
333
+ expected = <<TEXT
334
+ ## Plugin helpers
335
+
336
+ * [inject](https://docs.fluentd.org/v/1.0/plugin-helper-overview/api-plugin-helper-inject)
337
+ * [compat_parameters](https://docs.fluentd.org/v/1.0/plugin-helper-overview/api-plugin-helper-compat_parameters)
338
+
339
+ * See also: [Output Plugin Overview](https://docs.fluentd.org/v/1.0/output#overview)
340
+
341
+ ## TestFluentPluginConfigFormatter::ComplexOutput
342
+
343
+
344
+ ### \\<authentication\\> section (required) (single)
345
+
346
+ ### Configuration
347
+
348
+ |parameter|type|description|default|
349
+ |---|---|---|---|
350
+ |username|string (required)|username||
351
+ |password|string (required)|password||
352
+
353
+
354
+ ### \\<parent\\> section (optional) (multiple)
355
+
356
+
357
+ #### \\<child\\> section (optional) (multiple)
358
+
359
+ ### Configuration
360
+
361
+ |parameter|type|description|default|
362
+ |---|---|---|---|
363
+ |names|array (required)|names||
364
+ |difficulty|enum (optional)|difficulty (`easy`, `normal`, `hard`)|`normal`|
365
+
366
+
367
+
301
368
  TEXT
302
369
  assert_equal(expected, dumped_config)
303
370
  end
@@ -1453,7 +1453,7 @@ module Fluent::Config
1453
1453
  @example = ConfigurableSpec::ExampleWithSkipAccessor.new
1454
1454
  @example.configure(config_element('ROOT'))
1455
1455
  assert_equal 'example7', @example.instance_variable_get(:@name)
1456
- assert_raise NoMethodError.new("undefined method `name' for #{@example}") do
1456
+ assert_raise NoMethodError do
1457
1457
  @example.name
1458
1458
  end
1459
1459
  end
@@ -85,7 +85,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
85
85
  assert_equal 5, lines.size
86
86
  end
87
87
 
88
- test 'update seek postion of remained position entry' do
88
+ test 'update seek position of remained position entry' do
89
89
  pf = Fluent::Plugin::TailInput::PositionFile.new(@file, false, {}, **{logger: $log})
90
90
  target_info1 = Fluent::Plugin::TailInput::TargetInfo.new('path1', -1)
91
91
  target_info2 = Fluent::Plugin::TailInput::TargetInfo.new('path2', -1)
@@ -147,7 +147,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
147
147
  write_data(@file, TEST_CONTENT)
148
148
  pf = Fluent::Plugin::TailInput::PositionFile.load(@file, false, {}, **{logger: $log})
149
149
 
150
- valid_target_info = Fluent::Plugin::TailInput::TargetInfo.new('valid_path', Fluent::FileWrapper.stat(@file).ino)
150
+ valid_target_info = Fluent::Plugin::TailInput::TargetInfo.new('valid_path', File.stat(@file).ino)
151
151
  f = pf[valid_target_info]
152
152
  assert_equal Fluent::Plugin::TailInput::FilePositionEntry, f.class
153
153
  assert_equal 2, f.read_pos
@@ -177,7 +177,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
177
177
  assert_equal 0, f.read_inode
178
178
  assert_equal 0, f.read_pos
179
179
 
180
- pf[Fluent::Plugin::TailInput::TargetInfo.new('valid_path', Fluent::FileWrapper.stat(@file).ino)].update(1, 2)
180
+ pf[Fluent::Plugin::TailInput::TargetInfo.new('valid_path', File.stat(@file).ino)].update(1, 2)
181
181
 
182
182
  f = pf[Fluent::Plugin::TailInput::TargetInfo.new('nonexist_path', -1)]
183
183
  assert_equal 0, f.read_inode
@@ -193,7 +193,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
193
193
  test 'deletes entry by path' do
194
194
  write_data(@file, TEST_CONTENT)
195
195
  pf = Fluent::Plugin::TailInput::PositionFile.load(@file, false, {}, logger: $log)
196
- inode1 = Fluent::FileWrapper.stat(@file).ino
196
+ inode1 = File.stat(@file).ino
197
197
  target_info1 = Fluent::Plugin::TailInput::TargetInfo.new('valid_path', inode1)
198
198
  p1 = pf[target_info1]
199
199
  assert_equal Fluent::Plugin::TailInput::FilePositionEntry, p1.class
@@ -201,7 +201,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
201
201
  pf.unwatch(target_info1)
202
202
  assert_equal p1.read_pos, Fluent::Plugin::TailInput::PositionFile::UNWATCHED_POSITION
203
203
 
204
- inode2 = Fluent::FileWrapper.stat(@file).ino
204
+ inode2 = File.stat(@file).ino
205
205
  target_info2 = Fluent::Plugin::TailInput::TargetInfo.new('valid_path', inode2)
206
206
  p2 = pf[target_info2]
207
207
  assert_equal Fluent::Plugin::TailInput::FilePositionEntry, p2.class
@@ -282,4 +282,58 @@ class IntailPositionFileTest < Test::Unit::TestCase
282
282
  assert_equal 2, f.read_inode
283
283
  end
284
284
  end
285
+
286
+ sub_test_case "TargetInfo equality rules" do
287
+ sub_test_case "== operator" do
288
+ def test_equal
289
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1234)
290
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1235)
291
+
292
+ assert_equal t1, t2
293
+ end
294
+
295
+ def test_not_equal
296
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1234)
297
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test2", 1234)
298
+
299
+ assert_not_equal t1, t2
300
+ end
301
+ end
302
+
303
+ sub_test_case "eql? method" do
304
+ def test_eql?
305
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1234)
306
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test", 5321)
307
+
308
+ assert do
309
+ t1.eql? t2
310
+ end
311
+ end
312
+
313
+ def test_not_eql?
314
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test2", 1234)
315
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test3", 1234)
316
+
317
+ assert do
318
+ !t1.eql? t2
319
+ end
320
+ end
321
+ end
322
+
323
+ sub_test_case "hash" do
324
+ def test_equal
325
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1234)
326
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test", 7321)
327
+
328
+ assert_equal t1.hash, t2.hash
329
+ end
330
+
331
+ def test_not_equal
332
+ t1 = Fluent::Plugin::TailInput::TargetInfo.new("test", 1234)
333
+ t2 = Fluent::Plugin::TailInput::TargetInfo.new("test2", 1234)
334
+
335
+ assert_not_equal t1.hash, t2.hash
336
+ end
337
+ end
338
+ end
285
339
  end
@@ -0,0 +1,105 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin/file_wrapper'
3
+
4
+ class FileWrapperTest < Test::Unit::TestCase
5
+ require 'windows/file'
6
+ require 'windows/error'
7
+ include Windows::File
8
+ include Windows::Error
9
+
10
+ TMP_DIR = File.dirname(__FILE__) + "/../tmp/file_wrapper#{ENV['TEST_ENV_NUMBER']}"
11
+
12
+ def setup
13
+ FileUtils.mkdir_p(TMP_DIR)
14
+ end
15
+
16
+ def teardown
17
+ FileUtils.rm_rf(TMP_DIR)
18
+ end
19
+
20
+ sub_test_case 'Win32Error' do
21
+ test 'equal' do
22
+ assert_equal(Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, "message"),
23
+ Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, "message"))
24
+ end
25
+
26
+ test 'different error code' do
27
+ assert_not_equal(Fluent::Win32Error.new(ERROR_FILE_NOT_FOUND),
28
+ Fluent::Win32Error.new(ERROR_SHARING_VIOLATION))
29
+ end
30
+
31
+ test 'different error message' do
32
+ assert_not_equal(Fluent::Win32Error.new(ERROR_FILE_NOT_FOUND, "message1"),
33
+ Fluent::Win32Error.new(ERROR_FILE_NOT_FOUND, "message2"))
34
+ end
35
+
36
+ test 'different class' do
37
+ assert_not_equal(Errno::EPIPE,
38
+ Fluent::Win32Error.new(ERROR_SHARING_VIOLATION))
39
+ end
40
+
41
+ test 'ERROR_SHARING_VIOLATION message' do
42
+ assert_equal(Fluent::Win32Error.new(ERROR_SHARING_VIOLATION).message,
43
+ "Fluent::Win32Error: code: 32, The process cannot access the file because it is being used by another process.")
44
+ end
45
+
46
+ test 'ERROR_SHARING_VIOLATION with a message' do
47
+ assert_equal(Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, "cannot open the file").message,
48
+ "Fluent::Win32Error: code: 32, The process cannot access the file because it is being used by another process." +
49
+ " - cannot open the file")
50
+ end
51
+
52
+ test 'to_s' do
53
+ assert_equal("Fluent::Win32Error: code: 32, The process cannot access the file because it is being used by another process. - C:\file.txt",
54
+ Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, "C:\file.txt").to_s)
55
+ end
56
+
57
+ test 'inspect' do
58
+ assert_equal("#<Fluent::Win32Error: code: 32, The process cannot access the file because it is being used by another process. - C:\file.txt>",
59
+ Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, "C:\file.txt").inspect)
60
+ end
61
+ end
62
+
63
+ sub_test_case 'WindowsFile exceptions' do
64
+ test 'nothing raised' do
65
+ begin
66
+ path = "#{TMP_DIR}/test_windows_file.txt"
67
+ file1 = file2 = nil
68
+ file1 = File.open(path, "wb") do |f|
69
+ end
70
+ assert_nothing_raised do
71
+ file2 = Fluent::WindowsFile.new(path)
72
+ ensure
73
+ file2.close
74
+ end
75
+ ensure
76
+ file1.close if file1
77
+ end
78
+ end
79
+
80
+ test 'Errno::ENOENT raised' do
81
+ path = "#{TMP_DIR}/nofile.txt"
82
+ file = nil
83
+ assert_raise(Errno::ENOENT) do
84
+ file = Fluent::WindowsFile.new(path)
85
+ ensure
86
+ file.close if file
87
+ end
88
+ end
89
+
90
+ test 'ERROR_SHARING_VIOLATION raised' do
91
+ begin
92
+ path = "#{TMP_DIR}/test_windows_file.txt"
93
+ file1 = file2 = nil
94
+ file1 = File.open(path, "wb")
95
+ assert_raise(Fluent::Win32Error.new(ERROR_SHARING_VIOLATION, path)) do
96
+ file2 = Fluent::WindowsFile.new(path, 'r', FILE_SHARE_READ)
97
+ ensure
98
+ file2.close if file2
99
+ end
100
+ ensure
101
+ file1.close if file1
102
+ end
103
+ end
104
+ end
105
+ end if Fluent.windows?