fluentd 1.6.3 → 1.7.0

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.drone.yml +35 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +2 -0
  4. data/CHANGELOG.md +58 -0
  5. data/README.md +5 -1
  6. data/fluentd.gemspec +1 -1
  7. data/lib/fluent/clock.rb +4 -0
  8. data/lib/fluent/compat/output.rb +3 -3
  9. data/lib/fluent/compat/socket_util.rb +1 -1
  10. data/lib/fluent/config/element.rb +3 -3
  11. data/lib/fluent/config/literal_parser.rb +1 -1
  12. data/lib/fluent/config/section.rb +4 -1
  13. data/lib/fluent/error.rb +4 -0
  14. data/lib/fluent/event.rb +28 -24
  15. data/lib/fluent/event_router.rb +2 -1
  16. data/lib/fluent/log.rb +1 -1
  17. data/lib/fluent/msgpack_factory.rb +8 -0
  18. data/lib/fluent/plugin/bare_output.rb +4 -4
  19. data/lib/fluent/plugin/buf_file_single.rb +211 -0
  20. data/lib/fluent/plugin/buffer.rb +62 -63
  21. data/lib/fluent/plugin/buffer/chunk.rb +21 -3
  22. data/lib/fluent/plugin/buffer/file_chunk.rb +37 -12
  23. data/lib/fluent/plugin/buffer/file_single_chunk.rb +314 -0
  24. data/lib/fluent/plugin/buffer/memory_chunk.rb +2 -1
  25. data/lib/fluent/plugin/compressable.rb +10 -6
  26. data/lib/fluent/plugin/filter_grep.rb +2 -2
  27. data/lib/fluent/plugin/formatter_csv.rb +10 -6
  28. data/lib/fluent/plugin/in_syslog.rb +10 -3
  29. data/lib/fluent/plugin/in_tail.rb +7 -2
  30. data/lib/fluent/plugin/in_tcp.rb +34 -7
  31. data/lib/fluent/plugin/multi_output.rb +4 -4
  32. data/lib/fluent/plugin/out_exec_filter.rb +1 -0
  33. data/lib/fluent/plugin/out_file.rb +13 -3
  34. data/lib/fluent/plugin/out_forward.rb +126 -588
  35. data/lib/fluent/plugin/out_forward/ack_handler.rb +161 -0
  36. data/lib/fluent/plugin/out_forward/connection_manager.rb +113 -0
  37. data/lib/fluent/plugin/out_forward/error.rb +28 -0
  38. data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
  39. data/lib/fluent/plugin/out_forward/handshake_protocol.rb +121 -0
  40. data/lib/fluent/plugin/out_forward/load_balancer.rb +111 -0
  41. data/lib/fluent/plugin/out_forward/socket_cache.rb +138 -0
  42. data/lib/fluent/plugin/out_http.rb +231 -0
  43. data/lib/fluent/plugin/output.rb +29 -35
  44. data/lib/fluent/plugin/parser.rb +77 -0
  45. data/lib/fluent/plugin/parser_csv.rb +75 -0
  46. data/lib/fluent/plugin_helper/server.rb +1 -1
  47. data/lib/fluent/plugin_helper/thread.rb +1 -0
  48. data/lib/fluent/root_agent.rb +1 -1
  49. data/lib/fluent/time.rb +4 -2
  50. data/lib/fluent/timezone.rb +21 -7
  51. data/lib/fluent/version.rb +1 -1
  52. data/test/command/test_fluentd.rb +1 -1
  53. data/test/command/test_plugin_generator.rb +18 -2
  54. data/test/config/test_configurable.rb +78 -40
  55. data/test/counter/test_store.rb +1 -1
  56. data/test/helper.rb +1 -0
  57. data/test/helpers/process_extenstion.rb +33 -0
  58. data/test/plugin/out_forward/test_ack_handler.rb +101 -0
  59. data/test/plugin/out_forward/test_connection_manager.rb +145 -0
  60. data/test/plugin/out_forward/test_handshake_protocol.rb +103 -0
  61. data/test/plugin/out_forward/test_load_balancer.rb +60 -0
  62. data/test/plugin/out_forward/test_socket_cache.rb +139 -0
  63. data/test/plugin/test_buf_file.rb +118 -2
  64. data/test/plugin/test_buf_file_single.rb +734 -0
  65. data/test/plugin/test_buffer.rb +4 -48
  66. data/test/plugin/test_buffer_file_chunk.rb +19 -1
  67. data/test/plugin/test_buffer_file_single_chunk.rb +620 -0
  68. data/test/plugin/test_formatter_csv.rb +16 -0
  69. data/test/plugin/test_in_syslog.rb +56 -6
  70. data/test/plugin/test_in_tail.rb +1 -1
  71. data/test/plugin/test_in_tcp.rb +25 -0
  72. data/test/plugin/test_out_forward.rb +75 -201
  73. data/test/plugin/test_out_http.rb +352 -0
  74. data/test/plugin/test_output_as_buffered.rb +27 -24
  75. data/test/plugin/test_parser.rb +40 -0
  76. data/test/plugin/test_parser_csv.rb +83 -0
  77. data/test/plugin_helper/test_record_accessor.rb +1 -1
  78. data/test/test_time_formatter.rb +140 -121
  79. metadata +33 -4
@@ -18,6 +18,15 @@ require 'tzinfo'
18
18
 
19
19
  require 'fluent/config/error'
20
20
 
21
+ # For v0.12. Will be removed after v2
22
+ module IntegerExt
23
+ refine Integer do
24
+ def to_time
25
+ Time.at(self)
26
+ end
27
+ end
28
+ end
29
+
21
30
  module Fluent
22
31
  class Timezone
23
32
  # [+-]HH:MM, [+-]HHMM, [+-]HH
@@ -84,6 +93,8 @@ module Fluent
84
93
  end
85
94
  end
86
95
 
96
+ using IntegerExt
97
+
87
98
  # Create a formatter for a timezone and optionally a format.
88
99
  #
89
100
  # An Proc object is returned. If the given timezone is invalid,
@@ -100,15 +111,15 @@ module Fluent
100
111
  case
101
112
  when format.is_a?(String)
102
113
  return Proc.new {|time|
103
- Time.at(time).localtime(offset).strftime(format)
114
+ time.to_time.localtime(offset).strftime(format)
104
115
  }
105
116
  when format.is_a?(Strftime)
106
117
  return Proc.new {|time|
107
- format.exec(Time.at(time).localtime(offset))
118
+ format.exec(time.to_time.localtime(offset))
108
119
  }
109
120
  else
110
121
  return Proc.new {|time|
111
- Time.at(time).localtime(offset).iso8601
122
+ time.to_time.localtime(offset).iso8601
112
123
  }
113
124
  end
114
125
  end
@@ -124,15 +135,18 @@ module Fluent
124
135
  case
125
136
  when format.is_a?(String)
126
137
  return Proc.new {|time|
127
- Time.at(time).localtime(tz.period_for_utc(time).utc_total_offset).strftime(format)
138
+ time = time.to_time
139
+ time.localtime(tz.period_for_utc(time).utc_total_offset).strftime(format)
128
140
  }
129
141
  when format.is_a?(Strftime)
130
142
  return Proc.new {|time|
131
- format.exec(Time.at(time).localtime(tz.period_for_utc(time).utc_total_offset))
143
+ time = time.to_time
144
+ format.exec(time.localtime(tz.period_for_utc(time).utc_total_offset))
132
145
  }
133
146
  else
134
147
  return Proc.new {|time|
135
- Time.at(time).localtime(tz.period_for_utc(time).utc_total_offset).iso8601
148
+ time = time.to_time
149
+ time.localtime(tz.period_for_utc(time).utc_total_offset).iso8601
136
150
  }
137
151
  end
138
152
  end
@@ -149,7 +163,7 @@ module Fluent
149
163
  when NAME_PATTERN
150
164
  tz = TZInfo::Timezone.get(timezone)
151
165
  ->(time) {
152
- tz.period_for_utc(time).utc_total_offset
166
+ tz.period_for_utc(time.to_time).utc_total_offset
153
167
  }
154
168
  end
155
169
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.6.3'
19
+ VERSION = '1.7.0'
20
20
 
21
21
  end
@@ -807,7 +807,7 @@ CONF
807
807
  )
808
808
  end
809
809
 
810
- test 'success to start workers when configured plugins as a chidren of MultiOutput only for specific worker do not support multi worker configuration' do
810
+ test 'success to start workers when configured plugins as a children of MultiOutput only for specific worker do not support multi worker configuration' do
811
811
  script = <<-EOC
812
812
  require 'fluent/plugin/output'
813
813
  module Fluent::Plugin
@@ -16,6 +16,14 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
16
16
  FileUtils.rm_rf(TEMP_DIR)
17
17
  end
18
18
 
19
+ def stub_git_process(target)
20
+ stub(target).spawn do |cmd, arg1, arg2|
21
+ assert_equal %w[git init .], [cmd, arg1, arg2]
22
+ -1
23
+ end
24
+ stub(Process).wait { |pid| assert_equal(pid, -1) }
25
+ end
26
+
19
27
  sub_test_case "generate plugin" do
20
28
  data(input: ["input", "in"],
21
29
  output: ["output", "out"],
@@ -23,8 +31,10 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
23
31
  parser: ["parser", "parser"],
24
32
  formatter: ["formatter", "formatter"])
25
33
  test "generate plugin" do |(type, part)|
34
+ generator = FluentPluginGenerator.new([type, "fake"])
35
+ stub_git_process(generator)
26
36
  capture_stdout do
27
- FluentPluginGenerator.new([type, "fake"]).call
37
+ generator.call
28
38
  end
29
39
  plugin_base_dir = Pathname("fluent-plugin-fake")
30
40
  assert { plugin_base_dir.directory? }
@@ -49,8 +59,10 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
49
59
  end
50
60
 
51
61
  test "no license" do
62
+ generator = FluentPluginGenerator.new(["--no-license", "filter", "fake"])
63
+ stub_git_process(generator)
52
64
  capture_stdout do
53
- FluentPluginGenerator.new(["--no-license", "filter", "fake"]).call
65
+ generator.call
54
66
  end
55
67
  assert { !Pathname("fluent-plugin-fake/LICENSE").exist? }
56
68
  assert { Pathname("fluent-plugin-fake/Gemfile").exist? }
@@ -72,6 +84,8 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
72
84
  "dash" => ["rewrite-tag-filter", "rewrite_tag_filter"])
73
85
  test "plugin_name" do |(name, plugin_name)|
74
86
  generator = FluentPluginGenerator.new(["filter", name])
87
+ stub_git_process(generator)
88
+ stub(Process).wait { |pid| assert_equal(pid, -1) }
75
89
  capture_stdout do
76
90
  generator.call
77
91
  end
@@ -83,6 +97,8 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
83
97
  "dash" => ["rewrite-tag-filter", "fluent-plugin-rewrite-tag-filter"])
84
98
  test "gem_name" do |(name, gem_name)|
85
99
  generator = FluentPluginGenerator.new(["output", name])
100
+ stub_git_process(generator)
101
+ stub(Process).wait { |pid| assert_equal(pid, -1) }
86
102
  capture_stdout do
87
103
  generator.call
88
104
  end
@@ -152,7 +152,7 @@ module ConfigurableSpec
152
152
  config_param :arrayvalue, :array
153
153
  end
154
154
 
155
- class Example1
155
+ class ExampleWithAlias
156
156
  include Fluent::Configurable
157
157
 
158
158
  config_param :name, :string, alias: :fullname
@@ -166,22 +166,7 @@ module ConfigurableSpec
166
166
  end
167
167
  end
168
168
 
169
- class Example3
170
- include Fluent::Configurable
171
-
172
- config_param :age, :integer, default: 10
173
-
174
- config_section :appendix, required: true, multi: false, final: true do
175
- config_param :type, :string
176
- config_param :name, :string, default: "x"
177
- end
178
-
179
- def get_all
180
- [@name, @detail]
181
- end
182
- end
183
-
184
- class Example5
169
+ class ExampleWithSecret
185
170
  include Fluent::Configurable
186
171
 
187
172
  config_param :normal_param, :string
@@ -193,17 +178,42 @@ module ConfigurableSpec
193
178
  end
194
179
  end
195
180
 
196
- class Example6
181
+ class ExampleWithDefaultHashAndArray
197
182
  include Fluent::Configurable
198
183
  config_param :obj1, :hash, default: {}
199
184
  config_param :obj2, :array, default: []
200
185
  end
201
186
 
202
- class Example7
187
+ class ExampleWithSkipAccessor
203
188
  include Fluent::Configurable
204
189
  config_param :name, :string, default: 'example7', skip_accessor: true
205
190
  end
206
191
 
192
+ class ExampleWithCustomSection
193
+ include Fluent::Configurable
194
+ config_param :name_param, :string
195
+ config_section :normal_section do
196
+ config_param :normal_section_param, :string
197
+ end
198
+
199
+ class CustomSection
200
+ include Fluent::Configurable
201
+ config_param :custom_section_param, :string
202
+ end
203
+
204
+ class AnotherElement
205
+ include Fluent::Configurable
206
+ end
207
+
208
+ def configure(conf)
209
+ super
210
+ conf.elements.each do |e|
211
+ next if e.name != 'custom_section'
212
+ CustomSection.new.configure(e)
213
+ end
214
+ end
215
+ end
216
+
207
217
  module Overwrite
208
218
  class Base
209
219
  include Fluent::Configurable
@@ -564,12 +574,12 @@ module Fluent::Config
564
574
 
565
575
  sub_test_case 'default values should be duplicated before touched in plugin code' do
566
576
  test 'default object should be dupped for cases configured twice' do
567
- x6a = ConfigurableSpec::Example6.new
577
+ x6a = ConfigurableSpec::ExampleWithDefaultHashAndArray.new
568
578
  assert_nothing_raised { x6a.configure(config_element("")) }
569
579
  assert_equal({}, x6a.obj1)
570
580
  assert_equal([], x6a.obj2)
571
581
 
572
- x6b = ConfigurableSpec::Example6.new
582
+ x6b = ConfigurableSpec::ExampleWithDefaultHashAndArray.new
573
583
  assert_nothing_raised { x6b.configure(config_element("")) }
574
584
  assert_equal({}, x6b.obj1)
575
585
  assert_equal([], x6b.obj2)
@@ -577,7 +587,7 @@ module Fluent::Config
577
587
  assert { x6a.obj1.object_id != x6b.obj1.object_id }
578
588
  assert { x6a.obj2.object_id != x6b.obj2.object_id }
579
589
 
580
- x6c = ConfigurableSpec::Example6.new
590
+ x6c = ConfigurableSpec::ExampleWithDefaultHashAndArray.new
581
591
  assert_nothing_raised { x6c.configure(config_element("")) }
582
592
  assert_equal({}, x6c.obj1)
583
593
  assert_equal([], x6c.obj2)
@@ -1184,7 +1194,7 @@ module Fluent::Config
1184
1194
  sub_test_case 'class defined with config_param/config_section having :alias' do
1185
1195
  sub_test_case '#initialize' do
1186
1196
  test 'does not create methods for alias' do
1187
- ex1 = ConfigurableSpec::Example1.new
1197
+ ex1 = ConfigurableSpec::ExampleWithAlias.new
1188
1198
  assert_nothing_raised { ex1.name }
1189
1199
  assert_raise(NoMethodError) { ex1.fullname }
1190
1200
  assert_nothing_raised { ex1.bool }
@@ -1196,7 +1206,7 @@ module Fluent::Config
1196
1206
 
1197
1207
  sub_test_case '#configure' do
1198
1208
  test 'provides accessible data for alias attribute keys' do
1199
- ex1 = ConfigurableSpec::Example1.new
1209
+ ex1 = ConfigurableSpec::ExampleWithAlias.new
1200
1210
  conf = config_element('ROOT', '', {
1201
1211
  "fullname" => "foo bar",
1202
1212
  "bool" => false
@@ -1288,7 +1298,7 @@ module Fluent::Config
1288
1298
  'secret_param' => 'secret'
1289
1299
  },
1290
1300
  [config_element('section', '', {'normal_param2' => 'normal', 'secret_param2' => 'secret'} )])
1291
- @example = ConfigurableSpec::Example5.new
1301
+ @example = ConfigurableSpec::ExampleWithSecret.new
1292
1302
  @example.configure(@conf)
1293
1303
  end
1294
1304
 
@@ -1311,20 +1321,6 @@ module Fluent::Config
1311
1321
  }
1312
1322
  end
1313
1323
 
1314
- test 'get plugin name when found unknown section' do
1315
- @conf = config_element('ROOT', '',
1316
- {
1317
- 'normal_param' => 'normal',
1318
- 'secret_param' => 'secret'
1319
- },
1320
- [config_element('unknown', '', {'normal_param2' => 'normal', 'secret_param2' => 'secret'} )])
1321
- @example = ConfigurableSpec::Example5.new
1322
- @example.configure(@conf)
1323
- @conf.elements.each { |e|
1324
- assert_equal(['ROOT', nil], e.unused_in)
1325
- }
1326
- end
1327
-
1328
1324
  def assert_secret_param(key, value)
1329
1325
  case key
1330
1326
  when 'normal_param', 'normal_param2'
@@ -1335,9 +1331,51 @@ module Fluent::Config
1335
1331
  end
1336
1332
  end
1337
1333
 
1334
+ sub_test_case 'unused section' do
1335
+ test 'get plugin name when found unknown section' do
1336
+ conf = config_element('ROOT', '',
1337
+ {
1338
+ 'name_param' => 'name',
1339
+ },
1340
+ [config_element('unknown', '', {'name_param' => 'normal'} )])
1341
+ example = ConfigurableSpec::ExampleWithCustomSection.new
1342
+ example.configure(conf)
1343
+ conf.elements.each { |e|
1344
+ assert_equal(['ROOT', nil], e.unused_in)
1345
+ }
1346
+ end
1347
+
1348
+ test 'get an empty array when the section is defined without using config_section' do
1349
+ conf = config_element('ROOT', '',
1350
+ {
1351
+ 'name_param' => 'name',
1352
+ },
1353
+ [config_element('custom_section', '', {'custom_section_param' => 'custom'} )])
1354
+ example = ConfigurableSpec::ExampleWithCustomSection.new
1355
+ example.configure(conf)
1356
+ conf.elements.each { |e|
1357
+ assert_equal([], e.unused_in)
1358
+ }
1359
+ end
1360
+
1361
+ test 'get an empty array when the configuration is used in another element without any sections' do
1362
+ conf = config_element('ROOT', '',
1363
+ {
1364
+ 'name_param' => 'name',
1365
+ },
1366
+ [config_element('normal_section', '', {'normal_section_param' => 'normal'} )])
1367
+ example = ConfigurableSpec::ExampleWithCustomSection.new
1368
+ example.configure(conf)
1369
+ ConfigurableSpec::ExampleWithCustomSection::AnotherElement.new.configure(conf)
1370
+ conf.elements.each { |e|
1371
+ assert_equal([], e.unused_in)
1372
+ }
1373
+ end
1374
+ end
1375
+
1338
1376
  sub_test_case ':skip_accessor option' do
1339
1377
  test 'it does not create accessor methods for parameters' do
1340
- @example = ConfigurableSpec::Example7.new
1378
+ @example = ConfigurableSpec::ExampleWithSkipAccessor.new
1341
1379
  @example.configure(config_element('ROOT'))
1342
1380
  assert_equal 'example7', @example.instance_variable_get(:@name)
1343
1381
  assert_raise NoMethodError.new("undefined method `name' for #{@example}") do
@@ -14,7 +14,7 @@ class CounterStoreTest < ::Test::Unit::TestCase
14
14
  @now = Fluent::EventTime.now
15
15
  end
16
16
 
17
- shutdown do
17
+ teardown do
18
18
  Timecop.return
19
19
  end
20
20
 
data/test/helper.rb CHANGED
@@ -50,6 +50,7 @@ require 'fluent/msgpack_factory'
50
50
  require 'fluent/time'
51
51
  require 'serverengine'
52
52
  require 'helpers/fuzzy_assert'
53
+ require 'helpers/process_extenstion'
53
54
 
54
55
  module Fluent
55
56
  module Plugin
@@ -0,0 +1,33 @@
1
+ require 'timecop'
2
+
3
+ module Process
4
+ class << self
5
+ alias_method :clock_gettime_original, :clock_gettime
6
+
7
+ def clock_gettime(clock_id, unit = :float_second)
8
+ # now only support CLOCK_REALTIME
9
+ if Process::CLOCK_REALTIME == clock_id
10
+ t = Time.now
11
+
12
+ case unit
13
+ when :float_second
14
+ t.to_i + t.nsec / 1_000_000_000.0
15
+ when :float_millisecond
16
+ t.to_i * 1_000 + t.nsec / 1_000_000.0
17
+ when :float_microsecond
18
+ t.to_i * 1_000_000 + t.nsec / 1_000.0
19
+ when :second
20
+ t.to_i
21
+ when :millisecond
22
+ t.to_i * 1000 + t.nsec / 1_000_000
23
+ when :microsecond
24
+ t.to_i * 1_000_000 + t.nsec / 1_000
25
+ when :nanosecond
26
+ t.to_i * 1_000_000_000 + t.nsec
27
+ end
28
+ else
29
+ Process.clock_gettime_original(clock_id, unit)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../../helper'
2
+ require 'fluent/test/driver/output'
3
+ require 'flexmock/test_unit'
4
+
5
+ require 'fluent/plugin/out_forward'
6
+ require 'fluent/plugin/out_forward/ack_handler'
7
+
8
+ class AckHandlerTest < Test::Unit::TestCase
9
+ data(
10
+ 'chunk_id is matched' => [MessagePack.pack({ 'ack' => Base64.encode64('chunk_id 111') }), Fluent::Plugin::ForwardOutput::AckHandler::Result::SUCCESS],
11
+ 'chunk_id is not matched' => [MessagePack.pack({ 'ack' => 'unmatched' }), Fluent::Plugin::ForwardOutput::AckHandler::Result::CHUNKID_UNMATCHED],
12
+ 'chunk_id is empty' => ['', Fluent::Plugin::ForwardOutput::AckHandler::Result::FAILED],
13
+ )
14
+ test 'returns chunk_id, node, sock and result status' do |args|
15
+ receved, state = args
16
+ ack_handler = Fluent::Plugin::ForwardOutput::AckHandler.new(timeout: 10, log: $log, read_length: 100)
17
+
18
+ node = flexmock('node', host: '127.0.0.1', port: '1000') # for log
19
+ chunk_id = 'chunk_id 111'
20
+ ack = ack_handler.create_ack(chunk_id, node)
21
+
22
+ r, w = IO.pipe
23
+ begin
24
+ w.write(chunk_id)
25
+ mock(r).recv(anything) { |_| receved } # IO does not have recv
26
+ ack.enqueue(r)
27
+
28
+ a1 = a2 = a3 = a4 = nil
29
+ ack_handler.collect_response(1) do |cid, n, s, ret|
30
+ # This block is rescued by ack_handler so it needs to invoke assetion outside of this block
31
+ a1 = cid; a2 = n; a3 = s; a4 = ret
32
+ end
33
+
34
+ assert_equal chunk_id, a1
35
+ assert_equal node, a2
36
+ assert_equal r, a3
37
+ assert_equal state, a4
38
+ ensure
39
+ r.close rescue nil
40
+ w.close rescue nil
41
+ end
42
+ end
43
+
44
+ test 'returns nil if raise an error' do
45
+ ack_handler = Fluent::Plugin::ForwardOutput::AckHandler.new(timeout: 10, log: $log, read_length: 100)
46
+
47
+ node = flexmock('node', host: '127.0.0.1', port: '1000') # for log
48
+ chunk_id = 'chunk_id 111'
49
+ ack = ack_handler.create_ack(chunk_id, node)
50
+
51
+ r, w = IO.pipe
52
+ begin
53
+ w.write(chunk_id)
54
+ mock(r).recv(anything) { |_| raise 'unexpected error' } # IO does not have recv
55
+ ack.enqueue(r)
56
+
57
+ a1 = a2 = a3 = a4 = nil
58
+ ack_handler.collect_response(1) do |cid, n, s, ret|
59
+ # This block is rescued by ack_handler so it needs to invoke assetion outside of this block
60
+ a1 = cid; a2 = n; a3 = s; a4 = ret
61
+ end
62
+
63
+ assert_nil a1
64
+ assert_nil a2
65
+ assert_nil a3
66
+ assert_equal Fluent::Plugin::ForwardOutput::AckHandler::Result::FAILED, a4
67
+ ensure
68
+ r.close rescue nil
69
+ w.close rescue nil
70
+ end
71
+ end
72
+
73
+ test 'when ack is expired' do
74
+ ack_handler = Fluent::Plugin::ForwardOutput::AckHandler.new(timeout: 0, log: $log, read_length: 100)
75
+
76
+ node = flexmock('node', host: '127.0.0.1', port: '1000') # for log
77
+ chunk_id = 'chunk_id 111'
78
+ ack = ack_handler.create_ack(chunk_id, node)
79
+
80
+ r, w = IO.pipe
81
+ begin
82
+ w.write(chunk_id)
83
+ mock(r).recv(anything).never
84
+ ack.enqueue(r)
85
+
86
+ a1 = a2 = a3 = a4 = nil
87
+ ack_handler.collect_response(1) do |cid, n, s, ret|
88
+ # This block is rescued by ack_handler so it needs to invoke assetion outside of this block
89
+ a1 = cid; a2 = n; a3 = s; a4 = ret
90
+ end
91
+
92
+ assert_equal chunk_id, a1
93
+ assert_equal node, a2
94
+ assert_equal r, a3
95
+ assert_equal Fluent::Plugin::ForwardOutput::AckHandler::Result::FAILED, a4
96
+ ensure
97
+ r.close rescue nil
98
+ w.close rescue nil
99
+ end
100
+ end
101
+ end