fluentd 0.14.8 → 0.14.9

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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CONTRIBUTING.md +6 -1
  4. data/ChangeLog +38 -0
  5. data/Rakefile +21 -0
  6. data/example/out_exec_filter.conf +42 -0
  7. data/lib/fluent/agent.rb +2 -2
  8. data/lib/fluent/command/binlog_reader.rb +1 -1
  9. data/lib/fluent/command/cat.rb +5 -2
  10. data/lib/fluent/compat/output.rb +7 -8
  11. data/lib/fluent/compat/parser.rb +139 -11
  12. data/lib/fluent/config/configure_proxy.rb +2 -11
  13. data/lib/fluent/config/section.rb +7 -0
  14. data/lib/fluent/configurable.rb +1 -3
  15. data/lib/fluent/log.rb +1 -1
  16. data/lib/fluent/plugin/base.rb +17 -0
  17. data/lib/fluent/plugin/filter_parser.rb +108 -0
  18. data/lib/fluent/plugin/filter_record_transformer.rb +4 -7
  19. data/lib/fluent/plugin/filter_stdout.rb +1 -1
  20. data/lib/fluent/plugin/formatter.rb +5 -0
  21. data/lib/fluent/plugin/formatter_msgpack.rb +4 -0
  22. data/lib/fluent/plugin/formatter_stdout.rb +3 -2
  23. data/lib/fluent/plugin/formatter_tsv.rb +34 -0
  24. data/lib/fluent/plugin/in_exec.rb +48 -93
  25. data/lib/fluent/plugin/in_forward.rb +25 -105
  26. data/lib/fluent/plugin/in_http.rb +68 -65
  27. data/lib/fluent/plugin/in_syslog.rb +29 -51
  28. data/lib/fluent/plugin/multi_output.rb +1 -3
  29. data/lib/fluent/plugin/out_exec.rb +58 -71
  30. data/lib/fluent/plugin/out_exec_filter.rb +199 -279
  31. data/lib/fluent/plugin/out_file.rb +155 -80
  32. data/lib/fluent/plugin/out_forward.rb +44 -47
  33. data/lib/fluent/plugin/out_stdout.rb +6 -21
  34. data/lib/fluent/plugin/output.rb +23 -17
  35. data/lib/fluent/plugin/parser.rb +121 -61
  36. data/lib/fluent/plugin/parser_csv.rb +9 -3
  37. data/lib/fluent/plugin/parser_json.rb +37 -35
  38. data/lib/fluent/plugin/parser_ltsv.rb +11 -19
  39. data/lib/fluent/plugin/parser_msgpack.rb +50 -0
  40. data/lib/fluent/plugin/parser_regexp.rb +15 -42
  41. data/lib/fluent/plugin/parser_tsv.rb +8 -3
  42. data/lib/fluent/plugin_helper.rb +8 -1
  43. data/lib/fluent/plugin_helper/child_process.rb +139 -73
  44. data/lib/fluent/plugin_helper/compat_parameters.rb +93 -4
  45. data/lib/fluent/plugin_helper/event_emitter.rb +14 -1
  46. data/lib/fluent/plugin_helper/extract.rb +16 -4
  47. data/lib/fluent/plugin_helper/formatter.rb +9 -11
  48. data/lib/fluent/plugin_helper/inject.rb +4 -0
  49. data/lib/fluent/plugin_helper/parser.rb +3 -3
  50. data/lib/fluent/root_agent.rb +1 -1
  51. data/lib/fluent/test/driver/base.rb +51 -37
  52. data/lib/fluent/test/driver/base_owner.rb +18 -8
  53. data/lib/fluent/test/driver/multi_output.rb +2 -1
  54. data/lib/fluent/test/driver/output.rb +29 -6
  55. data/lib/fluent/test/helpers.rb +3 -1
  56. data/lib/fluent/test/log.rb +4 -0
  57. data/lib/fluent/test/startup_shutdown.rb +13 -0
  58. data/lib/fluent/time.rb +14 -8
  59. data/lib/fluent/version.rb +1 -1
  60. data/test/command/test_binlog_reader.rb +5 -1
  61. data/test/config/test_configurable.rb +173 -0
  62. data/test/config/test_configure_proxy.rb +0 -43
  63. data/test/plugin/test_base.rb +16 -0
  64. data/test/plugin/test_filter_parser.rb +665 -0
  65. data/test/plugin/test_filter_record_transformer.rb +11 -3
  66. data/test/plugin/test_filter_stdout.rb +18 -27
  67. data/test/plugin/test_in_dummy.rb +1 -1
  68. data/test/plugin/test_in_exec.rb +206 -94
  69. data/test/plugin/test_in_forward.rb +310 -327
  70. data/test/plugin/test_in_http.rb +310 -186
  71. data/test/plugin/test_out_exec.rb +223 -68
  72. data/test/plugin/test_out_exec_filter.rb +520 -169
  73. data/test/plugin/test_out_file.rb +620 -177
  74. data/test/plugin/test_out_forward.rb +110 -132
  75. data/test/plugin/test_out_null.rb +1 -1
  76. data/test/plugin/test_out_secondary_file.rb +4 -2
  77. data/test/plugin/test_out_stdout.rb +14 -35
  78. data/test/plugin/test_parser.rb +359 -0
  79. data/test/plugin/test_parser_csv.rb +1 -2
  80. data/test/plugin/test_parser_json.rb +3 -4
  81. data/test/plugin/test_parser_labeled_tsv.rb +1 -2
  82. data/test/plugin/test_parser_none.rb +1 -2
  83. data/test/plugin/test_parser_regexp.rb +8 -4
  84. data/test/plugin/test_parser_tsv.rb +4 -3
  85. data/test/plugin_helper/test_child_process.rb +184 -0
  86. data/test/plugin_helper/test_compat_parameters.rb +88 -1
  87. data/test/plugin_helper/test_extract.rb +0 -1
  88. data/test/plugin_helper/test_formatter.rb +5 -2
  89. data/test/plugin_helper/test_parser.rb +6 -5
  90. data/test/test_output.rb +24 -2
  91. data/test/test_plugin_classes.rb +20 -0
  92. data/test/test_root_agent.rb +139 -0
  93. data/test/test_test_drivers.rb +132 -0
  94. metadata +12 -4
  95. data/test/plugin/test_parser_base.rb +0 -32
@@ -71,25 +71,35 @@ module Fluent
71
71
  end
72
72
 
73
73
  def events(tag: nil)
74
- return [] if @event_streams.nil?
75
- selected = @event_streams.select{|e| tag.nil? ? true : e.tag == tag }
76
74
  if block_given?
77
- selected.each do |e|
78
- e.es.each do |time, record|
79
- yield e.tag, time, record
75
+ event_streams(tag: tag) do |t, es|
76
+ es.each do |time, record|
77
+ yield t, time, record
80
78
  end
81
79
  end
82
80
  else
83
81
  list = []
84
- selected.each do |e|
85
- e.es.each do |time, record|
86
- list << [e.tag, time, record]
82
+ event_streams(tag: tag) do |t, es|
83
+ es.each do |time, record|
84
+ list << [t, time, record]
87
85
  end
88
86
  end
89
87
  list
90
88
  end
91
89
  end
92
90
 
91
+ def event_streams(tag: nil)
92
+ return [] if @event_streams.nil?
93
+ selected = @event_streams.select{|e| tag.nil? ? true : e.tag == tag }
94
+ if block_given?
95
+ selected.each do |e|
96
+ yield e.tag, e.es
97
+ end
98
+ else
99
+ selected.map{|e| [e.tag, e.es] }
100
+ end
101
+ end
102
+
93
103
  def emit_count
94
104
  @event_streams.size
95
105
  end
@@ -37,10 +37,11 @@ module Fluent
37
37
  end
38
38
 
39
39
  def run_actual(**kwargs, &block)
40
- super(**kwargs, &block)
40
+ val = super(**kwargs, &block)
41
41
  if @flush_buffer_at_cleanup
42
42
  @instance.outputs.each{|o| o.force_flush }
43
43
  end
44
+ val
44
45
  end
45
46
 
46
47
  def flush
@@ -29,23 +29,31 @@ module Fluent
29
29
  def initialize(klass, opts: {}, &block)
30
30
  super
31
31
  raise ArgumentError, "plugin is not an instance of Fluent::Plugin::Output" unless @instance.is_a? Fluent::Plugin::Output
32
- @instance.in_tests = true
33
32
  @flush_buffer_at_cleanup = nil
33
+ @wait_flush_completion = nil
34
+ @force_flush_retry = nil
34
35
  @format_hook = nil
35
36
  @format_results = []
36
37
  end
37
38
 
38
- def run(flush: true, **kwargs, &block)
39
+ def run(flush: true, wait_flush_completion: true, force_flush_retry: false, **kwargs, &block)
39
40
  @flush_buffer_at_cleanup = flush
41
+ @wait_flush_completion = wait_flush_completion
42
+ @force_flush_retry = force_flush_retry
40
43
  super(**kwargs, &block)
41
44
  end
42
45
 
43
46
  def run_actual(**kwargs, &block)
44
- super(**kwargs, &block)
47
+ if @force_flush_retry
48
+ @instance.retry_for_error_chunk = true
49
+ end
50
+ val = super(**kwargs, &block)
45
51
  if @flush_buffer_at_cleanup
46
- @instance.force_flush
47
- Timeout.timeout(10){ sleep 0.1 until !@instance.buffer || @instance.buffer.queue.size == 0 }
52
+ self.flush
48
53
  end
54
+ val
55
+ ensure
56
+ @instance.retry_for_error_chunk = false
49
57
  end
50
58
 
51
59
  def formatted
@@ -54,7 +62,22 @@ module Fluent
54
62
 
55
63
  def flush
56
64
  @instance.force_flush
57
- Timeout.timeout(10){ sleep 0.1 until !@instance.buffer || @instance.buffer.queue.size == 0 }
65
+ wait_flush_completion if @wait_flush_completion
66
+ end
67
+
68
+ def wait_flush_completion
69
+ buffer_queue = ->(){ @instance.buffer && @instance.buffer.queue.size > 0 }
70
+ dequeued_chunks = ->(){
71
+ @instance.dequeued_chunks_mutex &&
72
+ @instance.dequeued_chunks &&
73
+ @instance.dequeued_chunks_mutex.synchronize{ @instance.dequeued_chunks.size > 0 }
74
+ }
75
+
76
+ Timeout.timeout(10) do
77
+ while buffer_queue.call || dequeued_chunks.call
78
+ sleep 0.1
79
+ end
80
+ end
58
81
  end
59
82
 
60
83
  def instance_hook_after_started
@@ -23,7 +23,9 @@ module Fluent
23
23
  module Helpers
24
24
  # See "Example Custom Assertion: http://test-unit.github.io/test-unit/en/Test/Unit/Assertions.html
25
25
  def assert_equal_event_time(expected, actual, message = nil)
26
- message = build_message(message, <<EOT, expected, actual)
26
+ expected_s = "#{Time.at(expected.sec)} (nsec #{expected.nsec})"
27
+ actual_s = "#{Time.at(actual.sec) } (nsec #{actual.nsec})"
28
+ message = build_message(message, <<EOT, expected_s, actual_s)
27
29
  <?> expected but was
28
30
  <?>.
29
31
  EOT
@@ -26,6 +26,7 @@ module Fluent
26
26
  def initialize
27
27
  @logs = []
28
28
  @flush_logs = true
29
+ @use_stderr = false
29
30
  end
30
31
 
31
32
  def reset
@@ -41,6 +42,9 @@ module Fluent
41
42
  end
42
43
 
43
44
  def write(message)
45
+ if @use_stderr
46
+ STDERR.write message
47
+ end
44
48
  @logs.push message
45
49
  end
46
50
 
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'serverengine'
18
+ require 'fileutils'
18
19
 
19
20
  module Fluent
20
21
  module Test
@@ -28,6 +29,18 @@ module Fluent
28
29
  def shutdown
29
30
  @server.close
30
31
  end
32
+
33
+ def self.setup
34
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
35
+ @server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
36
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
37
+ end
38
+
39
+ def self.teardown
40
+ @server.close
41
+ # on Windows, socket_manager_path is a TCP port number
42
+ FileUtils.rm_f @socket_manager_path unless Fluent.windows?
43
+ end
31
44
  end
32
45
  end
33
46
  end
@@ -50,6 +50,10 @@ module Fluent
50
50
  @sec
51
51
  end
52
52
 
53
+ def to_f
54
+ @sec + @nsec / 1_000_000_000.0
55
+ end
56
+
53
57
  # for Time.at
54
58
  def to_r
55
59
  Rational(@sec * 1_000_000_000 + @nsec, 1_000_000_000)
@@ -107,6 +111,8 @@ module Fluent
107
111
  end
108
112
 
109
113
  module TimeMixin
114
+ TIME_TYPES = ['string', 'unixtime', 'float']
115
+
110
116
  TIME_PARAMETERS = [
111
117
  [:time_format, :string, {default: nil}],
112
118
  [:localtime, :bool, {default: true}], # UTC if :localtime is false and :timezone is nil
@@ -115,7 +121,7 @@ module Fluent
115
121
  ]
116
122
  TIME_FULL_PARAMETERS = [
117
123
  # To avoid to define :time_type twice (in plugin_helper/inject)
118
- [:time_type, :enum, {default: :string, list: [:string, :unixtime, :float]}],
124
+ [:time_type, :enum, {default: :string, list: TIME_TYPES.map(&:to_sym)}],
119
125
  ] + TIME_PARAMETERS
120
126
 
121
127
  module TimeParameters
@@ -197,7 +203,7 @@ module Fluent
197
203
  else Time.now.localtime.utc_offset # utc
198
204
  end
199
205
 
200
- strptime = format && (Strptime.new(time_format) rescue nil)
206
+ strptime = format && (Strptime.new(format) rescue nil)
201
207
 
202
208
  @parse = case
203
209
  when format_with_timezone && strptime then ->(v){ Fluent::EventTime.from_time(strptime.exec(v)) }
@@ -248,8 +254,8 @@ module Fluent
248
254
  end
249
255
 
250
256
  def parse_unixtime(value)
251
- unless value.is_a?(String)
252
- raise TimeParseError, "value must be a string: #{value}"
257
+ unless value.is_a?(String) || value.is_a?(Numeric)
258
+ raise TimeParseError, "value must be a string or a number: #{value}(value.class)"
253
259
  end
254
260
 
255
261
  if @cache1_key == value
@@ -279,8 +285,8 @@ module Fluent
279
285
  ## parse_by_to_r (full): 28.722362 sec
280
286
  ## parse_by_to_r (msec): 28.232856 sec
281
287
  def parse_float(value)
282
- unless value.is_a?(String)
283
- raise TimeParseError, "value must be a string: #{value}"
288
+ unless value.is_a?(String) || value.is_a?(Numeric)
289
+ raise TimeParseError, "value must be a string or a number: #{value}(value.class)"
284
290
  end
285
291
 
286
292
  if @cache1_key == value
@@ -290,8 +296,8 @@ module Fluent
290
296
  end
291
297
 
292
298
  begin
293
- sec_s, nsec_s, _ = value.split('.', 3) # throw away second-dot and later
294
- nsec_s = nsec_s[0..9]
299
+ sec_s, nsec_s, _ = value.to_s.split('.', 3) # throw away second-dot and later
300
+ nsec_s = nsec_s && nsec_s[0..9] || '0'
295
301
  nsec_s += '0' * (9 - nsec_s.size) if nsec_s.size < 9
296
302
  time = Fluent::EventTime.new(sec_s.to_i, nsec_s.to_i)
297
303
  rescue => e
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.8'
19
+ VERSION = '0.14.9'
20
20
 
21
21
  end
@@ -58,9 +58,13 @@ class TestBaseCommand < ::Test::Unit::TestCase
58
58
  def create_message_packed_file(path, times = [event_time], records = [{ 'message' => 'dummy' }])
59
59
  es = Fluent::MultiEventStream.new(times, records)
60
60
  v = es.to_msgpack_stream
61
- File.open("#{TMP_DIR}/#{path}", 'w') do |f|
61
+ out_path = "#{TMP_DIR}/#{path}"
62
+ File.open(out_path, 'wb') do |f|
62
63
  f.print(v)
63
64
  end
65
+ waiting(5) do
66
+ sleep 0.5 until File.size(out_path) == v.bytesize
67
+ end
64
68
  end
65
69
 
66
70
  def setup
@@ -334,6 +334,12 @@ module ConfigurableSpec
334
334
  end
335
335
  end
336
336
 
337
+ class NilOwner < Owner
338
+ config_section :buffer do
339
+ config_set_default :size_of_something, nil
340
+ end
341
+ end
342
+
337
343
  class FlatChild
338
344
  include Fluent::Configurable
339
345
  attr_accessor :owner
@@ -346,6 +352,19 @@ module ConfigurableSpec
346
352
  configured_in :buffer
347
353
  config_param :size_of_something, :size, default: 128
348
354
  end
355
+
356
+ class BufferBase
357
+ include Fluent::Configurable
358
+ end
359
+
360
+ class BufferSubclass < BufferBase
361
+ attr_accessor :owner
362
+ configured_in :buffer
363
+ config_param :size_of_something, :size, default: 512
364
+ end
365
+
366
+ class BufferSubSubclass < BufferSubclass
367
+ end
349
368
  end
350
369
  class UnRecommended
351
370
  include Fluent::Configurable
@@ -1038,6 +1057,8 @@ module Fluent::Config
1038
1057
  test 'for feature plugin which has flat parameters with parent' do
1039
1058
  owner = ConfigurableSpec::OverwriteDefaults::Owner.new
1040
1059
  child = ConfigurableSpec::OverwriteDefaults::FlatChild.new
1060
+ assert_nil child.class.merged_configure_proxy.configured_in_section
1061
+
1041
1062
  child.owner = owner
1042
1063
  child.configure(config_element('ROOT', '', {}, []))
1043
1064
  assert_equal "V1", child.key1
@@ -1046,6 +1067,8 @@ module Fluent::Config
1046
1067
  test 'for feature plugin which has parameters in subsection of parent' do
1047
1068
  owner = ConfigurableSpec::OverwriteDefaults::Owner.new
1048
1069
  child = ConfigurableSpec::OverwriteDefaults::BufferChild.new
1070
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1071
+
1049
1072
  child.owner = owner
1050
1073
  child.configure(config_element('ROOT', '', {}, []))
1051
1074
  assert_equal 1024, child.size_of_something
@@ -1054,10 +1077,48 @@ module Fluent::Config
1054
1077
  test 'even in subclass of owner' do
1055
1078
  owner = ConfigurableSpec::OverwriteDefaults::SubOwner.new
1056
1079
  child = ConfigurableSpec::OverwriteDefaults::BufferChild.new
1080
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1081
+
1057
1082
  child.owner = owner
1058
1083
  child.configure(config_element('ROOT', '', {}, []))
1059
1084
  assert_equal 2048, child.size_of_something
1060
1085
  end
1086
+
1087
+ test 'default values can be overwritten with nil' do
1088
+ owner = ConfigurableSpec::OverwriteDefaults::NilOwner.new
1089
+ child = ConfigurableSpec::OverwriteDefaults::BufferChild.new
1090
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1091
+
1092
+ child.owner = owner
1093
+ child.configure(config_element('ROOT', '', {}, []))
1094
+ assert_nil child.size_of_something
1095
+ end
1096
+
1097
+ test 'the first configured_in (in the order from base class) will be applied' do
1098
+ child = ConfigurableSpec::OverwriteDefaults::BufferSubclass.new
1099
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1100
+
1101
+ child.configure(config_element('ROOT', '', {}, []))
1102
+ assert_equal 512, child.size_of_something
1103
+ end
1104
+
1105
+ test 'the first configured_in is valid with owner classes' do
1106
+ owner = ConfigurableSpec::OverwriteDefaults::Owner.new
1107
+ child = ConfigurableSpec::OverwriteDefaults::BufferSubclass.new
1108
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1109
+
1110
+ child.owner = owner
1111
+ child.configure(config_element('ROOT', '', {}, []))
1112
+ assert_equal 1024, child.size_of_something
1113
+ end
1114
+
1115
+ test 'the only first configured_in is valid even in subclasses of a class with configured_in' do
1116
+ child = ConfigurableSpec::OverwriteDefaults::BufferSubSubclass.new
1117
+ assert_equal :buffer, child.class.merged_configure_proxy.configured_in_section
1118
+
1119
+ child.configure(config_element('ROOT', '', {}, []))
1120
+ assert_equal 512, child.size_of_something
1121
+ end
1061
1122
  end
1062
1123
 
1063
1124
  sub_test_case ':secret option' do
@@ -1236,5 +1297,117 @@ module Fluent::Config
1236
1297
  end
1237
1298
  end
1238
1299
  end
1300
+
1301
+ sub_test_case '#config_param without default values cause error if section is configured as init:true' do
1302
+ setup do
1303
+ @type_lookup = ->(type) { Fluent::Configurable.lookup_type(type) }
1304
+ @proxy = Fluent::Config::ConfigureProxy.new(:section, type_lookup: @type_lookup)
1305
+ end
1306
+
1307
+ test 'with simple config_param with default value' do
1308
+ class InitTestClass01
1309
+ include Fluent::Configurable
1310
+ config_section :subsection, init: true do
1311
+ config_param :param1, :integer, default: 1
1312
+ end
1313
+ end
1314
+ c = InitTestClass01.new
1315
+ c.configure(config_element('root', ''))
1316
+
1317
+ assert_equal 1, c.subsection.size
1318
+ assert_equal 1, c.subsection.first.param1
1319
+ end
1320
+
1321
+ test 'with simple config_param without default value' do
1322
+ class InitTestClass02
1323
+ include Fluent::Configurable
1324
+ config_section :subsection, init: true do
1325
+ config_param :param1, :integer
1326
+ end
1327
+ end
1328
+ c = InitTestClass02.new
1329
+ assert_raises ArgumentError.new("subsection: init is specified, but there're parameters without default values:param1") do
1330
+ c.configure(config_element('root', ''))
1331
+ end
1332
+
1333
+ c.configure(config_element('root', '', {}, [config_element('subsection', '', {'param1' => '1'})]))
1334
+
1335
+ assert_equal 1, c.subsection.size
1336
+ assert_equal 1, c.subsection.first.param1
1337
+ end
1338
+
1339
+ test 'with config_param with config_set_default' do
1340
+ module InitTestModule03
1341
+ include Fluent::Configurable
1342
+ config_section :subsection, init: true do
1343
+ config_param :param1, :integer
1344
+ end
1345
+ end
1346
+ class InitTestClass03
1347
+ include Fluent::Configurable
1348
+ include InitTestModule03
1349
+ config_section :subsection do
1350
+ config_set_default :param1, 1
1351
+ end
1352
+ end
1353
+
1354
+ c = InitTestClass03.new
1355
+ c.configure(config_element('root', ''))
1356
+
1357
+ assert_equal 1, c.subsection.size
1358
+ assert_equal 1, c.subsection.first.param1
1359
+ end
1360
+
1361
+ test 'with config_argument with default value' do
1362
+ class InitTestClass04
1363
+ include Fluent::Configurable
1364
+ config_section :subsection, init: true do
1365
+ config_argument :param0, :string, default: 'yay'
1366
+ end
1367
+ end
1368
+
1369
+ c = InitTestClass04.new
1370
+ c.configure(config_element('root', ''))
1371
+
1372
+ assert_equal 1, c.subsection.size
1373
+ assert_equal 'yay', c.subsection.first.param0
1374
+ end
1375
+
1376
+ test 'with config_argument without default value' do
1377
+ class InitTestClass04
1378
+ include Fluent::Configurable
1379
+ config_section :subsection, init: true do
1380
+ config_argument :param0, :string
1381
+ end
1382
+ end
1383
+
1384
+ c = InitTestClass04.new
1385
+ assert_raise ArgumentError.new("subsection: init is specified, but default value of argument is missing") do
1386
+ c.configure(config_element('root', ''))
1387
+ end
1388
+ end
1389
+
1390
+ test 'with config_argument with config_set_default' do
1391
+ module InitTestModule05
1392
+ include Fluent::Configurable
1393
+ config_section :subsection, init: true do
1394
+ config_argument :param0, :string
1395
+ end
1396
+ end
1397
+ class InitTestClass05
1398
+ include Fluent::Configurable
1399
+ include InitTestModule05
1400
+ config_section :subsection do
1401
+ config_set_default :param0, 'foo'
1402
+ end
1403
+ end
1404
+
1405
+ c = InitTestClass05.new
1406
+ c.configure(config_element('root', ''))
1407
+
1408
+ assert_equal 1, c.subsection.size
1409
+ assert_equal 'foo', c.subsection.first.param0
1410
+ end
1411
+ end
1239
1412
  end
1240
1413
  end