fluentd 1.6.3 → 1.7.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 (84) 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 +83 -0
  5. data/README.md +5 -1
  6. data/fluentd.gemspec +3 -2
  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.rb +10 -1
  20. data/lib/fluent/plugin/buf_file_single.rb +219 -0
  21. data/lib/fluent/plugin/buffer.rb +62 -63
  22. data/lib/fluent/plugin/buffer/chunk.rb +21 -3
  23. data/lib/fluent/plugin/buffer/file_chunk.rb +44 -12
  24. data/lib/fluent/plugin/buffer/file_single_chunk.rb +314 -0
  25. data/lib/fluent/plugin/buffer/memory_chunk.rb +2 -1
  26. data/lib/fluent/plugin/compressable.rb +10 -6
  27. data/lib/fluent/plugin/filter_grep.rb +2 -2
  28. data/lib/fluent/plugin/formatter_csv.rb +10 -6
  29. data/lib/fluent/plugin/in_syslog.rb +10 -3
  30. data/lib/fluent/plugin/in_tail.rb +7 -2
  31. data/lib/fluent/plugin/in_tcp.rb +34 -7
  32. data/lib/fluent/plugin/multi_output.rb +4 -4
  33. data/lib/fluent/plugin/out_exec_filter.rb +1 -0
  34. data/lib/fluent/plugin/out_file.rb +13 -3
  35. data/lib/fluent/plugin/out_forward.rb +144 -588
  36. data/lib/fluent/plugin/out_forward/ack_handler.rb +161 -0
  37. data/lib/fluent/plugin/out_forward/connection_manager.rb +113 -0
  38. data/lib/fluent/plugin/out_forward/error.rb +28 -0
  39. data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
  40. data/lib/fluent/plugin/out_forward/handshake_protocol.rb +121 -0
  41. data/lib/fluent/plugin/out_forward/load_balancer.rb +111 -0
  42. data/lib/fluent/plugin/out_forward/socket_cache.rb +138 -0
  43. data/lib/fluent/plugin/out_http.rb +231 -0
  44. data/lib/fluent/plugin/output.rb +29 -35
  45. data/lib/fluent/plugin/parser.rb +77 -0
  46. data/lib/fluent/plugin/parser_csv.rb +75 -0
  47. data/lib/fluent/plugin/parser_syslog.rb +106 -3
  48. data/lib/fluent/plugin_helper/server.rb +2 -2
  49. data/lib/fluent/plugin_helper/socket.rb +14 -1
  50. data/lib/fluent/plugin_helper/thread.rb +1 -0
  51. data/lib/fluent/root_agent.rb +1 -1
  52. data/lib/fluent/time.rb +4 -2
  53. data/lib/fluent/timezone.rb +21 -7
  54. data/lib/fluent/version.rb +1 -1
  55. data/test/command/test_fluentd.rb +1 -1
  56. data/test/command/test_plugin_generator.rb +18 -2
  57. data/test/config/test_configurable.rb +78 -40
  58. data/test/counter/test_store.rb +1 -1
  59. data/test/helper.rb +1 -0
  60. data/test/helpers/process_extenstion.rb +33 -0
  61. data/test/plugin/out_forward/test_ack_handler.rb +101 -0
  62. data/test/plugin/out_forward/test_connection_manager.rb +145 -0
  63. data/test/plugin/out_forward/test_handshake_protocol.rb +103 -0
  64. data/test/plugin/out_forward/test_load_balancer.rb +60 -0
  65. data/test/plugin/out_forward/test_socket_cache.rb +139 -0
  66. data/test/plugin/test_buf_file.rb +172 -2
  67. data/test/plugin/test_buf_file_single.rb +801 -0
  68. data/test/plugin/test_buffer.rb +4 -48
  69. data/test/plugin/test_buffer_file_chunk.rb +38 -1
  70. data/test/plugin/test_buffer_file_single_chunk.rb +621 -0
  71. data/test/plugin/test_buffer_memory_chunk.rb +1 -0
  72. data/test/plugin/test_formatter_csv.rb +16 -0
  73. data/test/plugin/test_in_syslog.rb +56 -6
  74. data/test/plugin/test_in_tail.rb +1 -1
  75. data/test/plugin/test_in_tcp.rb +25 -0
  76. data/test/plugin/test_out_forward.rb +150 -201
  77. data/test/plugin/test_out_http.rb +352 -0
  78. data/test/plugin/test_output_as_buffered.rb +27 -24
  79. data/test/plugin/test_parser.rb +40 -0
  80. data/test/plugin/test_parser_csv.rb +83 -0
  81. data/test/plugin/test_parser_syslog.rb +118 -19
  82. data/test/plugin_helper/test_record_accessor.rb +1 -1
  83. data/test/test_time_formatter.rb +140 -121
  84. metadata +35 -6
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
@@ -0,0 +1,145 @@
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/connection_manager'
7
+ require 'fluent/plugin/out_forward/socket_cache'
8
+
9
+ class ConnectionManager < Test::Unit::TestCase
10
+ sub_test_case '#connect' do
11
+ sub_test_case 'when socket_cache is nil' do
12
+ test 'creates socket and does not close when block is not given' do
13
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
14
+ log: $log,
15
+ secure: false,
16
+ connection_factory: -> (_, _, _) { sock = 'sock'; mock(sock).close.never; sock },
17
+ socket_cache: nil,
18
+ )
19
+
20
+ mock.proxy(cm).connect_keepalive(anything).never
21
+ sock, ri = cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: nil)
22
+ assert_equal(sock, 'sock')
23
+ assert_equal(ri.state, :established)
24
+ end
25
+
26
+ test 'creates socket and calls close when block is given' do
27
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
28
+ log: $log,
29
+ secure: false,
30
+ connection_factory: -> (_, _, _) {
31
+ sock = 'sock'
32
+ mock(sock).close.once
33
+ mock(sock).close_write.once
34
+ sock
35
+ },
36
+ socket_cache: nil,
37
+ )
38
+
39
+ mock.proxy(cm).connect_keepalive(anything).never
40
+ cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: nil) do |sock, ri|
41
+ assert_equal(sock, 'sock')
42
+ assert_equal(ri.state, :established)
43
+ end
44
+ end
45
+
46
+ test 'when secure is true, state is helo' do
47
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
48
+ log: $log,
49
+ secure: true,
50
+ connection_factory: -> (_, _, _) { sock = 'sock'; mock(sock).close.never; sock },
51
+ socket_cache: nil,
52
+ )
53
+
54
+ mock.proxy(cm).connect_keepalive(anything).never
55
+ sock, ri = cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: nil)
56
+ assert_equal(sock, 'sock')
57
+ assert_equal(ri.state, :helo)
58
+ end
59
+
60
+ test 'when passed ack' do
61
+ sock = 'sock'
62
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
63
+ log: $log,
64
+ secure: false,
65
+ connection_factory: -> (_, _, _) {
66
+ mock(sock).close.never
67
+ mock(sock).close_write.never
68
+ sock
69
+ },
70
+ socket_cache: nil,
71
+ )
72
+
73
+ mock.proxy(cm).connect_keepalive(anything).never
74
+ ack = mock('ack').enqueue(sock).once.subject
75
+ cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: ack) do |sock, ri|
76
+ assert_equal(sock, 'sock')
77
+ assert_equal(ri.state, :established)
78
+ end
79
+ end
80
+ end
81
+
82
+ sub_test_case 'when socket_cache exists' do
83
+ test 'calls connect_keepalive' do
84
+ cache = Fluent::Plugin::ForwardOutput::SocketCache.new(10, $log)
85
+ mock(cache).checkin('sock').never
86
+
87
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
88
+ log: $log,
89
+ secure: false,
90
+ connection_factory: -> (_, _, _) { sock = 'sock'; mock(sock).close.never; sock },
91
+ socket_cache: cache,
92
+ )
93
+
94
+ mock.proxy(cm).connect_keepalive(host: 'host', port: 1234, hostname: 'hostname', ack: nil).once
95
+
96
+ sock, ri = cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: nil)
97
+ assert_equal(sock, 'sock')
98
+ assert_equal(ri.state, :established)
99
+ end
100
+
101
+ test 'calls connect_keepalive and closes socket with block' do
102
+ cache = Fluent::Plugin::ForwardOutput::SocketCache.new(10, $log)
103
+ mock(cache).checkin('sock').once
104
+
105
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
106
+ log: $log,
107
+ secure: false,
108
+ connection_factory: -> (_, _, _) { sock = 'sock'; mock(sock); sock },
109
+ socket_cache: cache,
110
+ )
111
+
112
+ mock.proxy(cm).connect_keepalive(host: 'host', port: 1234, hostname: 'hostname', ack: nil).once
113
+
114
+ cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: nil) do |sock, ri|
115
+ assert_equal(sock, 'sock')
116
+ assert_equal(ri.state, :established)
117
+ end
118
+ end
119
+
120
+ test 'does not call dec_ref when ack is passed' do
121
+ cache = Fluent::Plugin::ForwardOutput::SocketCache.new(10, $log)
122
+ mock(cache).checkin('sock').never
123
+ sock = 'sock'
124
+ ack = stub('ack').enqueue(sock).once.subject
125
+
126
+ cm = Fluent::Plugin::ForwardOutput::ConnectionManager.new(
127
+ log: $log,
128
+ secure: false,
129
+ connection_factory: -> (_, _, _) {
130
+ mock(sock).close.never
131
+ mock(sock).close_write.never
132
+ sock
133
+ },
134
+ socket_cache: cache,
135
+ )
136
+
137
+ mock.proxy(cm).connect_keepalive(host: 'host', port: 1234, hostname: 'hostname', ack: ack).once
138
+ cm.connect(host: 'host', port: 1234, hostname: 'hostname', ack: ack) do |sock, ri|
139
+ assert_equal(sock, 'sock')
140
+ assert_equal(ri.state, :established)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,103 @@
1
+ require_relative '../../helper'
2
+ require 'flexmock/test_unit'
3
+
4
+ require 'fluent/plugin/out_forward'
5
+ require 'fluent/plugin/out_forward/handshake_protocol'
6
+ require 'fluent/plugin/out_forward/connection_manager'
7
+
8
+ class HandshakeProtocolTest < Test::Unit::TestCase
9
+ sub_test_case '#invok when helo state' do
10
+ test 'sends PING message and change state to pingpong' do
11
+ hostname = 'hostname'
12
+ handshake = Fluent::Plugin::ForwardOutput::HandshakeProtocol.new(log: $log, hostname: hostname, shared_key: 'shared_key', password: nil, username: nil)
13
+ ri = Fluent::Plugin::ForwardOutput::ConnectionManager::RequestInfo.new(:helo)
14
+
15
+ sock = StringIO.new('')
16
+ handshake.invoke(sock, ri, ['HELO', {}])
17
+
18
+ assert_equal(ri.state, :pingpong)
19
+ Fluent::Engine.msgpack_factory.unpacker.feed_each(sock.string) do |ping|
20
+ assert_equal(ping.size, 6)
21
+ assert_equal(ping[0], 'PING')
22
+ assert_equal(ping[1], hostname)
23
+ assert(ping[2].is_a?(String)) # content is hashed value
24
+ assert(ping[3].is_a?(String)) # content is hashed value
25
+ assert_equal(ping[4], '')
26
+ assert_equal(ping[5], '')
27
+ end
28
+ end
29
+
30
+ test 'returns PING message with username if auth exists' do
31
+ hostname = 'hostname'
32
+ username = 'username'
33
+ pass = 'pass'
34
+ handshake = Fluent::Plugin::ForwardOutput::HandshakeProtocol.new(log: $log, hostname: hostname, shared_key: 'shared_key', password: pass, username: username)
35
+ ri = Fluent::Plugin::ForwardOutput::ConnectionManager::RequestInfo.new(:helo)
36
+
37
+ sock = StringIO.new('')
38
+ handshake.invoke(sock, ri, ['HELO', { 'auth' => 'auth' }])
39
+
40
+ assert_equal(ri.state, :pingpong)
41
+ Fluent::Engine.msgpack_factory.unpacker.feed_each(sock.string) do |ping|
42
+ assert_equal(ping.size, 6)
43
+ assert_equal(ping[0], 'PING')
44
+ assert_equal(ping[1], hostname)
45
+ assert(ping[2].is_a?(String)) # content is hashed value
46
+ assert(ping[3].is_a?(String)) # content is hashed value
47
+ assert_equal(ping[4], username)
48
+ assert_not_equal(ping[5], pass) # should be hashed
49
+ end
50
+ end
51
+
52
+ data(
53
+ lack_of_elem: ['HELO'],
54
+ wrong_message: ['HELLO!', {}],
55
+ )
56
+ test 'raises an error when message is' do |msg|
57
+ handshake = Fluent::Plugin::ForwardOutput::HandshakeProtocol.new(log: $log, hostname: 'hostname', shared_key: 'shared_key', password: nil, username: nil)
58
+ ri = Fluent::Plugin::ForwardOutput::ConnectionManager::RequestInfo.new(:helo)
59
+
60
+ sock = StringIO.new('')
61
+ assert_raise(Fluent::Plugin::ForwardOutput::HeloError) do
62
+ handshake.invoke(sock, ri, msg)
63
+ end
64
+
65
+ assert_equal(ri.state, :helo)
66
+ end
67
+ end
68
+
69
+ sub_test_case '#invok when pingpong state' do
70
+ test 'sends PING message and change state to pingpong' do
71
+ handshake = Fluent::Plugin::ForwardOutput::HandshakeProtocol.new(log: $log, hostname: 'hostname', shared_key: 'shared_key', password: nil, username: nil)
72
+ handshake.instance_variable_set(:@shared_key_salt, 'ce1897b0d3dbd76b90d7fb96010dcac3') # to fix salt
73
+
74
+ ri = Fluent::Plugin::ForwardOutput::ConnectionManager::RequestInfo.new(:pingpong, '', '')
75
+ handshake.invoke(
76
+ '',
77
+ ri,
78
+ # 40a3.... = Digest::SHA512.new.update('ce1897b0d3dbd76b90d7fb96010dcac3').update('client_hostname').update('').update('shared_key').hexdigest
79
+ ['PONG', true, '', 'client_hostname', '40a3c5943cc6256e0c5dcf176e97db3826b0909698c330dc8e53d15af63efb47e030d113130255dd6e7ced5176d2999cc2e02a44852d45152503af317b73b33f']
80
+ )
81
+ assert_equal(ri.state, :established)
82
+ end
83
+
84
+ data(
85
+ lack_of_elem: ['PONG', true, '', 'client_hostname'],
86
+ wrong_message: ['WRONG_PONG', true, '', 'client_hostname', '40a3c5943cc6256e0c5dcf176e97db3826b0909698c330dc8e53d15af63efb47e030d113130255dd6e7ced5176d2999cc2e02a44852d45152503af317b73b33f'],
87
+ error_by_server: ['PONG', false, 'error', 'client_hostname', '40a3c5943cc6256e0c5dcf176e97db3826b0909698c330dc8e53d15af63efb47e030d113130255dd6e7ced5176d2999cc2e02a44852d45152503af317b73b33f'],
88
+ same_hostname_as_server: ['PONG', true, '', 'hostname', '40a3c5943cc6256e0c5dcf176e97db3826b0909698c330dc8e53d15af63efb47e030d113130255dd6e7ced5176d2999cc2e02a44852d45152503af317b73b33f'],
89
+ wrong_key: ['PONG', true, '', 'hostname', 'wrong_key'],
90
+ )
91
+ test 'raises an error when message is' do |msg|
92
+ handshake = Fluent::Plugin::ForwardOutput::HandshakeProtocol.new(log: $log, hostname: 'hostname', shared_key: 'shared_key', password: nil, username: nil)
93
+ handshake.instance_variable_set(:@shared_key_salt, 'ce1897b0d3dbd76b90d7fb96010dcac3') # to fix salt
94
+
95
+ ri = Fluent::Plugin::ForwardOutput::ConnectionManager::RequestInfo.new(:pingpong, '', '')
96
+ assert_raise(Fluent::Plugin::ForwardOutput::PingpongError) do
97
+ handshake.invoke('', ri, msg)
98
+ end
99
+
100
+ assert_equal(ri.state, :pingpong)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,60 @@
1
+ require_relative '../../helper'
2
+ require 'flexmock/test_unit'
3
+
4
+ require 'fluent/plugin/out_forward/load_balancer'
5
+
6
+ class LoadBalancerTest < Test::Unit::TestCase
7
+ sub_test_case 'select_healthy_node' do
8
+ test 'select healty node' do
9
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
10
+ n1 = flexmock('node', :'standby?' => false, :'available?' => false, weight: 1)
11
+ n2 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
12
+
13
+ lb.rebuild_weight_array([n1, n2])
14
+ lb.select_healthy_node do |node|
15
+ assert_equal(node, n2)
16
+ end
17
+
18
+ lb.select_healthy_node do |node|
19
+ assert_equal(node, n2)
20
+ end
21
+ end
22
+
23
+ test 'call like round robin' do
24
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
25
+ n1 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
26
+ n2 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
27
+
28
+ lb.rebuild_weight_array([n1, n2])
29
+
30
+ lb.select_healthy_node do |node|
31
+ # to handle random choice
32
+ if node == n1
33
+ lb.select_healthy_node do |node|
34
+ assert_equal(node, n2)
35
+ end
36
+
37
+ lb.select_healthy_node do |node|
38
+ assert_equal(node, n1)
39
+ end
40
+ else
41
+ lb.select_healthy_node do |node|
42
+ assert_equal(node, n1)
43
+ end
44
+
45
+ lb.select_healthy_node do |node|
46
+ assert_equal(node, n2)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ test 'raise an error if all node are unavialble' do
53
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
54
+ lb.rebuild_weight_array([flexmock('node', :'standby?' => false, :'available?' => false, weight: 1)])
55
+ assert_raise(Fluent::Plugin::ForwardOutput::NoNodesAvailable) do
56
+ lb.select_healthy_node
57
+ end
58
+ end
59
+ end
60
+ end