fluentd 0.14.10-x64-mingw32 → 0.14.11-x64-mingw32
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.
- checksums.yaml +4 -4
- data/.travis.yml +14 -6
- data/ChangeLog +28 -2
- data/appveyor.yml +1 -0
- data/lib/fluent/engine.rb +4 -7
- data/lib/fluent/error.rb +30 -0
- data/lib/fluent/log.rb +0 -7
- data/lib/fluent/plugin/base.rb +11 -0
- data/lib/fluent/plugin/buf_file.rb +9 -7
- data/lib/fluent/plugin/formatter_csv.rb +4 -2
- data/lib/fluent/plugin/in_forward.rb +46 -17
- data/lib/fluent/plugin/in_http.rb +2 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +27 -2
- data/lib/fluent/plugin/in_syslog.rb +52 -36
- data/lib/fluent/plugin/in_tail.rb +1 -0
- data/lib/fluent/plugin/out_forward.rb +39 -29
- data/lib/fluent/plugin/output.rb +17 -0
- data/lib/fluent/plugin/storage_local.rb +16 -13
- data/lib/fluent/plugin_helper/storage.rb +21 -9
- data/lib/fluent/plugin_id.rb +17 -0
- data/lib/fluent/supervisor.rb +73 -45
- data/lib/fluent/system_config.rb +24 -21
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +348 -0
- data/test/config/test_system_config.rb +39 -31
- data/test/plugin/test_base.rb +20 -0
- data/test/plugin/test_buf_file.rb +40 -0
- data/test/plugin/test_formatter_csv.rb +8 -0
- data/test/plugin/test_in_forward.rb +56 -21
- data/test/plugin/test_in_monitor_agent.rb +80 -8
- data/test/plugin/test_in_syslog.rb +75 -45
- data/test/plugin/test_out_file.rb +0 -1
- data/test/plugin/test_out_forward.rb +19 -11
- data/test/plugin/test_output.rb +44 -0
- data/test/plugin/test_storage_local.rb +290 -2
- data/test/plugin_helper/test_child_process.rb +40 -39
- data/test/plugin_helper/test_storage.rb +4 -3
- data/test/test_log.rb +1 -1
- data/test/test_output.rb +3 -0
- data/test/test_plugin_id.rb +101 -0
- data/test/test_supervisor.rb +3 -0
- metadata +7 -2
@@ -3,21 +3,8 @@ require 'fluent/test/driver/input'
|
|
3
3
|
require 'fluent/plugin/in_syslog'
|
4
4
|
|
5
5
|
class SyslogInputTest < Test::Unit::TestCase
|
6
|
-
class << self
|
7
|
-
def startup
|
8
|
-
socket_manager_path = ServerEngine::SocketManager::Server.generate_path
|
9
|
-
@server = ServerEngine::SocketManager::Server.open(socket_manager_path)
|
10
|
-
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
|
11
|
-
end
|
12
|
-
|
13
|
-
def shutdown
|
14
|
-
@server.close
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
6
|
def setup
|
19
7
|
Fluent::Test.setup
|
20
|
-
require 'fluent/plugin/socket_util'
|
21
8
|
end
|
22
9
|
|
23
10
|
PORT = unused_port
|
@@ -37,41 +24,45 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
37
24
|
Fluent::Test::Driver::Input.new(Fluent::Plugin::SyslogInput).configure(conf)
|
38
25
|
end
|
39
26
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
27
|
+
data(
|
28
|
+
ipv4: ['127.0.0.1', CONFIG, ::Socket::AF_INET],
|
29
|
+
ipv6: ['::1', IPv6_CONFIG, ::Socket::AF_INET6],
|
30
|
+
)
|
31
|
+
def test_configure(data)
|
32
|
+
bind_addr, config, family = data
|
33
|
+
omit "IPv6 unavailable" if family == ::Socket::AF_INET6 && !ipv6_enabled?
|
34
|
+
|
35
|
+
d = create_driver(config)
|
36
|
+
assert_equal PORT, d.instance.port
|
37
|
+
assert_equal bind_addr, d.instance.bind
|
49
38
|
end
|
50
39
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
40
|
+
data(
|
41
|
+
ipv4: ['127.0.0.1', CONFIG, ::Socket::AF_INET],
|
42
|
+
ipv6: ['::1', IPv6_CONFIG, ::Socket::AF_INET6],
|
43
|
+
)
|
44
|
+
def test_time_format(data)
|
45
|
+
bind_addr, config, family = data
|
46
|
+
omit "IPv6 unavailable" if family == ::Socket::AF_INET6 && !ipv6_enabled?
|
57
47
|
|
58
|
-
|
59
|
-
{'msg' => '<6>Dec 11 00:00:00 localhost logger: foo', 'expected' => Fluent::EventTime.from_time(Time.strptime('Dec 11 00:00:00', '%b %d %H:%M:%S'))},
|
60
|
-
{'msg' => '<6>Dec 1 00:00:00 localhost logger: foo', 'expected' => Fluent::EventTime.from_time(Time.strptime('Dec 1 00:00:00', '%b %d %H:%M:%S'))},
|
61
|
-
]
|
62
|
-
d.run(expect_emits: 2) do
|
63
|
-
u = Fluent::SocketUtil.create_udp_socket(k)
|
64
|
-
u.connect(k, PORT)
|
65
|
-
tests.each {|test|
|
66
|
-
u.send(test['msg'], 0)
|
67
|
-
}
|
68
|
-
end
|
48
|
+
d = create_driver(config)
|
69
49
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
50
|
+
tests = [
|
51
|
+
{'msg' => '<6>Dec 11 00:00:00 localhost logger: foo', 'expected' => Fluent::EventTime.from_time(Time.strptime('Dec 11 00:00:00', '%b %d %H:%M:%S'))},
|
52
|
+
{'msg' => '<6>Dec 1 00:00:00 localhost logger: foo', 'expected' => Fluent::EventTime.from_time(Time.strptime('Dec 1 00:00:00', '%b %d %H:%M:%S'))},
|
53
|
+
]
|
54
|
+
d.run(expect_emits: 2) do
|
55
|
+
u = UDPSocket.new(family)
|
56
|
+
u.connect(bind_addr, PORT)
|
57
|
+
tests.each {|test|
|
58
|
+
u.send(test['msg'], 0)
|
74
59
|
}
|
60
|
+
end
|
61
|
+
|
62
|
+
events = d.events
|
63
|
+
assert(events.size > 0)
|
64
|
+
events.each_index {|i|
|
65
|
+
assert_equal_event_time(tests[i]['expected'], events[i][1])
|
75
66
|
}
|
76
67
|
end
|
77
68
|
|
@@ -179,7 +170,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
179
170
|
compare_test_result(d.events, tests, {host: host})
|
180
171
|
end
|
181
172
|
|
182
|
-
def
|
173
|
+
def test_msg_size_with_priority_key
|
183
174
|
d = create_driver([CONFIG, 'priority_key priority'].join("\n"))
|
184
175
|
tests = create_test_case
|
185
176
|
|
@@ -196,7 +187,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
196
187
|
compare_test_result(d.events, tests, {priority: priority})
|
197
188
|
end
|
198
189
|
|
199
|
-
def
|
190
|
+
def test_msg_size_with_facility_key
|
200
191
|
d = create_driver([CONFIG, 'facility_key facility'].join("\n"))
|
201
192
|
tests = create_test_case
|
202
193
|
|
@@ -213,6 +204,43 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
213
204
|
compare_test_result(d.events, tests, {facility: facility})
|
214
205
|
end
|
215
206
|
|
207
|
+
def test_msg_size_with_source_address_key
|
208
|
+
d = create_driver([CONFIG, 'source_address_key source_address'].join("\n"))
|
209
|
+
tests = create_test_case
|
210
|
+
|
211
|
+
address = nil
|
212
|
+
d.run(expect_emits: 2) do
|
213
|
+
u = UDPSocket.new
|
214
|
+
u.connect('127.0.0.1', PORT)
|
215
|
+
address = u.peeraddr[3]
|
216
|
+
tests.each {|test|
|
217
|
+
u.send(test['msg'], 0)
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
assert(d.events.size > 0)
|
222
|
+
compare_test_result(d.events, tests, {address: address})
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_msg_size_with_source_hostname_key
|
226
|
+
d = create_driver([CONFIG, 'source_hostname_key source_hostname'].join("\n"))
|
227
|
+
tests = create_test_case
|
228
|
+
|
229
|
+
hostname = nil
|
230
|
+
d.run(expect_emits: 2) do
|
231
|
+
u = UDPSocket.new
|
232
|
+
u.do_not_reverse_lookup = false
|
233
|
+
u.connect('127.0.0.1', PORT)
|
234
|
+
hostname = u.peeraddr[2]
|
235
|
+
tests.each {|test|
|
236
|
+
u.send(test['msg'], 0)
|
237
|
+
}
|
238
|
+
end
|
239
|
+
|
240
|
+
assert(d.events.size > 0)
|
241
|
+
compare_test_result(d.events, tests, {hostname: hostname})
|
242
|
+
end
|
243
|
+
|
216
244
|
def create_test_case(large_message: false)
|
217
245
|
# actual syslog message has "\n"
|
218
246
|
if large_message
|
@@ -234,6 +262,8 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
234
262
|
assert_equal('syslog.kern.info', events[i][0]) # <6> means kern.info
|
235
263
|
assert_equal(tests[i]['expected'], events[i][2]['message'])
|
236
264
|
assert_equal(options[:host], events[i][2]['source_host']) if options[:host]
|
265
|
+
assert_equal(options[:address], events[i][2]['source_address']) if options[:address]
|
266
|
+
assert_equal(options[:hostname], events[i][2]['source_hostname']) if options[:hostname]
|
237
267
|
assert_equal(options[:priority], events[i][2]['priority']) if options[:priority]
|
238
268
|
assert_equal(options[:facility], events[i][2]['facility']) if options[:facility]
|
239
269
|
}
|
@@ -136,7 +136,6 @@ class FileOutputTest < Test::Unit::TestCase
|
|
136
136
|
|
137
137
|
test 'configured as secondary with primary using chunk_key_tag and not using chunk_key_time' do
|
138
138
|
require 'fluent/plugin/out_null'
|
139
|
-
port = unused_port
|
140
139
|
conf = config_element('match', '**', {
|
141
140
|
}, [
|
142
141
|
config_element('buffer', 'tag', {
|
@@ -35,16 +35,25 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
35
35
|
|
36
36
|
def create_driver(conf=CONFIG)
|
37
37
|
Fluent::Test::Driver::Output.new(Fluent::Plugin::ForwardOutput) {
|
38
|
-
attr_reader :
|
38
|
+
attr_reader :response_chunk_ids, :exceptions, :sent_chunk_ids
|
39
39
|
|
40
40
|
def initialize
|
41
41
|
super
|
42
|
-
@
|
42
|
+
@sent_chunk_ids = []
|
43
|
+
@response_chunk_ids = []
|
43
44
|
@exceptions = []
|
44
45
|
end
|
45
46
|
|
47
|
+
def try_write(chunk)
|
48
|
+
retval = super
|
49
|
+
@sent_chunk_ids << chunk.unique_id
|
50
|
+
retval
|
51
|
+
end
|
52
|
+
|
46
53
|
def read_ack_from_sock(sock, unpacker)
|
47
|
-
|
54
|
+
retval = super
|
55
|
+
@response_chunk_ids << retval
|
56
|
+
retval
|
48
57
|
rescue => e
|
49
58
|
@exceptions << e
|
50
59
|
raise e
|
@@ -302,7 +311,7 @@ EOL
|
|
302
311
|
assert_equal ['test', time, records[0]], events[0]
|
303
312
|
assert_equal ['test', time, records[1]], events[1]
|
304
313
|
|
305
|
-
assert_empty d.instance.
|
314
|
+
assert_empty d.instance.response_chunk_ids # not attempt to receive responses, so it's empty
|
306
315
|
assert_empty d.instance.exceptions
|
307
316
|
end
|
308
317
|
|
@@ -329,7 +338,7 @@ EOL
|
|
329
338
|
assert_equal ['test', time, records[0]], events[0]
|
330
339
|
assert_equal ['test', time, records[1]], events[1]
|
331
340
|
|
332
|
-
assert_empty d.instance.
|
341
|
+
assert_empty d.instance.response_chunk_ids # not attempt to receive responses, so it's empty
|
333
342
|
assert_empty d.instance.exceptions
|
334
343
|
end
|
335
344
|
|
@@ -354,7 +363,7 @@ EOL
|
|
354
363
|
{"a" => 2}
|
355
364
|
]
|
356
365
|
target_input_driver.run(expect_records: 2) do
|
357
|
-
d.end_if{ d.instance.
|
366
|
+
d.end_if{ d.instance.response_chunk_ids.length > 0 }
|
358
367
|
d.run(default_tag: 'test', wait_flush_completion: false, shutdown: false) do
|
359
368
|
d.feed([[time, records[0]], [time,records[1]]])
|
360
369
|
end
|
@@ -364,7 +373,8 @@ EOL
|
|
364
373
|
assert_equal ['test', time, records[0]], events[0]
|
365
374
|
assert_equal ['test', time, records[1]], events[1]
|
366
375
|
|
367
|
-
assert_equal 1, d.instance.
|
376
|
+
assert_equal 1, d.instance.response_chunk_ids.size
|
377
|
+
assert_equal d.instance.sent_chunk_ids.first, d.instance.response_chunk_ids.first
|
368
378
|
assert_empty d.instance.exceptions
|
369
379
|
end
|
370
380
|
|
@@ -400,7 +410,7 @@ EOL
|
|
400
410
|
end
|
401
411
|
end
|
402
412
|
|
403
|
-
assert_equal 1, delayed_commit_timeout_value
|
413
|
+
assert_equal (1 + 2), delayed_commit_timeout_value
|
404
414
|
|
405
415
|
events = target_input_driver.events
|
406
416
|
assert_equal ['test', time, records[0]], events[0]
|
@@ -409,7 +419,6 @@ EOL
|
|
409
419
|
assert{ d.instance.rollback_count > 0 }
|
410
420
|
|
411
421
|
logs = d.instance.log.logs
|
412
|
-
assert{ logs.any?{|log| log.include?("failed to flush the buffer chunk, timeout to commit.") } }
|
413
422
|
assert{ logs.any?{|log| log.include?("no response from node. regard it as unavailable.") } }
|
414
423
|
end
|
415
424
|
|
@@ -445,7 +454,7 @@ EOL
|
|
445
454
|
end
|
446
455
|
end
|
447
456
|
|
448
|
-
assert_equal 5, delayed_commit_timeout_value
|
457
|
+
assert_equal (5 + 2), delayed_commit_timeout_value
|
449
458
|
|
450
459
|
events = target_input_driver.events
|
451
460
|
assert_equal ['test', time, records[0]], events[0]
|
@@ -454,7 +463,6 @@ EOL
|
|
454
463
|
assert{ d.instance.rollback_count > 0 }
|
455
464
|
|
456
465
|
logs = d.instance.log.logs
|
457
|
-
assert{ logs.any?{|log| log.include?("failed to flush the buffer chunk, timeout to commit.") } }
|
458
466
|
assert{ logs.any?{|log| log.include?("no response from node. regard it as unavailable.") } }
|
459
467
|
end
|
460
468
|
|
data/test/plugin/test_output.rb
CHANGED
@@ -799,4 +799,48 @@ class OutputTest < Test::Unit::TestCase
|
|
799
799
|
assert_equal Fluent::Plugin::Output::FORMAT_MSGPACK_STREAM, i.generate_format_proc
|
800
800
|
end
|
801
801
|
end
|
802
|
+
|
803
|
+
sub_test_case 'slow_flush_log_threshold' do
|
804
|
+
def invoke_slow_flush_log_threshold_test(i)
|
805
|
+
i.configure(config_element('ROOT', '', {'slow_flush_log_threshold' => 0.5}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
|
806
|
+
i.start
|
807
|
+
i.after_start
|
808
|
+
|
809
|
+
t = event_time()
|
810
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
811
|
+
i.force_flush
|
812
|
+
|
813
|
+
waiting(4) { Thread.pass until i.test_finished? }
|
814
|
+
|
815
|
+
yield
|
816
|
+
ensure
|
817
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
818
|
+
end
|
819
|
+
|
820
|
+
test '#write flush took longer time than slow_flush_log_threshold' do
|
821
|
+
i = create_output(:buffered)
|
822
|
+
write_called = false
|
823
|
+
i.register(:write) { |chunk| sleep 1 }
|
824
|
+
i.define_singleton_method(:test_finished?) { write_called }
|
825
|
+
i.define_singleton_method(:try_flush) { super(); write_called = true }
|
826
|
+
|
827
|
+
invoke_slow_flush_log_threshold_test(i) {
|
828
|
+
assert write_called
|
829
|
+
assert_equal 1, i.log.out.logs.select { |line| line =~ /buffer flush took longer time than slow_flush_log_threshold: elapsed_time/ }.size
|
830
|
+
}
|
831
|
+
end
|
832
|
+
|
833
|
+
test '#try_write flush took longer time than slow_flush_log_threshold' do
|
834
|
+
i = create_output(:delayed)
|
835
|
+
try_write_called = false
|
836
|
+
i.register(:try_write){ |chunk| sleep 1 }
|
837
|
+
i.define_singleton_method(:test_finished?) { try_write_called }
|
838
|
+
i.define_singleton_method(:try_flush) { super(); try_write_called = true }
|
839
|
+
|
840
|
+
invoke_slow_flush_log_threshold_test(i) {
|
841
|
+
assert try_write_called
|
842
|
+
assert_equal 1, i.log.out.logs.select { |line| line =~ /buffer flush took longer time than slow_flush_log_threshold: elapsed_time/ }.size
|
843
|
+
}
|
844
|
+
end
|
845
|
+
end
|
802
846
|
end
|
@@ -1,8 +1,296 @@
|
|
1
1
|
require_relative '../helper'
|
2
2
|
require 'fluent/plugin/storage_local'
|
3
|
+
require 'fluent/plugin/input'
|
4
|
+
require 'fluent/system_config'
|
5
|
+
require 'fileutils'
|
3
6
|
|
4
7
|
class LocalStorageTest < Test::Unit::TestCase
|
5
|
-
|
6
|
-
|
8
|
+
TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/tmp/storage_local#{ENV['TEST_ENV_NUMBER']}")
|
9
|
+
|
10
|
+
class MyInput < Fluent::Plugin::Input
|
11
|
+
helpers :storage
|
12
|
+
config_section :storage do
|
13
|
+
config_set_default :@type, 'local'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
setup do
|
18
|
+
FileUtils.rm_rf(TMP_DIR)
|
19
|
+
FileUtils.mkdir_p(TMP_DIR)
|
20
|
+
Fluent::Test.setup
|
21
|
+
@d = MyInput.new
|
22
|
+
end
|
23
|
+
|
24
|
+
teardown do
|
25
|
+
@d.stop unless @d.stopped?
|
26
|
+
@d.before_shutdown unless @d.before_shutdown?
|
27
|
+
@d.shutdown unless @d.shutdown?
|
28
|
+
@d.after_shutdown unless @d.after_shutdown?
|
29
|
+
@d.close unless @d.closed?
|
30
|
+
@d.terminate unless @d.terminated?
|
31
|
+
end
|
32
|
+
|
33
|
+
sub_test_case 'without any configuration' do
|
34
|
+
test 'works as on-memory storage' do
|
35
|
+
conf = config_element()
|
36
|
+
|
37
|
+
@d.configure(conf)
|
38
|
+
@d.start
|
39
|
+
@p = @d.storage_create()
|
40
|
+
|
41
|
+
assert_nil @p.path
|
42
|
+
assert @p.store.empty?
|
43
|
+
|
44
|
+
assert_nil @p.get('key1')
|
45
|
+
assert_equal 'EMPTY', @p.fetch('key1', 'EMPTY')
|
46
|
+
|
47
|
+
@p.put('key1', '1')
|
48
|
+
assert_equal '1', @p.get('key1')
|
49
|
+
|
50
|
+
@p.update('key1') do |v|
|
51
|
+
(v.to_i * 2).to_s
|
52
|
+
end
|
53
|
+
assert_equal '2', @p.get('key1')
|
54
|
+
|
55
|
+
@p.save # on-memory storage does nothing...
|
56
|
+
|
57
|
+
@d.stop; @d.before_shutdown; @d.shutdown; @d.after_shutdown; @d.close; @d.terminate
|
58
|
+
|
59
|
+
# re-create to reload storage contents
|
60
|
+
@d = MyInput.new
|
61
|
+
@d.configure(conf)
|
62
|
+
@d.start
|
63
|
+
@p = @d.storage_create()
|
64
|
+
|
65
|
+
assert @p.store.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
test 'warns about on-memory storage if autosave is true' do
|
69
|
+
@d.configure(config_element())
|
70
|
+
@d.start
|
71
|
+
@p = @d.storage_create()
|
72
|
+
|
73
|
+
logs = @d.log.out.logs
|
74
|
+
assert{ logs.any?{|log| log.include?("[warn]: both of Plugin @id and path for <storage> are not specified. Using on-memory store.") } }
|
75
|
+
end
|
76
|
+
|
77
|
+
test 'show info log about on-memory storage if autosave is false' do
|
78
|
+
@d.configure(config_element('ROOT', '', {}, [config_element('storage', '', {'autosave' => 'false'})]))
|
79
|
+
@d.start
|
80
|
+
@p = @d.storage_create()
|
81
|
+
|
82
|
+
logs = @d.log.out.logs
|
83
|
+
assert{ logs.any?{|log| log.include?("[info]: both of Plugin @id and path for <storage> are not specified. Using on-memory store.") } }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
sub_test_case 'configured with path' do
|
88
|
+
test 'works as storage which stores data on disk' do
|
89
|
+
storage_path = File.join(TMP_DIR, 'my_store.json')
|
90
|
+
conf = config_element('ROOT', '', {}, [config_element('storage', '', {'path' => storage_path})])
|
91
|
+
@d.configure(conf)
|
92
|
+
@d.start
|
93
|
+
@p = @d.storage_create()
|
94
|
+
|
95
|
+
assert_equal storage_path, @p.path
|
96
|
+
assert @p.store.empty?
|
97
|
+
|
98
|
+
assert_nil @p.get('key1')
|
99
|
+
assert_equal 'EMPTY', @p.fetch('key1', 'EMPTY')
|
100
|
+
|
101
|
+
@p.put('key1', '1')
|
102
|
+
assert_equal '1', @p.get('key1')
|
103
|
+
|
104
|
+
@p.update('key1') do |v|
|
105
|
+
(v.to_i * 2).to_s
|
106
|
+
end
|
107
|
+
assert_equal '2', @p.get('key1')
|
108
|
+
|
109
|
+
@p.save # stores all data into file
|
110
|
+
|
111
|
+
assert File.exist?(storage_path)
|
112
|
+
|
113
|
+
@p.put('key2', 4)
|
114
|
+
|
115
|
+
@d.stop; @d.before_shutdown; @d.shutdown; @d.after_shutdown; @d.close; @d.terminate
|
116
|
+
|
117
|
+
assert_equal({'key1' => '2', 'key2' => 4}, File.open(storage_path){|f| JSON.parse(f.read) })
|
118
|
+
|
119
|
+
# re-create to reload storage contents
|
120
|
+
@d = MyInput.new
|
121
|
+
@d.configure(conf)
|
122
|
+
@d.start
|
123
|
+
@p = @d.storage_create()
|
124
|
+
|
125
|
+
assert_false @p.store.empty?
|
126
|
+
|
127
|
+
assert_equal '2', @p.get('key1')
|
128
|
+
assert_equal 4, @p.get('key2')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
sub_test_case 'configured with root-dir and plugin id' do
|
133
|
+
test 'works as storage which stores data under root dir' do
|
134
|
+
root_dir = File.join(TMP_DIR, 'root')
|
135
|
+
expected_storage_path = File.join(root_dir, 'worker0', 'local_storage_test', 'storage.json')
|
136
|
+
conf = config_element('ROOT', '', {'@id' => 'local_storage_test'})
|
137
|
+
Fluent::SystemConfig.overwrite_system_config('root_dir' => root_dir) do
|
138
|
+
@d.configure(conf)
|
139
|
+
end
|
140
|
+
@d.start
|
141
|
+
@p = @d.storage_create()
|
142
|
+
|
143
|
+
assert_equal expected_storage_path, @p.path
|
144
|
+
assert @p.store.empty?
|
145
|
+
|
146
|
+
assert_nil @p.get('key1')
|
147
|
+
assert_equal 'EMPTY', @p.fetch('key1', 'EMPTY')
|
148
|
+
|
149
|
+
@p.put('key1', '1')
|
150
|
+
assert_equal '1', @p.get('key1')
|
151
|
+
|
152
|
+
@p.update('key1') do |v|
|
153
|
+
(v.to_i * 2).to_s
|
154
|
+
end
|
155
|
+
assert_equal '2', @p.get('key1')
|
156
|
+
|
157
|
+
@p.save # stores all data into file
|
158
|
+
|
159
|
+
assert File.exist?(expected_storage_path)
|
160
|
+
|
161
|
+
@p.put('key2', 4)
|
162
|
+
|
163
|
+
@d.stop; @d.before_shutdown; @d.shutdown; @d.after_shutdown; @d.close; @d.terminate
|
164
|
+
|
165
|
+
assert_equal({'key1' => '2', 'key2' => 4}, File.open(expected_storage_path){|f| JSON.parse(f.read) })
|
166
|
+
|
167
|
+
# re-create to reload storage contents
|
168
|
+
@d = MyInput.new
|
169
|
+
Fluent::SystemConfig.overwrite_system_config('root_dir' => root_dir) do
|
170
|
+
@d.configure(conf)
|
171
|
+
end
|
172
|
+
@d.start
|
173
|
+
@p = @d.storage_create()
|
174
|
+
|
175
|
+
assert_false @p.store.empty?
|
176
|
+
|
177
|
+
assert_equal '2', @p.get('key1')
|
178
|
+
assert_equal 4, @p.get('key2')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
sub_test_case 'persistent specified' do
|
183
|
+
test 'works well with path' do
|
184
|
+
omit "It's hard to test on Windows" if Fluent.windows?
|
185
|
+
|
186
|
+
storage_path = File.join(TMP_DIR, 'my_store.json')
|
187
|
+
conf = config_element('ROOT', '', {}, [config_element('storage', '', {'path' => storage_path, 'persistent' => 'true'})])
|
188
|
+
@d.configure(conf)
|
189
|
+
@d.start
|
190
|
+
@p = @d.storage_create()
|
191
|
+
|
192
|
+
assert_equal storage_path, @p.path
|
193
|
+
assert @p.store.empty?
|
194
|
+
|
195
|
+
assert_nil @p.get('key1')
|
196
|
+
assert_equal 'EMPTY', @p.fetch('key1', 'EMPTY')
|
197
|
+
|
198
|
+
@p.put('key1', '1')
|
199
|
+
assert_equal({'key1' => '1'}, File.open(storage_path){|f| JSON.parse(f.read) })
|
200
|
+
|
201
|
+
@p.update('key1') do |v|
|
202
|
+
(v.to_i * 2).to_s
|
203
|
+
end
|
204
|
+
assert_equal({'key1' => '2'}, File.open(storage_path){|f| JSON.parse(f.read) })
|
205
|
+
end
|
206
|
+
|
207
|
+
test 'works well with root-dir and plugin id' do
|
208
|
+
omit "It's hard to test on Windows" if Fluent.windows?
|
209
|
+
|
210
|
+
root_dir = File.join(TMP_DIR, 'root')
|
211
|
+
expected_storage_path = File.join(root_dir, 'worker0', 'local_storage_test', 'storage.json')
|
212
|
+
conf = config_element('ROOT', '', {'@id' => 'local_storage_test'}, [config_element('storage', '', {'persistent' => 'true'})])
|
213
|
+
Fluent::SystemConfig.overwrite_system_config('root_dir' => root_dir) do
|
214
|
+
@d.configure(conf)
|
215
|
+
end
|
216
|
+
@d.start
|
217
|
+
@p = @d.storage_create()
|
218
|
+
|
219
|
+
assert_equal expected_storage_path, @p.path
|
220
|
+
assert @p.store.empty?
|
221
|
+
|
222
|
+
assert_nil @p.get('key1')
|
223
|
+
assert_equal 'EMPTY', @p.fetch('key1', 'EMPTY')
|
224
|
+
|
225
|
+
@p.put('key1', '1')
|
226
|
+
assert_equal({'key1' => '1'}, File.open(expected_storage_path){|f| JSON.parse(f.read) })
|
227
|
+
|
228
|
+
@p.update('key1') do |v|
|
229
|
+
(v.to_i * 2).to_s
|
230
|
+
end
|
231
|
+
assert_equal({'key1' => '2'}, File.open(expected_storage_path){|f| JSON.parse(f.read) })
|
232
|
+
end
|
233
|
+
|
234
|
+
test 'raises error if it is configured to use on-memory storage' do
|
235
|
+
assert_raise Fluent::ConfigError.new("Plugin @id or path for <storage> required when 'persistent' is true") do
|
236
|
+
@d.configure(config_element('ROOT', '', {}, [config_element('storage', '', {'persistent' => 'true'})]))
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
sub_test_case 'with various configurations' do
|
242
|
+
test 'mode and dir_mode controls permissions of stored data' do
|
243
|
+
omit "NTFS doesn't support UNIX like permissions" if Fluent.windows?
|
244
|
+
|
245
|
+
storage_path = File.join(TMP_DIR, 'dir', 'my_store.json')
|
246
|
+
storage_conf = {
|
247
|
+
'path' => storage_path,
|
248
|
+
'mode' => '0600',
|
249
|
+
'dir_mode' => '0777',
|
250
|
+
}
|
251
|
+
conf = config_element('ROOT', '', {}, [config_element('storage', '', storage_conf)])
|
252
|
+
@d.configure(conf)
|
253
|
+
@d.start
|
254
|
+
@p = @d.storage_create()
|
255
|
+
|
256
|
+
assert_equal storage_path, @p.path
|
257
|
+
assert @p.store.empty?
|
258
|
+
|
259
|
+
@p.put('key1', '1')
|
260
|
+
assert_equal '1', @p.get('key1')
|
261
|
+
|
262
|
+
@p.save # stores all data into file
|
263
|
+
|
264
|
+
assert File.exist?(storage_path)
|
265
|
+
assert_equal 0600, (File.stat(storage_path).mode % 01000)
|
266
|
+
assert_equal 0777, (File.stat(File.dirname(storage_path)).mode % 01000)
|
267
|
+
end
|
268
|
+
|
269
|
+
test 'pretty_print controls to write data in files as human-easy-to-read' do
|
270
|
+
storage_path = File.join(TMP_DIR, 'dir', 'my_store.json')
|
271
|
+
storage_conf = {
|
272
|
+
'path' => storage_path,
|
273
|
+
'pretty_print' => 'true',
|
274
|
+
}
|
275
|
+
conf = config_element('ROOT', '', {}, [config_element('storage', '', storage_conf)])
|
276
|
+
@d.configure(conf)
|
277
|
+
@d.start
|
278
|
+
@p = @d.storage_create()
|
279
|
+
|
280
|
+
assert_equal storage_path, @p.path
|
281
|
+
assert @p.store.empty?
|
282
|
+
|
283
|
+
@p.put('key1', '1')
|
284
|
+
assert_equal '1', @p.get('key1')
|
285
|
+
|
286
|
+
@p.save # stores all data into file
|
287
|
+
|
288
|
+
expected_pp_json = <<JSON.chomp
|
289
|
+
{
|
290
|
+
"key1": "1"
|
291
|
+
}
|
292
|
+
JSON
|
293
|
+
assert_equal expected_pp_json, File.read(storage_path)
|
294
|
+
end
|
7
295
|
end
|
8
296
|
end
|