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
@@ -48,10 +48,19 @@ module Fluent
48
48
  }
49
49
 
50
50
  PARSER_PARAMS = {
51
- "format" => "@type",
51
+ "format" => nil,
52
+ "types" => nil,
53
+ "types_delimiter" => nil,
54
+ "types_label_delimiter" => nil,
55
+ "keys" => "keys", # CSVParser, TSVParser (old ValuesParser)
52
56
  "time_key" => "time_key",
53
57
  "time_format" => "time_format",
58
+ "localtim" => nil,
59
+ "utc" => nil,
54
60
  "delimiter" => "delimiter",
61
+ "keep_time_key" => "keep_time_key",
62
+ "null_empty_string" => "null_empty_string",
63
+ "null_value_pattern" => "null_value_pattern",
55
64
  "json_parser" => "json_parser", # JSONParser
56
65
  "label_delimiter" => "label_delimiter", # LabeledTSVParser
57
66
  "format_firstline" => "format_firstline", # MultilineParser
@@ -62,19 +71,29 @@ module Fluent
62
71
 
63
72
  INJECT_PARAMS = {
64
73
  "include_time_key" => nil,
65
- "time_key" => "time_key",
66
- "time_format" => "time_format",
67
- "timezone" => "timezone",
74
+ "time_key" => "time_key",
75
+ "time_format" => "time_format",
76
+ "timezone" => "timezone",
68
77
  "include_tag_key" => nil,
69
78
  "tag_key" => "tag_key",
70
79
  "localtime" => nil,
71
80
  "utc" => nil,
72
81
  }
73
82
 
83
+ EXTRACT_PARAMS = {
84
+ "time_key" => "time_key",
85
+ "time_format" => "time_format",
86
+ "timezone" => "timezone",
87
+ "tag_key" => "tag_key",
88
+ "localtime" => nil,
89
+ "utc" => nil,
90
+ }
91
+
74
92
  FORMATTER_PARAMS = {
75
93
  "format" => "@type",
76
94
  "delimiter" => "delimiter",
77
95
  "force_quotes" => "force_quotes", # CsvFormatter
96
+ "keys" => "keys", # TSVFormatter
78
97
  "fields" => "fields", # CsvFormatter
79
98
  "json_parser" => "json_parser", # JSONFormatter
80
99
  "label_delimiter" => "label_delimiter", # LabeledTSVFormatter
@@ -95,6 +114,8 @@ module Fluent
95
114
  compat_parameters_buffer(conf, **kwargs)
96
115
  when :inject
97
116
  compat_parameters_inject(conf)
117
+ when :extract
118
+ compat_parameters_extract(conf)
98
119
  when :parser
99
120
  compat_parameters_parser(conf)
100
121
  when :formatter
@@ -167,6 +188,7 @@ module Fluent
167
188
  hash['time_type'] ||= 'string'
168
189
  end
169
190
  if conf.has_key?('time_as_epoch') && Fluent::Config.bool_value(conf['time_as_epoch'])
191
+ hash['time_key'] ||= 'time'
170
192
  hash['time_type'] = 'unixtime'
171
193
  end
172
194
  if conf.has_key?('localtime') || conf.has_key?('utc')
@@ -193,6 +215,40 @@ module Fluent
193
215
  conf
194
216
  end
195
217
 
218
+ def compat_parameters_extract(conf)
219
+ return unless conf.elements('extract').empty?
220
+ return if EXTRACT_PARAMS.keys.all?{|k| !conf.has_key?(k) } && !conf.has_key?('format')
221
+
222
+ # TODO: warn obsolete parameters if these are deprecated
223
+ hash = compat_parameters_copy_to_subsection_attributes(conf, EXTRACT_PARAMS)
224
+
225
+ if conf.has_key?('time_as_epoch') && Fluent::Config.bool_value(conf['time_as_epoch'])
226
+ hash['time_key'] ||= 'time'
227
+ hash['time_type'] = 'unixtime'
228
+ elsif conf.has_key?('format') && conf["format"].start_with?("/") && conf["format"].end_with?("/") # old-style regexp parser
229
+ hash['time_key'] ||= 'time'
230
+ hash['time_type'] ||= 'string'
231
+ end
232
+ if conf.has_key?('localtime') || conf.has_key?('utc')
233
+ if conf.has_key?('localtime') && conf.has_key?('utc')
234
+ raise Fluent::ConfigError, "both of utc and localtime are specified, use only one of them"
235
+ elsif conf.has_key?('localtime')
236
+ hash['localtime'] = Fluent::Config.bool_value(conf['localtime'])
237
+ elsif conf.has_key?('utc')
238
+ hash['localtime'] = !(Fluent::Config.bool_value(conf['utc']))
239
+ # Specifying "localtime false" means using UTC in TimeFormatter
240
+ # And specifying "utc" is different from specifying "timezone +0000"(it's not always UTC).
241
+ # There are difference between "Z" and "+0000" in timezone formatting.
242
+ # TODO: add kwargs to TimeFormatter to specify "using localtime", "using UTC" or "using specified timezone" in more explicit way
243
+ end
244
+ end
245
+
246
+ e = Fluent::Config::Element.new('extract', '', hash, [])
247
+ conf.elements << e
248
+
249
+ conf
250
+ end
251
+
196
252
  def compat_parameters_parser(conf)
197
253
  return unless conf.elements('parse').empty?
198
254
  return if PARSER_PARAMS.keys.all?{|k| !conf.has_key?(k) }
@@ -200,6 +256,39 @@ module Fluent
200
256
  # TODO: warn obsolete parameters if these are deprecated
201
257
  hash = compat_parameters_copy_to_subsection_attributes(conf, PARSER_PARAMS)
202
258
 
259
+ if conf["format"]
260
+ if conf["format"].start_with?("/") && conf["format"].end_with?("/")
261
+ hash["@type"] = "regexp"
262
+ hash["expression"] = conf["format"][1..-2]
263
+ else
264
+ hash["@type"] = conf["format"]
265
+ end
266
+ end
267
+
268
+ if conf["types"]
269
+ delimiter = conf["types_delimiter"] || ','
270
+ label_delimiter = conf["types_label_delimiter"] || ':'
271
+ types = {}
272
+ conf['types'].split(delimiter).each do |pair|
273
+ key, value = pair.split(label_delimiter, 2)
274
+ types[key] = value
275
+ end
276
+ hash["types"] = JSON.dump(types)
277
+ end
278
+ if conf.has_key?('localtime') || conf.has_key?('utc')
279
+ if conf.has_key?('localtime') && conf.has_key?('utc')
280
+ raise Fluent::ConfigError, "both of utc and localtime are specified, use only one of them"
281
+ elsif conf.has_key?('localtime')
282
+ hash['localtime'] = Fluent::Config.bool_value(conf['localtime'])
283
+ elsif conf.has_key?('utc')
284
+ hash['localtime'] = !(Fluent::Config.bool_value(conf['utc']))
285
+ # Specifying "localtime false" means using UTC in TimeFormatter
286
+ # And specifying "utc" is different from specifying "timezone +0000"(it's not always UTC).
287
+ # There are difference between "Z" and "+0000" in timezone formatting.
288
+ # TODO: add kwargs to TimeFormatter to specify "using localtime", "using UTC" or "using specified timezone" in more explicit way
289
+ end
290
+ end
291
+
203
292
  e = Fluent::Config::Element.new('parse', '', hash, [])
204
293
  conf.elements << e
205
294
 
@@ -26,10 +26,14 @@ module Fluent
26
26
 
27
27
  def router
28
28
  @_event_emitter_used_actually = true
29
+ if @_event_emitter_lazy_init
30
+ @router = @primary_instance.router
31
+ end
29
32
  @router
30
33
  end
31
34
 
32
35
  def router=(r)
36
+ # not recommended now...
33
37
  @router = r
34
38
  end
35
39
 
@@ -44,14 +48,23 @@ module Fluent
44
48
  def event_emitter_router(label_name)
45
49
  if label_name
46
50
  Engine.root_agent.find_label(label_name).event_router
51
+ elsif self.respond_to?(:as_secondary) && self.as_secondary
52
+ if @primary_instance.has_router?
53
+ @_event_emitter_lazy_init = true
54
+ nil # primary plugin's event router is not initialized yet, here.
55
+ else
56
+ @primary_instance.context_router
57
+ end
47
58
  else
48
- Engine.root_agent.event_router
59
+ # `Engine.root_agent.event_router` is for testing
60
+ self.context_router || Engine.root_agent.event_router
49
61
  end
50
62
  end
51
63
 
52
64
  def initialize
53
65
  super
54
66
  @_event_emitter_used_actually = false
67
+ @_event_emitter_lazy_init = false
55
68
  @router = nil
56
69
  end
57
70
 
@@ -25,7 +25,8 @@ module Fluent
25
25
  return nil unless @_extract_enabled
26
26
 
27
27
  if @_extract_tag_key && record.has_key?(@_extract_tag_key)
28
- return record[@_extract_tag_key].to_s
28
+ v = @_extract_keep_tag_key ? record[@_extract_tag_key] : record.delete(@_extract_tag_key)
29
+ return v.to_s
29
30
  end
30
31
 
31
32
  nil
@@ -35,7 +36,8 @@ module Fluent
35
36
  return nil unless @_extract_enabled
36
37
 
37
38
  if @_extract_time_key && record.has_key?(@_extract_time_key)
38
- return @_extract_time_parser.call(record[@_extract_time_key])
39
+ v = @_extract_keep_time_key ? record[@_extract_time_key] : record.delete(@_extract_time_key)
40
+ return @_extract_time_parser.call(v)
39
41
  end
40
42
 
41
43
  nil
@@ -45,7 +47,9 @@ module Fluent
45
47
  include Fluent::Configurable
46
48
  config_section :extract, required: false, multi: false, param_name: :extract_config do
47
49
  config_param :tag_key, :string, default: nil
50
+ config_param :keep_tag_key, :bool, default: false
48
51
  config_param :time_key, :string, default: nil
52
+ config_param :keep_time_key, :bool, default: false
49
53
 
50
54
  # To avoid defining :time_type twice
51
55
  config_param :time_type, :enum, list: [:float, :unixtime, :string], default: :float
@@ -64,7 +68,9 @@ module Fluent
64
68
  super
65
69
  @_extract_enabled = false
66
70
  @_extract_tag_key = nil
71
+ @_extract_keep_tag_key = nil
67
72
  @_extract_time_key = nil
73
+ @_extract_keep_time_key = nil
68
74
  @_extract_time_parser = nil
69
75
  end
70
76
 
@@ -73,15 +79,21 @@ module Fluent
73
79
 
74
80
  if @extract_config
75
81
  @_extract_tag_key = @extract_config.tag_key
82
+ @_extract_keep_tag_key = @extract_config.keep_tag_key
76
83
  @_extract_time_key = @extract_config.time_key
77
84
  if @_extract_time_key
85
+ @_extract_keep_time_key = @extract_config.keep_time_key
78
86
  @_extract_time_parser = case @extract_config.time_type
79
- when :float then ->(v){ Fluent::EventTime.new(v.to_i, ((v.to_f - v.to_i) * 1_000_000_000).to_i) }
80
- when :unixtime then ->(v){ Fluent::EventTime.new(v.to_i, 0) }
87
+ when :float then Fluent::NumericTimeParser.new(:float)
88
+ when :unixtime then Fluent::NumericTimeParser.new(:unixtime)
81
89
  else
82
90
  localtime = @extract_config.localtime && !@extract_config.utc
83
91
  Fluent::TimeParser.new(@extract_config.time_format, localtime, @extract_config.timezone)
84
92
  end
93
+ else
94
+ if @extract_config.time_format
95
+ log.warn "'time_format' specified without 'time_key', will be ignored"
96
+ end
85
97
  end
86
98
 
87
99
  @_extract_enabled = @_extract_tag_key || @_extract_time_key
@@ -24,7 +24,7 @@ module Fluent
24
24
  module Formatter
25
25
  def formatter_create(usage: '', type: nil, conf: nil, default_type: nil)
26
26
  formatter = @_formatters[usage]
27
- return formatter if formatter
27
+ return formatter if formatter && !type && !conf
28
28
 
29
29
  type = if type
30
30
  type
@@ -61,9 +61,9 @@ module Fluent
61
61
  module FormatterParams
62
62
  include Fluent::Configurable
63
63
  # minimum section definition to instantiate formatter plugin instances
64
- config_section :format, required: false, multi: true, param_name: :formatter_configs do
64
+ config_section :format, required: false, multi: true, init: true, param_name: :formatter_configs do
65
65
  config_argument :usage, :string, default: ''
66
- config_param :@type, :string
66
+ config_param :@type, :string # config_set_default required for :@type
67
67
  end
68
68
  end
69
69
 
@@ -82,15 +82,13 @@ module Fluent
82
82
  def configure(conf)
83
83
  super
84
84
 
85
- if @formatter_configs
86
- @formatter_configs.each do |section|
87
- if @_formatters[section.usage]
88
- raise Fluent::ConfigError, "duplicated formatter configured: #{section.usage}"
89
- end
90
- formatter = Plugin.new_formatter(section[:@type], parent: self)
91
- formatter.configure(section.corresponding_config_element)
92
- @_formatters[section.usage] = formatter
85
+ @formatter_configs.each do |section|
86
+ if @_formatters[section.usage]
87
+ raise Fluent::ConfigError, "duplicated formatter configured: #{section.usage}"
93
88
  end
89
+ formatter = Plugin.new_formatter(section[:@type], parent: self)
90
+ formatter.configure(section.corresponding_config_element)
91
+ @_formatters[section.usage] = formatter
94
92
  end
95
93
  end
96
94
 
@@ -113,6 +113,10 @@ module Fluent
113
113
  localtime = @inject_config.localtime && !@inject_config.utc
114
114
  Fluent::TimeFormatter.new(@inject_config.time_format, localtime, @inject_config.timezone)
115
115
  end
116
+ else
117
+ if @inject_config.time_format
118
+ log.warn "'time_format' specified without 'time_key', will be ignored"
119
+ end
116
120
  end
117
121
 
118
122
  @_inject_enabled = @_inject_hostname_key || @_inject_tag_key || @_inject_time_key
@@ -24,7 +24,7 @@ module Fluent
24
24
  module Parser
25
25
  def parser_create(usage: '', type: nil, conf: nil, default_type: nil)
26
26
  parser = @_parsers[usage]
27
- return parser if parser
27
+ return parser if parser && !type && !conf
28
28
 
29
29
  type = if type
30
30
  type
@@ -61,9 +61,9 @@ module Fluent
61
61
  module ParserParams
62
62
  include Fluent::Configurable
63
63
  # minimum section definition to instantiate parser plugin instances
64
- config_section :parse, required: false, multi: true, param_name: :parser_configs do
64
+ config_section :parse, required: false, multi: true, init: true, param_name: :parser_configs do
65
65
  config_argument :usage, :string, default: ''
66
- config_param :@type, :string
66
+ config_param :@type, :string # config_set_default required for :@type
67
67
  end
68
68
  end
69
69
 
@@ -233,7 +233,7 @@ module Fluent
233
233
  # <source> emits events to the top-level event router (RootAgent#event_router).
234
234
  # Input#configure overwrites event_router to a label's event_router if it has `@label` parameter.
235
235
  # See also 'fluentd/plugin/input.rb'
236
- input.router = @event_router
236
+ input.context_router = @event_router
237
237
  input.configure(conf)
238
238
  @inputs << input
239
239
 
@@ -23,9 +23,13 @@ require 'timeout'
23
23
  module Fluent
24
24
  module Test
25
25
  module Driver
26
+ class TestTimedOut < RuntimeError; end
27
+
26
28
  class Base
27
29
  attr_reader :instance, :logs
28
30
 
31
+ DEFAULT_TIMEOUT = 300
32
+
29
33
  def initialize(klass, opts: {}, &block)
30
34
  if klass.is_a?(Class)
31
35
  if block
@@ -44,6 +48,8 @@ module Fluent
44
48
 
45
49
  @logs = []
46
50
 
51
+ @test_clock_id = Process::CLOCK_MONOTONIC_RAW rescue Process::CLOCK_MONOTONIC
52
+
47
53
  @run_post_conditions = []
48
54
  @run_breaking_conditions = []
49
55
  @broken = false
@@ -70,15 +76,25 @@ module Fluent
70
76
  def run(timeout: nil, start: true, shutdown: true, &block)
71
77
  instance_start if start
72
78
 
73
- if @instance.respond_to?(:thread_wait_until_start)
74
- @instance.thread_wait_until_start
75
- end
76
- if @instance.respond_to?(:event_loop_wait_until_start)
77
- @instance.event_loop_wait_until_start
79
+ timeout ||= DEFAULT_TIMEOUT
80
+ stop_at = Process.clock_gettime(@test_clock_id) + timeout
81
+ @run_breaking_conditions << ->(){ Process.clock_gettime(@test_clock_id) >= stop_at }
82
+
83
+ if !block_given? && @run_post_conditions.empty? && @run_breaking_conditions.empty?
84
+ raise ArgumentError, "no stop conditions nor block specified"
78
85
  end
79
86
 
87
+ sleep_with_watching_threads = ->(){
88
+ if @instance.respond_to?(:_threads)
89
+ @instance._threads.values.each{|t| t.join(0) }
90
+ end
91
+ sleep 0.1
92
+ }
93
+
80
94
  begin
81
- run_actual(timeout: timeout, &block)
95
+ retval = run_actual(timeout: timeout, &block)
96
+ sleep_with_watching_threads.call until stop?
97
+ retval
82
98
  ensure
83
99
  instance_shutdown if shutdown
84
100
  end
@@ -87,18 +103,33 @@ module Fluent
87
103
  def instance_start
88
104
  unless @instance.started?
89
105
  @instance.start
90
- instance_hook_after_started
91
106
  end
92
107
  unless @instance.after_started?
93
108
  @instance.after_start
94
109
  end
110
+
111
+ if @instance.respond_to?(:thread_wait_until_start)
112
+ @instance.thread_wait_until_start
113
+ end
114
+
115
+ if @instance.respond_to?(:event_loop_wait_until_start)
116
+ @instance.event_loop_wait_until_start
117
+ end
118
+
119
+ instance_hook_after_started
95
120
  end
96
121
 
97
122
  def instance_hook_after_started
98
123
  # insert hooks for tests available after instance.start
99
124
  end
100
125
 
126
+ def instance_hook_before_stopped
127
+ # same with above
128
+ end
129
+
101
130
  def instance_shutdown
131
+ instance_hook_before_stopped
132
+
102
133
  @instance.stop unless @instance.stopped?
103
134
  @instance.before_shutdown unless @instance.before_shutdown?
104
135
  @instance.shutdown unless @instance.shutdown?
@@ -117,50 +148,33 @@ module Fluent
117
148
  @instance.terminate unless @instance.terminated?
118
149
  end
119
150
 
120
- def run_actual(timeout: nil, &block)
151
+ def run_actual(timeout: DEFAULT_TIMEOUT, &block)
121
152
  if @instance.respond_to?(:_threads)
122
- until @instance._threads.values.all?(&:alive?)
123
- sleep 0.01
124
- end
153
+ sleep 0.1 until @instance._threads.values.all?(&:alive?)
125
154
  end
126
155
 
127
156
  if @instance.respond_to?(:event_loop_running?)
128
- until @instance.event_loop_running?
129
- sleep 0.01
130
- end
131
- end
132
-
133
- if timeout
134
- stop_at = Time.now + timeout
135
- @run_breaking_conditions << ->(){ Time.now >= stop_at }
157
+ sleep 0.1 until @instance.event_loop_running?
136
158
  end
137
159
 
138
- if !block_given? && @run_post_conditions.empty? && @run_breaking_conditions.empty?
139
- raise ArgumentError, "no stop conditions nor block specified"
160
+ if @instance.respond_to?(:_child_process_processes)
161
+ sleep 0.1 until @instance._child_process_processes.values.all?{|pinfo| pinfo.alive }
140
162
  end
141
163
 
142
- proc = if block_given?
143
- ->(){ block.call; sleep(0.1) until stop? }
144
- else
145
- ->(){ sleep(0.1) until stop? }
146
- end
147
-
148
- if timeout
149
- begin
150
- Timeout.timeout(timeout * 1.1) do |sec|
151
- proc.call
152
- end
153
- rescue Timeout::Error
154
- @broken = true
164
+ return_value = nil
165
+ begin
166
+ Timeout.timeout(timeout * 1.1) do |sec|
167
+ return_value = block.call if block_given?
155
168
  end
156
- else
157
- proc.call
169
+ rescue Timeout::Error
170
+ raise TestTimedOut, "Test case timed out with hard limit."
158
171
  end
172
+ return_value
159
173
  end
160
174
 
161
175
  def stop?
162
176
  # Should stop running if post conditions are not registered.
163
- return true unless @run_post_conditions
177
+ return true unless @run_post_conditions || @run_post_conditions.empty?
164
178
 
165
179
  # Should stop running if all of the post conditions are true.
166
180
  return true if @run_post_conditions.all? {|proc| proc.call }