fluentd 1.10.1 → 1.11.1

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +112 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/lib/fluent/command/debug.rb +1 -0
  5. data/lib/fluent/command/fluentd.rb +12 -1
  6. data/lib/fluent/config.rb +1 -0
  7. data/lib/fluent/log.rb +45 -6
  8. data/lib/fluent/match.rb +1 -1
  9. data/lib/fluent/plugin/in_dummy.rb +2 -2
  10. data/lib/fluent/plugin/in_forward.rb +2 -2
  11. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  12. data/lib/fluent/plugin/in_http.rb +146 -75
  13. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  14. data/lib/fluent/plugin/in_syslog.rb +4 -4
  15. data/lib/fluent/plugin/in_tail.rb +4 -4
  16. data/lib/fluent/plugin/in_unix.rb +77 -77
  17. data/lib/fluent/plugin/out_copy.rb +1 -1
  18. data/lib/fluent/plugin/out_file.rb +1 -1
  19. data/lib/fluent/plugin/out_forward.rb +23 -18
  20. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  21. data/lib/fluent/plugin/out_http.rb +15 -2
  22. data/lib/fluent/plugin/parser_multiline.rb +1 -1
  23. data/lib/fluent/plugin/parser_syslog.rb +215 -54
  24. data/lib/fluent/plugin_helper/child_process.rb +3 -2
  25. data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
  26. data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
  27. data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
  28. data/lib/fluent/plugin_helper/socket.rb +20 -2
  29. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  30. data/lib/fluent/supervisor.rb +21 -9
  31. data/lib/fluent/system_config.rb +2 -1
  32. data/lib/fluent/test/filter_test.rb +2 -2
  33. data/lib/fluent/test/output_test.rb +3 -3
  34. data/lib/fluent/version.rb +1 -1
  35. data/test/command/test_fluentd.rb +57 -10
  36. data/test/config/test_system_config.rb +2 -0
  37. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  38. data/test/plugin/test_in_gc_stat.rb +24 -1
  39. data/test/plugin/test_in_http.rb +57 -0
  40. data/test/plugin/test_in_syslog.rb +1 -1
  41. data/test/plugin/test_in_tail.rb +20 -16
  42. data/test/plugin/test_in_unix.rb +128 -73
  43. data/test/plugin/test_out_forward.rb +11 -2
  44. data/test/plugin/test_out_http.rb +38 -0
  45. data/test/plugin/test_out_null.rb +1 -1
  46. data/test/plugin/test_output_as_buffered_retries.rb +12 -4
  47. data/test/plugin/test_parser_syslog.rb +66 -29
  48. data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +27 -0
  49. data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +20 -0
  50. data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +27 -0
  51. data/test/plugin_helper/data/cert/cert_chains/cert.pem +40 -0
  52. data/test/plugin_helper/data/cert/generate_cert.rb +38 -0
  53. data/test/plugin_helper/http_server/test_app.rb +1 -1
  54. data/test/plugin_helper/http_server/test_route.rb +1 -1
  55. data/test/plugin_helper/test_child_process.rb +15 -0
  56. data/test/plugin_helper/test_http_server_helper.rb +2 -2
  57. data/test/plugin_helper/test_record_accessor.rb +41 -0
  58. data/test/plugin_helper/test_server.rb +1 -1
  59. data/test/plugin_helper/test_service_discovery.rb +37 -4
  60. data/test/plugin_helper/test_socket.rb +131 -0
  61. data/test/test_log.rb +44 -0
  62. metadata +12 -2
@@ -60,6 +60,14 @@ module Fluent
60
60
  end
61
61
  end
62
62
 
63
+ %i[after_start stop before_shutdown shutdown after_shutdown close terminate].each do |mth|
64
+ define_method(mth) do
65
+ @discoveries.each do |d|
66
+ d.__send__(mth)
67
+ end
68
+ end
69
+ end
70
+
63
71
  def run_once
64
72
  # Don't care race in this loop intentionally
65
73
  s = @queue.size
@@ -145,9 +145,16 @@ module Fluent
145
145
  context.ciphers = ciphers
146
146
  context.verify_mode = OpenSSL::SSL::VERIFY_PEER
147
147
  context.cert_store = cert_store
148
- context.verify_hostname = true if verify_fqdn && fqdn && context.respond_to?(:verify_hostname=)
149
- context.cert = OpenSSL::X509::Certificate.new(File.read(cert_path)) if cert_path
148
+ context.verify_hostname = verify_fqdn && fqdn
150
149
  context.key = OpenSSL::PKey::read(File.read(private_key_path), private_key_passphrase) if private_key_path
150
+
151
+ if cert_path
152
+ certs = socket_certificates_from_file(cert_path)
153
+ context.cert = certs.shift
154
+ unless certs.empty?
155
+ context.extra_chain_cert = certs
156
+ end
157
+ end
151
158
  end
152
159
  Fluent::TLS.set_version_to_context(context, version, min_version, max_version)
153
160
 
@@ -186,6 +193,17 @@ module Fluent
186
193
  end
187
194
  end
188
195
 
196
+ def socket_certificates_from_file(path)
197
+ data = File.read(path)
198
+ pattern = Regexp.compile('-+BEGIN CERTIFICATE-+\r?\n(?:[^-]*\r?\n)+-+END CERTIFICATE-+\r?\n?', Regexp::MULTILINE)
199
+ list = []
200
+ data.scan(pattern) { |match| list << OpenSSL::X509::Certificate.new(match) }
201
+ if list.length == 0
202
+ log.warn "cert_path does not contain a valid certificate"
203
+ end
204
+ list
205
+ end
206
+
189
207
  def self.tls_verify_result_name(code)
190
208
  case code
191
209
  when OpenSSL::X509::V_OK then 'V_OK'
@@ -67,8 +67,8 @@ module Fluent
67
67
  end
68
68
  else
69
69
  if linger_timeout
70
- optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
71
- socket_option_set_one(sock, :SO_LINGER, optval)
70
+ optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
71
+ socket_option_set_one(sock, :SO_LINGER, optval)
72
72
  end
73
73
  end
74
74
  if recv_timeout
@@ -301,6 +301,7 @@ module Fluent
301
301
 
302
302
  log_level = params['log_level']
303
303
  suppress_repeated_stacktrace = params['suppress_repeated_stacktrace']
304
+ ignore_repeated_log_interval = params['ignore_repeated_log_interval']
304
305
 
305
306
  log_path = params['log_path']
306
307
  chuser = params['chuser']
@@ -308,7 +309,7 @@ module Fluent
308
309
  log_rotate_age = params['log_rotate_age']
309
310
  log_rotate_size = params['log_rotate_size']
310
311
 
311
- log_opts = {suppress_repeated_stacktrace: suppress_repeated_stacktrace}
312
+ log_opts = {suppress_repeated_stacktrace: suppress_repeated_stacktrace, ignore_repeated_log_interval: ignore_repeated_log_interval}
312
313
  logger_initializer = Supervisor::LoggerInitializer.new(
313
314
  log_path, log_level, chuser, chgroup, log_opts,
314
315
  log_rotate_age: log_rotate_age,
@@ -345,6 +346,7 @@ module Fluent
345
346
  chgroup: chgroup,
346
347
  chumask: 0,
347
348
  suppress_repeated_stacktrace: suppress_repeated_stacktrace,
349
+ ignore_repeated_log_interval: ignore_repeated_log_interval,
348
350
  daemonize: daemonize,
349
351
  rpc_endpoint: params['rpc_endpoint'],
350
352
  counter_server: params['counter_server'],
@@ -439,9 +441,10 @@ module Fluent
439
441
  self
440
442
  end
441
443
 
442
- def apply_options(format: nil, time_format: nil, log_dir_perm: nil)
444
+ def apply_options(format: nil, time_format: nil, log_dir_perm: nil, ignore_repeated_log_interval: nil)
443
445
  $log.format = format if format
444
446
  $log.time_format = time_format if time_format
447
+ $log.ignore_repeated_log_interval = ignore_repeated_log_interval if ignore_repeated_log_interval
445
448
 
446
449
  if @path && log_dir_perm
447
450
  File.chmod(log_dir_perm || 0755, File.dirname(@path))
@@ -468,6 +471,7 @@ module Fluent
468
471
  root_dir: nil,
469
472
  suppress_interval: 0,
470
473
  suppress_repeated_stacktrace: true,
474
+ ignore_repeated_log_interval: nil,
471
475
  without_source: nil,
472
476
  use_v1_config: true,
473
477
  strict_config_value: nil,
@@ -507,7 +511,7 @@ module Fluent
507
511
  @cl_opt = opt
508
512
  @conf = nil
509
513
 
510
- log_opts = { suppress_repeated_stacktrace: opt[:suppress_repeated_stacktrace] }
514
+ log_opts = {suppress_repeated_stacktrace: opt[:suppress_repeated_stacktrace], ignore_repeated_log_interval: opt[:ignore_repeated_log_interval]}
511
515
  @log = LoggerInitializer.new(
512
516
  @log_path, opt[:log_level], @chuser, @chgroup, log_opts,
513
517
  log_rotate_age: @log_rotate_age,
@@ -552,7 +556,7 @@ module Fluent
552
556
  end
553
557
 
554
558
  if dry_run
555
- $log.info 'finsihed dry run mode'
559
+ $log.info 'finished dry run mode'
556
560
  exit 0
557
561
  else
558
562
  supervise
@@ -589,7 +593,10 @@ module Fluent
589
593
 
590
594
  main_process do
591
595
  create_socket_manager if @standalone_worker
592
- ServerEngine::Privilege.change(@chuser, @chgroup) if @standalone_worker
596
+ if @standalone_worker
597
+ ServerEngine::Privilege.change(@chuser, @chgroup)
598
+ File.umask(0)
599
+ end
593
600
  MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
594
601
  Fluent::Engine.init(@system_config)
595
602
  Fluent::Engine.run_configure(@conf)
@@ -628,6 +635,7 @@ module Fluent
628
635
  format: @system_config.log.format,
629
636
  time_format: @system_config.log.time_format,
630
637
  log_dir_perm: @system_config.dir_permission,
638
+ ignore_repeated_log_interval: @system_config.ignore_repeated_log_interval
631
639
  )
632
640
 
633
641
  $log.info :supervisor, 'parsing config file is succeeded', path: @config_path
@@ -690,6 +698,7 @@ module Fluent
690
698
  'root_dir' => @system_config.root_dir,
691
699
  'log_level' => @system_config.log_level,
692
700
  'suppress_repeated_stacktrace' => @system_config.suppress_repeated_stacktrace,
701
+ 'ignore_repeated_log_interval' => @system_config.ignore_repeated_log_interval,
693
702
  'rpc_endpoint' => @system_config.rpc_endpoint,
694
703
  'enable_get_dump' => @system_config.enable_get_dump,
695
704
  'counter_server' => @system_config.counter_server,
@@ -882,7 +891,11 @@ module Fluent
882
891
  RUBY_ENCODING_OPTIONS_REGEX = %r{\A(-E|--encoding=|--internal-encoding=|--external-encoding=)}.freeze
883
892
 
884
893
  def build_spawn_command
885
- fluentd_spawn_cmd = [ServerEngine.ruby_bin_path]
894
+ if ENV['TEST_RUBY_PATH']
895
+ fluentd_spawn_cmd = [ENV['TEST_RUBY_PATH']]
896
+ else
897
+ fluentd_spawn_cmd = [ServerEngine.ruby_bin_path]
898
+ end
886
899
 
887
900
  rubyopt = ENV['RUBYOPT']
888
901
  if rubyopt
@@ -897,10 +910,9 @@ module Fluent
897
910
 
898
911
  # Adding `-h` so that it can avoid ruby's command blocking
899
912
  # e.g. `ruby -Eascii-8bit:ascii-8bit` will block. but `ruby -Eascii-8bit:ascii-8bit -h` won't.
900
- cmd = fluentd_spawn_cmd.join(' ')
901
- _, e, s = Open3.capture3("#{cmd} -h")
913
+ _, e, s = Open3.capture3(*fluentd_spawn_cmd, "-h")
902
914
  if s.exitstatus != 0
903
- $log.error('Invalid option is passed to RUBYOPT', command: cmd, error: e)
915
+ $log.error('Invalid option is passed to RUBYOPT', command: fluentd_spawn_cmd, error: e)
904
916
  exit s.exitstatus
905
917
  end
906
918
 
@@ -24,7 +24,7 @@ module Fluent
24
24
  SYSTEM_CONFIG_PARAMETERS = [
25
25
  :workers, :root_dir, :log_level,
26
26
  :suppress_repeated_stacktrace, :emit_error_log_interval, :suppress_config_dump,
27
- :log_event_verbose,
27
+ :log_event_verbose, :ignore_repeated_log_interval,
28
28
  :without_source, :rpc_endpoint, :enable_get_dump, :process_name,
29
29
  :file_permission, :dir_permission, :counter_server, :counter_client,
30
30
  :strict_config_value, :enable_msgpack_time_support
@@ -34,6 +34,7 @@ module Fluent
34
34
  config_param :root_dir, :string, default: nil
35
35
  config_param :log_level, :enum, list: [:trace, :debug, :info, :warn, :error, :fatal], default: 'info'
36
36
  config_param :suppress_repeated_stacktrace, :bool, default: nil
37
+ config_param :ignore_repeated_log_interval, :time, default: nil
37
38
  config_param :emit_error_log_interval, :time, default: nil
38
39
  config_param :suppress_config_dump, :bool, default: nil
39
40
  config_param :log_event_verbose, :bool, default: nil
@@ -30,12 +30,12 @@ module Fluent
30
30
  attr_reader :filtered
31
31
  attr_accessor :tag
32
32
 
33
- def emit(record, time = Engine.now)
33
+ def emit(record, time = EventTime.now)
34
34
  emit_with_tag(@tag, record, time)
35
35
  end
36
36
  alias_method :filter, :emit
37
37
 
38
- def emit_with_tag(tag, record, time = Engine.now)
38
+ def emit_with_tag(tag, record, time = EventTime.now)
39
39
  @events[tag] ||= MultiEventStream.new
40
40
  @events[tag].add(time, record)
41
41
  end
@@ -41,7 +41,7 @@ module Fluent
41
41
 
42
42
  attr_accessor :tag
43
43
 
44
- def emit(record, time=Engine.now)
44
+ def emit(record, time=EventTime.now)
45
45
  es = OneEventStream.new(time, record)
46
46
  @instance.emit_events(@tag, es)
47
47
  end
@@ -62,7 +62,7 @@ module Fluent
62
62
 
63
63
  attr_accessor :tag
64
64
 
65
- def emit(record, time=Engine.now)
65
+ def emit(record, time=EventTime.now)
66
66
  @entries << [time, record]
67
67
  self
68
68
  end
@@ -110,7 +110,7 @@ module Fluent
110
110
 
111
111
  attr_accessor :tag
112
112
 
113
- def emit(record, time=Engine.now)
113
+ def emit(record, time=EventTime.now)
114
114
  @entries << [time, record]
115
115
  self
116
116
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.10.1'
19
+ VERSION = '1.11.1'
20
20
 
21
21
  end
@@ -16,6 +16,7 @@ class TestFluentdCommand < ::Test::Unit::TestCase
16
16
  FileUtils.mkdir_p(TMP_DIR)
17
17
  @supervisor_pid = nil
18
18
  @worker_pids = []
19
+ ENV["TEST_RUBY_PATH"] = nil
19
20
  end
20
21
 
21
22
  def process_exist?(pid)
@@ -98,7 +99,8 @@ class TestFluentdCommand < ::Test::Unit::TestCase
98
99
 
99
100
  def assert_log_matches(cmdline, *pattern_list, patterns_not_match: [], timeout: 10, env: {})
100
101
  matched = false
101
- assert_error_msg = "matched correctly"
102
+ matched_wrongly = false
103
+ assert_error_msg = ""
102
104
  stdio_buf = ""
103
105
  begin
104
106
  execute_command(cmdline, TMP_DIR, env) do |pid, stdout|
@@ -128,13 +130,18 @@ class TestFluentdCommand < ::Test::Unit::TestCase
128
130
  end
129
131
  end
130
132
  rescue Timeout::Error
131
- assert_error_msg = "execution timeout with command out:\n" + stdio_buf
133
+ assert_error_msg = "execution timeout"
132
134
  rescue => e
133
- assert_error_msg = "unexpected error in launching fluentd: #{e.inspect}\n" + stdio_buf
135
+ assert_error_msg = "unexpected error in launching fluentd: #{e.inspect}"
136
+ else
137
+ assert_error_msg = "log doesn't match" unless matched
134
138
  end
135
- assert matched, assert_error_msg
136
139
 
137
- unless patterns_not_match.empty?
140
+ if patterns_not_match.empty?
141
+ assert_error_msg = build_message(assert_error_msg,
142
+ "<?>\nwas expected to include:\n<?>",
143
+ stdio_buf, pattern_list)
144
+ else
138
145
  lines = stdio_buf.split("\n")
139
146
  patterns_not_match.each do |ptn|
140
147
  matched_wrongly = if ptn.is_a? Regexp
@@ -142,9 +149,17 @@ class TestFluentdCommand < ::Test::Unit::TestCase
142
149
  else
143
150
  lines.any?{|line| line.include?(ptn) }
144
151
  end
145
- assert_false matched_wrongly, "pattern exists in logs wrongly:\n" + stdio_buf
152
+ if matched_wrongly
153
+ assert_error_msg << "\n" unless assert_error_msg.empty?
154
+ assert_error_msg << "pattern exists in logs wrongly: #{ptn}"
155
+ end
146
156
  end
157
+ assert_error_msg = build_message(assert_error_msg,
158
+ "<?>\nwas expected to include:\n<?>\nand not include:\n<?>",
159
+ stdio_buf, pattern_list, patterns_not_match)
147
160
  end
161
+
162
+ assert matched && !matched_wrongly, assert_error_msg
148
163
  end
149
164
 
150
165
  def assert_fluentd_fails_to_start(cmdline, *pattern_list, timeout: 10)
@@ -842,8 +857,7 @@ CONF
842
857
  '-external-encoding' => '--external-encoding=utf-8',
843
858
  '-internal-encoding' => '--internal-encoding=utf-8',
844
859
  )
845
- test "-E option is set to RUBYOPT3" do |opt|
846
- omit "hard to run correctly on Windows. Need to debug." if Fluent.windows?
860
+ test "-E option is set to RUBYOPT" do |opt|
847
861
  conf = <<CONF
848
862
  <source>
849
863
  @type dummy
@@ -854,6 +868,7 @@ CONF
854
868
  </match>
855
869
  CONF
856
870
  conf_path = create_conf_file('rubyopt_test.conf', conf)
871
+ opt << " #{ENV['RUBYOPT']}" if ENV['RUBYOPT']
857
872
  assert_log_matches(
858
873
  create_cmdline(conf_path),
859
874
  *opt.split(' '),
@@ -862,7 +877,7 @@ CONF
862
877
  )
863
878
  end
864
879
 
865
- test "without RUBYOPT" do
880
+ test "without RUBYOPT" do
866
881
  conf = <<CONF
867
882
  <source>
868
883
  @type dummy
@@ -877,7 +892,7 @@ CONF
877
892
  end
878
893
 
879
894
  test 'invalid values are set to RUBYOPT' do
880
- omit "hard to run correctly on Windows. Need to debug." if Fluent.windows?
895
+ omit "hard to run correctly because RUBYOPT=-r/path/to/bundler/setup is required on Windows while this test set invalid RUBYOPT" if Fluent.windows?
881
896
  conf = <<CONF
882
897
  <source>
883
898
  @type dummy
@@ -895,6 +910,38 @@ CONF
895
910
  )
896
911
  end
897
912
 
913
+ # https://github.com/fluent/fluentd/issues/2915
914
+ test "ruby path contains spaces" do
915
+ conf = <<CONF
916
+ <source>
917
+ @type dummy
918
+ tag dummy
919
+ </source>
920
+ <match>
921
+ @type null
922
+ </match>
923
+ CONF
924
+ ruby_path = ServerEngine.ruby_bin_path
925
+ tmp_ruby_path = File.join(TMP_DIR, "ruby with spaces")
926
+ if Fluent.windows?
927
+ tmp_ruby_path << ".bat"
928
+ File.open(tmp_ruby_path, "w") do |file|
929
+ file.write "#{ruby_path} %*"
930
+ end
931
+ else
932
+ FileUtils.ln_sf(ruby_path, tmp_ruby_path)
933
+ end
934
+ ENV["TEST_RUBY_PATH"] = tmp_ruby_path
935
+ cmd_path = File.expand_path(File.dirname(__FILE__) + "../../../bin/fluentd")
936
+ conf_path = create_conf_file('space_mixed_ruby_path_test.conf', conf)
937
+ args = ["bundle", "exec", tmp_ruby_path, cmd_path, "-c", conf_path]
938
+ assert_log_matches(
939
+ args,
940
+ 'spawn command to main:',
941
+ '-Eascii-8bit:ascii-8bit'
942
+ )
943
+ end
944
+
898
945
  test 'success to start workers when file buffer is configured in non-workers way only for specific worker' do
899
946
  conf = <<CONF
900
947
  <system>
@@ -73,6 +73,7 @@ module Fluent::Config
73
73
  assert_nil(sc.root_dir)
74
74
  assert_equal(Fluent::Log::LEVEL_INFO, sc.log_level)
75
75
  assert_nil(sc.suppress_repeated_stacktrace)
76
+ assert_nil(sc.ignore_repeated_log_interval)
76
77
  assert_nil(sc.emit_error_log_interval)
77
78
  assert_nil(sc.suppress_config_dump)
78
79
  assert_nil(sc.without_source)
@@ -86,6 +87,7 @@ module Fluent::Config
86
87
  'root_dir' => ['root_dir', File.join(TMP_DIR, 'root')],
87
88
  'log_level' => ['log_level', 'error'],
88
89
  'suppress_repeated_stacktrace' => ['suppress_repeated_stacktrace', true],
90
+ 'ignore_repeated_log_interval' => ['ignore_repeated_log_interval', 10],
89
91
  'log_event_verbose' => ['log_event_verbose', true],
90
92
  'suppress_config_dump' => ['suppress_config_dump', true],
91
93
  'without_source' => ['without_source', true],
@@ -49,6 +49,44 @@ class LoadBalancerTest < Test::Unit::TestCase
49
49
  end
50
50
  end
51
51
 
52
+ test 'call like round robin without weight=0 node' do
53
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
54
+ n1 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
55
+ n2 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
56
+ n3 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 0)
57
+
58
+ lb.rebuild_weight_array([n1, n2, n3])
59
+
60
+ lb.select_healthy_node do |node|
61
+ # to handle random choice
62
+ if node == n1
63
+ lb.select_healthy_node do |node|
64
+ assert_equal(node, n2)
65
+ end
66
+
67
+ lb.select_healthy_node do |node|
68
+ assert_equal(node, n1)
69
+ end
70
+
71
+ lb.select_healthy_node do |node|
72
+ assert_equal(node, n2)
73
+ end
74
+ else
75
+ lb.select_healthy_node do |node|
76
+ assert_equal(node, n1)
77
+ end
78
+
79
+ lb.select_healthy_node do |node|
80
+ assert_equal(node, n2)
81
+ end
82
+
83
+ lb.select_healthy_node do |node|
84
+ assert_equal(node, n1)
85
+ end
86
+ end
87
+ end
88
+ end
89
+
52
90
  test 'raise an error if all node are unavialble' do
53
91
  lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
54
92
  lb.rebuild_weight_array([flexmock('node', :'standby?' => false, :'available?' => false, weight: 1)])
@@ -56,5 +94,13 @@ class LoadBalancerTest < Test::Unit::TestCase
56
94
  lb.select_healthy_node
57
95
  end
58
96
  end
97
+
98
+ test 'it regards weight=0 node as unavialble' do
99
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
100
+ lb.rebuild_weight_array([flexmock('node', :'standby?' => false, :'available?' => true, weight: 0)])
101
+ assert_raise(Fluent::Plugin::ForwardOutput::NoNodesAvailable) do
102
+ lb.select_healthy_node
103
+ end
104
+ end
59
105
  end
60
106
  end