fluentd 0.14.7-x86-mingw32 → 0.14.10-x86-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.

Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +2 -0
  4. data/CONTRIBUTING.md +6 -1
  5. data/ChangeLog +95 -0
  6. data/Rakefile +21 -0
  7. data/appveyor.yml +1 -0
  8. data/code-of-conduct.md +3 -0
  9. data/example/out_exec_filter.conf +42 -0
  10. data/fluentd.gemspec +1 -1
  11. data/lib/fluent/agent.rb +2 -2
  12. data/lib/fluent/command/binlog_reader.rb +1 -1
  13. data/lib/fluent/command/cat.rb +15 -4
  14. data/lib/fluent/compat/output.rb +14 -9
  15. data/lib/fluent/compat/parser.rb +141 -11
  16. data/lib/fluent/config/configure_proxy.rb +2 -11
  17. data/lib/fluent/config/section.rb +8 -1
  18. data/lib/fluent/configurable.rb +1 -3
  19. data/lib/fluent/env.rb +1 -1
  20. data/lib/fluent/log.rb +1 -1
  21. data/lib/fluent/plugin/base.rb +17 -0
  22. data/lib/fluent/plugin/filter_parser.rb +108 -0
  23. data/lib/fluent/plugin/filter_record_transformer.rb +14 -35
  24. data/lib/fluent/plugin/filter_stdout.rb +1 -1
  25. data/lib/fluent/plugin/formatter.rb +5 -0
  26. data/lib/fluent/plugin/formatter_msgpack.rb +4 -0
  27. data/lib/fluent/plugin/formatter_stdout.rb +3 -2
  28. data/lib/fluent/plugin/formatter_tsv.rb +34 -0
  29. data/lib/fluent/plugin/in_exec.rb +48 -93
  30. data/lib/fluent/plugin/in_forward.rb +66 -265
  31. data/lib/fluent/plugin/in_http.rb +68 -65
  32. data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
  33. data/lib/fluent/plugin/in_syslog.rb +42 -58
  34. data/lib/fluent/plugin/in_tail.rb +29 -14
  35. data/lib/fluent/plugin/in_tcp.rb +54 -14
  36. data/lib/fluent/plugin/in_udp.rb +49 -13
  37. data/lib/fluent/plugin/multi_output.rb +1 -3
  38. data/lib/fluent/plugin/out_exec.rb +58 -71
  39. data/lib/fluent/plugin/out_exec_filter.rb +199 -279
  40. data/lib/fluent/plugin/out_file.rb +172 -81
  41. data/lib/fluent/plugin/out_forward.rb +229 -206
  42. data/lib/fluent/plugin/out_stdout.rb +6 -21
  43. data/lib/fluent/plugin/output.rb +90 -59
  44. data/lib/fluent/plugin/parser.rb +121 -61
  45. data/lib/fluent/plugin/parser_csv.rb +9 -3
  46. data/lib/fluent/plugin/parser_json.rb +37 -35
  47. data/lib/fluent/plugin/parser_ltsv.rb +11 -19
  48. data/lib/fluent/plugin/parser_msgpack.rb +50 -0
  49. data/lib/fluent/plugin/parser_regexp.rb +15 -42
  50. data/lib/fluent/plugin/parser_tsv.rb +8 -3
  51. data/lib/fluent/plugin_helper.rb +10 -1
  52. data/lib/fluent/plugin_helper/child_process.rb +139 -73
  53. data/lib/fluent/plugin_helper/compat_parameters.rb +93 -4
  54. data/lib/fluent/plugin_helper/event_emitter.rb +14 -1
  55. data/lib/fluent/plugin_helper/event_loop.rb +24 -6
  56. data/lib/fluent/plugin_helper/extract.rb +16 -4
  57. data/lib/fluent/plugin_helper/formatter.rb +9 -11
  58. data/lib/fluent/plugin_helper/inject.rb +16 -1
  59. data/lib/fluent/plugin_helper/parser.rb +3 -3
  60. data/lib/fluent/plugin_helper/server.rb +494 -0
  61. data/lib/fluent/plugin_helper/socket.rb +101 -0
  62. data/lib/fluent/plugin_helper/socket_option.rb +84 -0
  63. data/lib/fluent/plugin_helper/timer.rb +1 -0
  64. data/lib/fluent/root_agent.rb +1 -1
  65. data/lib/fluent/test/driver/base.rb +95 -49
  66. data/lib/fluent/test/driver/base_owner.rb +18 -8
  67. data/lib/fluent/test/driver/multi_output.rb +2 -1
  68. data/lib/fluent/test/driver/output.rb +29 -6
  69. data/lib/fluent/test/helpers.rb +3 -1
  70. data/lib/fluent/test/log.rb +4 -0
  71. data/lib/fluent/test/startup_shutdown.rb +13 -0
  72. data/lib/fluent/time.rb +14 -8
  73. data/lib/fluent/version.rb +1 -1
  74. data/lib/fluent/winsvc.rb +1 -1
  75. data/test/command/test_binlog_reader.rb +5 -1
  76. data/test/compat/test_parser.rb +10 -0
  77. data/test/config/test_configurable.rb +193 -0
  78. data/test/config/test_configure_proxy.rb +0 -43
  79. data/test/helper.rb +36 -1
  80. data/test/plugin/test_base.rb +16 -0
  81. data/test/plugin/test_filter_parser.rb +665 -0
  82. data/test/plugin/test_filter_record_transformer.rb +36 -100
  83. data/test/plugin/test_filter_stdout.rb +18 -27
  84. data/test/plugin/test_in_dummy.rb +1 -1
  85. data/test/plugin/test_in_exec.rb +206 -94
  86. data/test/plugin/test_in_forward.rb +268 -347
  87. data/test/plugin/test_in_http.rb +310 -186
  88. data/test/plugin/test_in_monitor_agent.rb +65 -35
  89. data/test/plugin/test_in_syslog.rb +39 -3
  90. data/test/plugin/test_in_tcp.rb +78 -62
  91. data/test/plugin/test_in_udp.rb +101 -80
  92. data/test/plugin/test_out_exec.rb +223 -68
  93. data/test/plugin/test_out_exec_filter.rb +520 -169
  94. data/test/plugin/test_out_file.rb +637 -177
  95. data/test/plugin/test_out_forward.rb +242 -234
  96. data/test/plugin/test_out_null.rb +1 -1
  97. data/test/plugin/test_out_secondary_file.rb +4 -2
  98. data/test/plugin/test_out_stdout.rb +14 -35
  99. data/test/plugin/test_output_as_buffered.rb +60 -2
  100. data/test/plugin/test_parser.rb +359 -0
  101. data/test/plugin/test_parser_csv.rb +1 -2
  102. data/test/plugin/test_parser_json.rb +3 -4
  103. data/test/plugin/test_parser_labeled_tsv.rb +1 -2
  104. data/test/plugin/test_parser_none.rb +1 -2
  105. data/test/plugin/test_parser_regexp.rb +8 -4
  106. data/test/plugin/test_parser_tsv.rb +4 -3
  107. data/test/plugin_helper/test_child_process.rb +184 -0
  108. data/test/plugin_helper/test_compat_parameters.rb +88 -1
  109. data/test/plugin_helper/test_extract.rb +0 -1
  110. data/test/plugin_helper/test_formatter.rb +5 -2
  111. data/test/plugin_helper/test_inject.rb +21 -0
  112. data/test/plugin_helper/test_parser.rb +6 -5
  113. data/test/plugin_helper/test_server.rb +905 -0
  114. data/test/test_event_time.rb +3 -1
  115. data/test/test_output.rb +53 -2
  116. data/test/test_plugin_classes.rb +20 -0
  117. data/test/test_root_agent.rb +139 -0
  118. data/test/test_test_drivers.rb +135 -0
  119. metadata +28 -8
  120. data/test/plugin/test_parser_base.rb +0 -32
@@ -1,8 +1,10 @@
1
1
  require_relative '../helper'
2
- require 'fluent/test'
2
+ require 'fluent/test/driver/output'
3
3
  require 'fluent/plugin/out_file'
4
4
  require 'fileutils'
5
5
  require 'time'
6
+ require 'timecop'
7
+ require 'zlib'
6
8
 
7
9
  class FileOutputTest < Test::Unit::TestCase
8
10
  def setup
@@ -21,92 +23,320 @@ class FileOutputTest < Test::Unit::TestCase
21
23
  ]
22
24
 
23
25
  def create_driver(conf = CONFIG)
24
- Fluent::Test::TimeSlicedOutputTestDriver.new(Fluent::FileOutput).configure(conf)
26
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::FileOutput).configure(conf)
25
27
  end
26
28
 
27
- def test_configure
28
- d = create_driver %[
29
- path test_path
30
- compress gz
31
- ]
32
- assert_equal 'test_path', d.instance.path
33
- assert_equal :gz, d.instance.compress
34
- end
29
+ sub_test_case 'configuration' do
30
+ test 'basic configuration' do
31
+ d = create_driver %[
32
+ path test_path
33
+ compress gz
34
+ ]
35
+ assert_equal 'test_path', d.instance.path
36
+ assert_equal :gz, d.instance.compress
37
+ assert_equal :gzip, d.instance.instance_eval{ @compress_method }
38
+ end
39
+
40
+ test 'path should be writable' do
41
+ assert_nothing_raised do
42
+ create_driver %[path #{TMP_DIR}/test_path]
43
+ end
35
44
 
36
- def test_path_writable
37
- assert_nothing_raised do
38
- create_driver %[path #{TMP_DIR}/test_path]
45
+ assert_nothing_raised do
46
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
47
+ File.chmod(0777, "#{TMP_DIR}/test_dir")
48
+ create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
49
+ end
50
+
51
+ assert_raise(Fluent::ConfigError) do
52
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
53
+ File.chmod(0555, "#{TMP_DIR}/test_dir")
54
+ create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
55
+ end
39
56
  end
40
57
 
41
- assert_nothing_raised do
42
- FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
43
- File.chmod(0777, "#{TMP_DIR}/test_dir")
44
- create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
58
+ test 'default timezone is localtime' do
59
+ d = create_driver(%[path #{TMP_DIR}/out_file_test])
60
+ time = event_time("2011-01-02 13:14:15 UTC")
61
+
62
+ with_timezone(Fluent.windows? ? 'NST-8' : 'Asia/Taipei') do
63
+ d.run(default_tag: 'test') do
64
+ d.feed(time, {"a"=>1})
65
+ end
66
+ end
67
+ assert_equal 1, d.formatted.size
68
+ assert_equal %[2011-01-02T21:14:15+08:00\ttest\t{"a":1}\n], d.formatted[0]
45
69
  end
46
70
 
47
- assert_raise(Fluent::ConfigError) do
48
- FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
49
- File.chmod(0555, "#{TMP_DIR}/test_dir")
50
- create_driver %[path #{TMP_DIR}/test_dir/foo/bar/baz]
71
+ test 'no configuration error raised for basic configuration using "*" (v0.12 style)' do
72
+ conf = config_element('match', '**', {
73
+ 'path' => "#{TMP_DIR}/test_out.*.log",
74
+ 'time_slice_format' => '%Y%m%d',
75
+ })
76
+ assert_nothing_raised do
77
+ create_driver(conf)
78
+ end
79
+ end
80
+
81
+ test 'configuration error raised if specified directory via template is not writable' do
82
+ Timecop.freeze(Time.parse("2016-10-04 21:33:27 UTC")) do
83
+ conf = config_element('match', '**', {
84
+ 'path' => "#{TMP_DIR}/prohibited/${tag}/file.%Y%m%d.log",
85
+ }, [ config_element('buffer', 'time,tag', {'timekey' => 86400, 'timekey_zone' => '+0000'}) ])
86
+ FileUtils.mkdir_p("#{TMP_DIR}/prohibited")
87
+ File.chmod(0555, "#{TMP_DIR}/prohibited")
88
+ assert_raise Fluent::ConfigError.new("out_file: `#{TMP_DIR}/prohibited/a/file.20161004.log_**.log` is not writable") do
89
+ create_driver(conf)
90
+ end
91
+ end
51
92
  end
52
- end
53
93
 
54
- def test_default_localtime
55
- d = create_driver(%[path #{TMP_DIR}/out_file_test])
56
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
94
+ test 'configuration using inject/format/buffer sections fully' do
95
+ conf = config_element('match', '**', {
96
+ 'path' => "#{TMP_DIR}/${tag}/${type}/conf_test.%Y%m%d.%H%M.log",
97
+ 'add_path_suffix' => 'false',
98
+ 'append' => "true",
99
+ 'symlink_path' => "#{TMP_DIR}/conf_test.current.log",
100
+ 'compress' => 'gzip',
101
+ 'recompress' => 'true',
102
+ }, [
103
+ config_element('inject', '', {
104
+ 'hostname_key' => 'hostname',
105
+ 'hostname' => 'testing.local',
106
+ 'tag_key' => 'tag',
107
+ 'time_key' => 'time',
108
+ 'time_type' => 'string',
109
+ 'time_format' => '%Y/%m/%d %H:%M:%S %z',
110
+ 'timezone' => '+0900',
111
+ }),
112
+ config_element('format', '', {
113
+ '@type' => 'out_file',
114
+ 'include_tag' => 'true',
115
+ 'include_time' => 'true',
116
+ 'delimiter' => 'COMMA',
117
+ 'time_type' => 'string',
118
+ 'time_format' => '%Y-%m-%d %H:%M:%S %z',
119
+ 'utc' => 'true',
120
+ }),
121
+ config_element('buffer', 'time,tag,type', {
122
+ '@type' => 'file',
123
+ 'timekey' => '15m',
124
+ 'timekey_wait' => '5s',
125
+ 'timekey_zone' => '+0000',
126
+ 'path' => "#{TMP_DIR}/buf_conf_test",
127
+ 'chunk_limit_size' => '50m',
128
+ 'total_limit_size' => '1g',
129
+ 'compress' => 'gzip',
130
+ }),
131
+ ])
132
+ assert_nothing_raised do
133
+ create_driver(conf)
134
+ end
135
+ end
57
136
 
58
- with_timezone(Fluent.windows? ? 'NST-8' : 'Asia/Taipei') do
59
- d.emit({"a"=>1}, time)
60
- d.expect_format %[2011-01-02T21:14:15+08:00\ttest\t{"a":1}\n]
61
- d.run
137
+ test 'configured as secondary with primary using chunk_key_tag and not using chunk_key_time' do
138
+ require 'fluent/plugin/out_null'
139
+ port = unused_port
140
+ conf = config_element('match', '**', {
141
+ }, [
142
+ config_element('buffer', 'tag', {
143
+ }),
144
+ config_element('secondary', '', {
145
+ '@type' => 'file',
146
+ 'path' => "#{TMP_DIR}/testing_to_dump_by_out_file",
147
+ }),
148
+ ])
149
+ assert_nothing_raised do
150
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::NullOutput).configure(conf)
151
+ end
62
152
  end
63
153
  end
64
154
 
65
- def test_format
66
- d = create_driver
155
+ sub_test_case 'fully configured output' do
156
+ setup do
157
+ Timecop.freeze(Time.parse("2016-10-03 23:58:00 UTC"))
158
+ conf = config_element('match', '**', {
159
+ 'path' => "#{TMP_DIR}/${tag}/${type}/full.%Y%m%d.%H%M.log",
160
+ 'add_path_suffix' => 'false',
161
+ 'append' => "true",
162
+ 'symlink_path' => "#{TMP_DIR}/full.current.log",
163
+ 'compress' => 'gzip',
164
+ 'recompress' => 'true',
165
+ }, [
166
+ config_element('inject', '', {
167
+ 'hostname_key' => 'hostname',
168
+ 'hostname' => 'testing.local',
169
+ 'tag_key' => 'tag',
170
+ 'time_key' => 'time',
171
+ 'time_type' => 'string',
172
+ 'time_format' => '%Y/%m/%d %H:%M:%S %z',
173
+ 'timezone' => '+0900',
174
+ }),
175
+ config_element('format', '', {
176
+ '@type' => 'out_file',
177
+ 'include_tag' => 'true',
178
+ 'include_time' => 'true',
179
+ 'delimiter' => 'COMMA',
180
+ 'time_type' => 'string',
181
+ 'time_format' => '%Y-%m-%d %H:%M:%S %z',
182
+ 'utc' => 'true',
183
+ }),
184
+ config_element('buffer', 'time,tag,type', {
185
+ '@type' => 'file',
186
+ 'timekey' => '15m',
187
+ 'timekey_wait' => '5s',
188
+ 'timekey_zone' => '+0000',
189
+ 'path' => "#{TMP_DIR}/buf_full",
190
+ 'chunk_limit_size' => '50m',
191
+ 'total_limit_size' => '1g',
192
+ 'compress' => 'gzip',
193
+ }),
194
+ ])
195
+ @d = create_driver(conf)
196
+ end
197
+
198
+ teardown do
199
+ FileUtils.rm_rf("#{TMP_DIR}/buf_full")
200
+ FileUtils.rm_rf("#{TMP_DIR}/my.data")
201
+ FileUtils.rm_rf("#{TMP_DIR}/your.data")
202
+ FileUtils.rm_rf("#{TMP_DIR}/full.current.log")
203
+ Timecop.return
204
+ end
67
205
 
68
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
69
- d.emit({"a"=>1}, time)
70
- d.emit({"a"=>2}, time)
206
+ test 'can format/write data correctly' do
207
+ d = @d
71
208
 
72
- d.expect_format %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n]
73
- d.expect_format %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n]
209
+ assert_equal 50*1024*1024, d.instance.buffer.chunk_limit_size
210
+ assert_equal 1*1024*1024*1024, d.instance.buffer.total_limit_size
74
211
 
75
- d.run
76
- end
212
+ assert !(File.symlink?("#{TMP_DIR}/full.current.log"))
77
213
 
78
- def test_timezone_1
79
- d = create_driver %[
80
- path #{TMP_DIR}/out_file_test
81
- timezone Asia/Taipei
82
- ]
214
+ t1 = event_time("2016-10-03 23:58:09 UTC")
215
+ t2 = event_time("2016-10-03 23:59:33 UTC")
216
+ t3 = event_time("2016-10-03 23:59:57 UTC")
217
+ t4 = event_time("2016-10-04 00:00:17 UTC")
218
+ t5 = event_time("2016-10-04 00:01:59 UTC")
83
219
 
84
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
220
+ Timecop.freeze(Time.parse("2016-10-03 23:58:30 UTC"))
85
221
 
86
- d.emit({"a"=>1}, time)
87
- d.expect_format %[2011-01-02T21:14:15+08:00\ttest\t{"a":1}\n]
88
- d.run
89
- end
222
+ d.run(start: true, flush: false, shutdown: false) do
223
+ d.feed('my.data', t1, {"type" => "a", "message" => "data raw content"})
224
+ d.feed('my.data', t2, {"type" => "a", "message" => "data raw content"})
225
+ d.feed('your.data', t3, {"type" => "a", "message" => "data raw content"})
226
+ end
90
227
 
91
- def test_timezone_2
92
- d = create_driver %[
93
- path #{TMP_DIR}/out_file_test
94
- timezone -03:30
95
- ]
228
+ assert_equal 3, d.formatted.size
229
+
230
+ assert Dir.exist?("#{TMP_DIR}/buf_full")
231
+ assert !(Dir.exist?("#{TMP_DIR}/my.data/a"))
232
+ assert !(Dir.exist?("#{TMP_DIR}/your.data/a"))
233
+ buffer_files = Dir.entries("#{TMP_DIR}/buf_full").reject{|e| e =~ /^\.+$/ }
234
+ assert_equal 2, buffer_files.select{|n| n.end_with?('.meta') }.size
235
+ assert_equal 2, buffer_files.select{|n| !n.end_with?('.meta') }.size
96
236
 
97
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
237
+ m1 = d.instance.metadata('my.data', t1, {"type" => "a"})
238
+ m2 = d.instance.metadata('your.data', t3, {"type" => "a"})
98
239
 
99
- d.emit({"a"=>1}, time)
100
- d.expect_format %[2011-01-02T09:44:15-03:30\ttest\t{"a":1}\n]
101
- d.run
240
+ assert_equal 2, d.instance.buffer.stage.size
241
+ b1_path = d.instance.buffer.stage[m1].path
242
+ b1_size = File.lstat(b1_path).size
243
+
244
+ unless Fluent.windows?
245
+ assert File.symlink?("#{TMP_DIR}/full.current.log")
246
+ assert_equal d.instance.buffer.stage[m2].path, File.readlink("#{TMP_DIR}/full.current.log")
247
+ end
248
+
249
+ Timecop.freeze(Time.parse("2016-10-04 00:00:06 UTC"))
250
+
251
+ d.run(start: false, flush: true, shutdown: true) do
252
+ d.feed('my.data', t4, {"type" => "a", "message" => "data raw content"})
253
+ d.feed('your.data', t5, {"type" => "a", "message" => "data raw content"})
254
+ end
255
+
256
+ assert Dir.exist?("#{TMP_DIR}/buf_full")
257
+ assert Dir.exist?("#{TMP_DIR}/my.data/a")
258
+ assert Dir.exist?("#{TMP_DIR}/your.data/a")
259
+
260
+ buffer_files = Dir.entries("#{TMP_DIR}/buf_full").reject{|e| e =~ /^\.+$/ }
261
+ assert_equal 0, buffer_files.size
262
+
263
+ assert File.exist?("#{TMP_DIR}/my.data/a/full.20161003.2345.log.gz")
264
+ assert File.exist?("#{TMP_DIR}/my.data/a/full.20161004.0000.log.gz")
265
+ assert File.exist?("#{TMP_DIR}/your.data/a/full.20161003.2345.log.gz")
266
+ assert File.exist?("#{TMP_DIR}/your.data/a/full.20161004.0000.log.gz")
267
+
268
+ assert{ File.lstat("#{TMP_DIR}/my.data/a/full.20161003.2345.log.gz").size < b1_size } # recompress
269
+
270
+ assert_equal 5, d.formatted.size
271
+
272
+ r1 = %!2016-10-03 23:58:09 +0000,my.data,{"type":"a","message":"data raw content","hostname":"testing.local","tag":"my.data","time":"2016/10/04 08:58:09 +0900"}\n!
273
+ r2 = %!2016-10-03 23:59:33 +0000,my.data,{"type":"a","message":"data raw content","hostname":"testing.local","tag":"my.data","time":"2016/10/04 08:59:33 +0900"}\n!
274
+ r3 = %!2016-10-03 23:59:57 +0000,your.data,{"type":"a","message":"data raw content","hostname":"testing.local","tag":"your.data","time":"2016/10/04 08:59:57 +0900"}\n!
275
+ r4 = %!2016-10-04 00:00:17 +0000,my.data,{"type":"a","message":"data raw content","hostname":"testing.local","tag":"my.data","time":"2016/10/04 09:00:17 +0900"}\n!
276
+ r5 = %!2016-10-04 00:01:59 +0000,your.data,{"type":"a","message":"data raw content","hostname":"testing.local","tag":"your.data","time":"2016/10/04 09:01:59 +0900"}\n!
277
+ assert_equal r1, d.formatted[0]
278
+ assert_equal r2, d.formatted[1]
279
+ assert_equal r3, d.formatted[2]
280
+ assert_equal r4, d.formatted[3]
281
+ assert_equal r5, d.formatted[4]
282
+
283
+ read_gunzip = ->(path){ File.open(path){|fio| Zlib::GzipReader.open(fio){|io| io.read } } }
284
+ assert_equal r1 + r2, read_gunzip.call("#{TMP_DIR}/my.data/a/full.20161003.2345.log.gz")
285
+ assert_equal r3, read_gunzip.call("#{TMP_DIR}/your.data/a/full.20161003.2345.log.gz")
286
+ assert_equal r4, read_gunzip.call("#{TMP_DIR}/my.data/a/full.20161004.0000.log.gz")
287
+ assert_equal r5, read_gunzip.call("#{TMP_DIR}/your.data/a/full.20161004.0000.log.gz")
288
+ end
102
289
  end
103
290
 
104
- def test_timezone_invalid
105
- assert_raise(Fluent::ConfigError) do
106
- create_driver %[
291
+ sub_test_case 'format' do
292
+ test 'timezone UTC specified' do
293
+ d = create_driver
294
+
295
+ time = event_time("2011-01-02 13:14:15 UTC")
296
+ d.run(default_tag: 'test') do
297
+ d.feed(time, {"a"=>1})
298
+ d.feed(time, {"a"=>2})
299
+ end
300
+ assert_equal 2, d.formatted.size
301
+ assert_equal %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n], d.formatted[0]
302
+ assert_equal %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n], d.formatted[1]
303
+ end
304
+
305
+ test 'time formatted with specified timezone, using area name' do
306
+ d = create_driver %[
107
307
  path #{TMP_DIR}/out_file_test
108
- timezone Invalid/Invalid
308
+ timezone Asia/Taipei
109
309
  ]
310
+
311
+ time = event_time("2011-01-02 13:14:15 UTC")
312
+ d.run(default_tag: 'test') do
313
+ d.feed(time, {"a"=>1})
314
+ end
315
+ assert_equal 1, d.formatted.size
316
+ assert_equal %[2011-01-02T21:14:15+08:00\ttest\t{"a":1}\n], d.formatted[0]
317
+ end
318
+
319
+ test 'time formatted with specified timezone, using offset' do
320
+ d = create_driver %[
321
+ path #{TMP_DIR}/out_file_test
322
+ timezone -03:30
323
+ ]
324
+
325
+ time = event_time("2011-01-02 13:14:15 UTC")
326
+ d.run(default_tag: 'test') do
327
+ d.feed(time, {"a"=>1})
328
+ end
329
+ assert_equal 1, d.formatted.size
330
+ assert_equal %[2011-01-02T09:44:15-03:30\ttest\t{"a":1}\n], d.formatted[0]
331
+ end
332
+
333
+ test 'configuration error raised for invalid timezone' do
334
+ assert_raise(Fluent::ConfigError) do
335
+ create_driver %[
336
+ path #{TMP_DIR}/out_file_test
337
+ timezone Invalid/Invalid
338
+ ]
339
+ end
110
340
  end
111
341
  end
112
342
 
@@ -128,22 +358,24 @@ class FileOutputTest < Test::Unit::TestCase
128
358
  assert_equal expect, result
129
359
  end
130
360
 
131
- def test_write
132
- d = create_driver
361
+ sub_test_case 'write' do
362
+ test 'basic case' do
363
+ d = create_driver
133
364
 
134
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
135
- d.emit({"a"=>1}, time)
136
- d.emit({"a"=>2}, time)
365
+ assert_false File.exist?("#{TMP_DIR}/out_file_test.20110102_0.log.gz")
137
366
 
138
- # FileOutput#write returns path
139
- paths = d.run
140
- expect_paths = ["#{TMP_DIR}/out_file_test.20110102_0.log.gz"]
141
- assert_equal expect_paths, paths
367
+ time = event_time("2011-01-02 13:14:15 UTC")
368
+ d.run(default_tag: 'test') do
369
+ d.feed(time, {"a"=>1})
370
+ d.feed(time, {"a"=>2})
371
+ end
142
372
 
143
- check_gzipped_result(paths[0], %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n])
373
+ assert File.exist?("#{TMP_DIR}/out_file_test.20110102_0.log.gz")
374
+ check_gzipped_result("#{TMP_DIR}/out_file_test.20110102_0.log.gz", %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n])
375
+ end
144
376
  end
145
377
 
146
- class TestWithSystem < self
378
+ sub_test_case 'file/directory permissions' do
147
379
  TMP_DIR_WITH_SYSTEM = File.expand_path(File.dirname(__FILE__) + "/../tmp/out_file_system#{ENV['TEST_ENV_NUMBER']}")
148
380
  # 0750 interprets as "488". "488".to_i(8) # => 4. So, it makes wrong permission. Umm....
149
381
  OVERRIDE_DIR_PERMISSION = 750
@@ -158,7 +390,7 @@ class FileOutputTest < Test::Unit::TestCase
158
390
  </system>
159
391
  ]
160
392
 
161
- def setup
393
+ setup do
162
394
  omit "NTFS doesn't support UNIX like permissions" if Fluent.windows?
163
395
  FileUtils.rm_rf(TMP_DIR_WITH_SYSTEM)
164
396
  end
@@ -168,97 +400,104 @@ class FileOutputTest < Test::Unit::TestCase
168
400
  Fluent::Config.parse(text, '(test)', basepath, true).elements.find { |e| e.name == 'system' }
169
401
  end
170
402
 
171
- def test_write_with_system
403
+ test 'write to file with permission specifications' do
172
404
  system_conf = parse_system(CONFIG_WITH_SYSTEM)
173
405
  sc = Fluent::SystemConfig.new(system_conf)
174
406
  Fluent::Engine.init(sc)
175
407
  d = create_driver CONFIG_WITH_SYSTEM
176
408
 
177
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
178
- d.emit({"a"=>1}, time)
179
- d.emit({"a"=>2}, time)
409
+ assert_false File.exist?("#{TMP_DIR_WITH_SYSTEM}/out_file_test.20110102_0.log.gz")
180
410
 
181
- # FileOutput#write returns path
182
- paths = d.run
183
- expect_paths = ["#{TMP_DIR_WITH_SYSTEM}/out_file_test.20110102_0.log.gz"]
184
- assert_equal expect_paths, paths
411
+ time = event_time("2011-01-02 13:14:15 UTC")
412
+ d.run(default_tag: 'test') do
413
+ d.feed(time, {"a"=>1})
414
+ d.feed(time, {"a"=>2})
415
+ end
185
416
 
186
- check_gzipped_result(paths[0], %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n])
417
+ assert File.exist?("#{TMP_DIR_WITH_SYSTEM}/out_file_test.20110102_0.log.gz")
418
+
419
+ check_gzipped_result("#{TMP_DIR_WITH_SYSTEM}/out_file_test.20110102_0.log.gz", %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n])
187
420
  dir_mode = "%o" % File::stat(TMP_DIR_WITH_SYSTEM).mode
188
421
  assert_equal(OVERRIDE_DIR_PERMISSION, dir_mode[-3, 3].to_i)
189
- file_mode = "%o" % File::stat(paths[0]).mode
422
+ file_mode = "%o" % File::stat("#{TMP_DIR_WITH_SYSTEM}/out_file_test.20110102_0.log.gz").mode
190
423
  assert_equal(OVERRIDE_FILE_PERMISSION, file_mode[-3, 3].to_i)
191
424
  end
192
425
  end
193
426
 
194
- def test_write_with_format_json
195
- d = create_driver [CONFIG, 'format json', 'include_time_key true', 'time_as_epoch'].join("\n")
427
+ sub_test_case 'format specified' do
428
+ test 'json' do
429
+ d = create_driver [CONFIG, 'format json', 'include_time_key true', 'time_as_epoch'].join("\n")
196
430
 
197
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
198
- d.emit({"a"=>1}, time)
199
- d.emit({"a"=>2}, time)
431
+ time = event_time("2011-01-02 13:14:15 UTC")
432
+ d.run(default_tag: 'test') do
433
+ d.feed(time, {"a"=>1})
434
+ d.feed(time, {"a"=>2})
435
+ end
200
436
 
201
- # FileOutput#write returns path
202
- paths = d.run
203
- check_gzipped_result(paths[0], %[#{Yajl.dump({"a" => 1, 'time' => time})}\n] + %[#{Yajl.dump({"a" => 2, 'time' => time})}\n])
204
- end
437
+ path = d.instance.last_written_path
438
+ check_gzipped_result(path, %[#{Yajl.dump({"a" => 1, 'time' => time.to_i})}\n] + %[#{Yajl.dump({"a" => 2, 'time' => time.to_i})}\n])
439
+ end
205
440
 
206
- def test_write_with_format_ltsv
207
- d = create_driver [CONFIG, 'format ltsv', 'include_time_key true'].join("\n")
441
+ test 'ltsv' do
442
+ d = create_driver [CONFIG, 'format ltsv', 'include_time_key true'].join("\n")
208
443
 
209
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
210
- d.emit({"a"=>1}, time)
211
- d.emit({"a"=>2}, time)
444
+ time = event_time("2011-01-02 13:14:15 UTC")
445
+ d.run(default_tag: 'test') do
446
+ d.feed(time, {"a"=>1})
447
+ d.feed(time, {"a"=>2})
448
+ end
212
449
 
213
- # FileOutput#write returns path
214
- paths = d.run
215
- check_gzipped_result(paths[0], %[a:1\ttime:2011-01-02T13:14:15Z\n] + %[a:2\ttime:2011-01-02T13:14:15Z\n])
216
- end
450
+ path = d.instance.last_written_path
451
+ check_gzipped_result(path, %[a:1\ttime:2011-01-02T13:14:15Z\n] + %[a:2\ttime:2011-01-02T13:14:15Z\n])
452
+ end
217
453
 
218
- def test_write_with_format_single_value
219
- d = create_driver [CONFIG, 'format single_value', 'message_key a'].join("\n")
454
+ test 'single_value' do
455
+ d = create_driver [CONFIG, 'format single_value', 'message_key a'].join("\n")
220
456
 
221
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
222
- d.emit({"a"=>1}, time)
223
- d.emit({"a"=>2}, time)
457
+ time = event_time("2011-01-02 13:14:15 UTC")
458
+ d.run(default_tag: 'test') do
459
+ d.feed(time, {"a"=>1})
460
+ d.feed(time, {"a"=>2})
461
+ end
224
462
 
225
- # FileOutput#write returns path
226
- paths = d.run
227
- check_gzipped_result(paths[0], %[1\n] + %[2\n])
463
+ path = d.instance.last_written_path
464
+ check_gzipped_result(path, %[1\n] + %[2\n])
465
+ end
228
466
  end
229
467
 
230
- def test_write_path_increment
231
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
468
+ test 'path with index number' do
469
+ time = event_time("2011-01-02 13:14:15 UTC")
232
470
  formatted_lines = %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n]
233
471
 
234
472
  write_once = ->(){
235
473
  d = create_driver
236
- d.emit({"a"=>1}, time)
237
- d.emit({"a"=>2}, time)
238
- d.run
474
+ d.run(default_tag: 'test'){
475
+ d.feed(time, {"a"=>1})
476
+ d.feed(time, {"a"=>2})
477
+ }
478
+ d.instance.last_written_path
239
479
  }
240
480
 
241
481
  assert !File.exist?("#{TMP_DIR}/out_file_test.20110102_0.log.gz")
242
482
 
243
- # FileOutput#write returns path
244
- paths = write_once.call
245
- assert_equal ["#{TMP_DIR}/out_file_test.20110102_0.log.gz"], paths
246
- check_gzipped_result(paths[0], formatted_lines)
483
+ path = write_once.call
484
+ assert_equal "#{TMP_DIR}/out_file_test.20110102_0.log.gz", path
485
+ check_gzipped_result(path, formatted_lines)
247
486
  assert_equal 1, Dir.glob("#{TMP_DIR}/out_file_test.*").size
248
487
 
249
- paths = write_once.call
250
- assert_equal ["#{TMP_DIR}/out_file_test.20110102_1.log.gz"], paths
251
- check_gzipped_result(paths[0], formatted_lines)
488
+ path = write_once.call
489
+ assert_equal "#{TMP_DIR}/out_file_test.20110102_1.log.gz", path
490
+ check_gzipped_result(path, formatted_lines)
252
491
  assert_equal 2, Dir.glob("#{TMP_DIR}/out_file_test.*").size
253
492
 
254
- paths = write_once.call
255
- assert_equal ["#{TMP_DIR}/out_file_test.20110102_2.log.gz"], paths
256
- check_gzipped_result(paths[0], formatted_lines)
493
+ path = write_once.call
494
+ assert_equal "#{TMP_DIR}/out_file_test.20110102_2.log.gz", path
495
+ check_gzipped_result(path, formatted_lines)
257
496
  assert_equal 3, Dir.glob("#{TMP_DIR}/out_file_test.*").size
258
497
  end
259
498
 
260
- def test_write_with_append
261
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
499
+ test 'append' do
500
+ time = event_time("2011-01-02 13:14:15 UTC")
262
501
  formatted_lines = %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] + %[2011-01-02T13:14:15Z\ttest\t{"a":2}\n]
263
502
 
264
503
  write_once = ->(){
@@ -268,53 +507,52 @@ class FileOutputTest < Test::Unit::TestCase
268
507
  utc
269
508
  append true
270
509
  ]
271
- d.emit({"a"=>1}, time)
272
- d.emit({"a"=>2}, time)
273
- d.run
510
+ d.run(default_tag: 'test'){
511
+ d.feed(time, {"a"=>1})
512
+ d.feed(time, {"a"=>2})
513
+ }
514
+ d.instance.last_written_path
274
515
  }
275
516
 
276
- # FileOutput#write returns path
277
- paths = write_once.call
278
- assert_equal ["#{TMP_DIR}/out_file_test.20110102.log.gz"], paths
279
- check_gzipped_result(paths[0], formatted_lines)
280
- paths = write_once.call
281
- assert_equal ["#{TMP_DIR}/out_file_test.20110102.log.gz"], paths
282
- check_gzipped_result(paths[0], formatted_lines * 2)
283
- paths = write_once.call
284
- assert_equal ["#{TMP_DIR}/out_file_test.20110102.log.gz"], paths
285
- check_gzipped_result(paths[0], formatted_lines * 3)
517
+ path = write_once.call
518
+ assert_equal "#{TMP_DIR}/out_file_test.20110102.log.gz", path
519
+ check_gzipped_result(path, formatted_lines)
520
+
521
+ path = write_once.call
522
+ assert_equal "#{TMP_DIR}/out_file_test.20110102.log.gz", path
523
+ check_gzipped_result(path, formatted_lines * 2)
524
+
525
+ path = write_once.call
526
+ assert_equal "#{TMP_DIR}/out_file_test.20110102.log.gz", path
527
+ check_gzipped_result(path, formatted_lines * 3)
286
528
  end
287
529
 
288
- def test_write_with_symlink
530
+ test 'symlink' do
289
531
  omit "Windows doesn't support symlink" if Fluent.windows?
290
532
  conf = CONFIG + %[
291
533
  symlink_path #{SYMLINK_PATH}
292
534
  ]
293
535
  symlink_path = "#{SYMLINK_PATH}"
294
536
 
295
- d = Fluent::Test::TestDriver.new(Fluent::FileOutput).configure(conf)
296
-
537
+ d = create_driver(conf)
297
538
  begin
298
- d.instance.start
299
- 10.times { sleep 0.05 }
300
-
301
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
302
- es = Fluent::OneEventStream.new(time, {"a"=>1})
303
- d.instance.emit_events('tag', es)
539
+ d.run(default_tag: 'tag') do
540
+ es = Fluent::OneEventStream.new(event_time("2011-01-02 13:14:15 UTC"), {"a"=>1})
541
+ d.feed(es)
304
542
 
305
- assert File.exist?(symlink_path)
306
- assert File.symlink?(symlink_path)
543
+ assert File.symlink?(symlink_path)
544
+ assert File.exist?(symlink_path) # This checks dest of symlink exists or not.
307
545
 
308
- es = Fluent::OneEventStream.new(event_time("2011-01-03 14:15:16 UTC"), {"a"=>2})
309
- d.instance.emit_events('tag', es)
546
+ es = Fluent::OneEventStream.new(event_time("2011-01-03 14:15:16 UTC"), {"a"=>2})
547
+ d.feed(es)
310
548
 
311
- assert File.exist?(symlink_path)
312
- assert File.symlink?(symlink_path)
549
+ assert File.symlink?(symlink_path)
550
+ assert File.exist?(symlink_path)
313
551
 
314
- meta = d.instance.metadata('tag', event_time("2011-01-03 14:15:16 UTC"), {})
315
- assert_equal d.instance.buffer.instance_eval{ @stage[meta].path }, File.readlink(symlink_path)
552
+ meta = d.instance.metadata('tag', event_time("2011-01-03 14:15:16 UTC"), {})
553
+ assert_equal d.instance.buffer.instance_eval{ @stage[meta].path }, File.readlink(symlink_path)
554
+ end
316
555
  ensure
317
- d.instance.shutdown
318
556
  FileUtils.rm_rf(symlink_path)
319
557
  end
320
558
  end
@@ -326,11 +564,12 @@ class FileOutputTest < Test::Unit::TestCase
326
564
  time_slice_format %Y-%m-%d-%H
327
565
  utc true
328
566
  ])
329
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
330
- d.emit({"a"=>1}, time)
331
- # FileOutput#write returns path
332
- paths = d.run
333
- assert_equal ["#{TMP_DIR}/out_file_test.2011-01-02-13_0.log"], paths
567
+ time = event_time("2011-01-02 13:14:15 UTC")
568
+ d.run(default_tag: 'test') do
569
+ d.feed(time, {"a"=>1})
570
+ end
571
+ path = d.instance.last_written_path
572
+ assert_equal "#{TMP_DIR}/out_file_test.2011-01-02-13_0.log", path
334
573
  end
335
574
 
336
575
  test 'normal with append' do
@@ -340,22 +579,26 @@ class FileOutputTest < Test::Unit::TestCase
340
579
  utc true
341
580
  append true
342
581
  ])
343
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
344
- d.emit({"a"=>1}, time)
345
- paths = d.run
346
- assert_equal ["#{TMP_DIR}/out_file_test.2011-01-02-13.log"], paths
347
- end
582
+ time = event_time("2011-01-02 13:14:15 UTC")
583
+ d.run(default_tag: 'test') do
584
+ d.feed(time, {"a"=>1})
585
+ end
586
+ path = d.instance.last_written_path
587
+ assert_equal "#{TMP_DIR}/out_file_test.2011-01-02-13.log", path
588
+ end
348
589
 
349
- test '*' do
590
+ test '*' do
350
591
  d = create_driver(%[
351
592
  path #{TMP_DIR}/out_file_test.*.txt
352
593
  time_slice_format %Y-%m-%d-%H
353
594
  utc true
354
595
  ])
355
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
356
- d.emit({"a"=>1}, time)
357
- paths = d.run
358
- assert_equal ["#{TMP_DIR}/out_file_test.2011-01-02-13_0.txt"], paths
596
+ time = event_time("2011-01-02 13:14:15 UTC")
597
+ d.run(default_tag: 'test') do
598
+ d.feed(time, {"a"=>1})
599
+ end
600
+ path = d.instance.last_written_path
601
+ assert_equal "#{TMP_DIR}/out_file_test.2011-01-02-13_0.txt", path
359
602
  end
360
603
 
361
604
  test '* with append' do
@@ -365,11 +608,228 @@ class FileOutputTest < Test::Unit::TestCase
365
608
  utc true
366
609
  append true
367
610
  ])
368
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
369
- d.emit({"a"=>1}, time)
370
- paths = d.run
371
- assert_equal ["#{TMP_DIR}/out_file_test.2011-01-02-13.txt"], paths
611
+ time = event_time("2011-01-02 13:14:15 UTC")
612
+ d.run(default_tag: 'test') do
613
+ d.feed(time, {"a"=>1})
614
+ end
615
+ path = d.instance.last_written_path
616
+ assert_equal "#{TMP_DIR}/out_file_test.2011-01-02-13.txt", path
372
617
  end
373
618
  end
374
- end
375
619
 
620
+ sub_test_case '#timekey_to_timeformat' do
621
+ setup do
622
+ @d = create_driver
623
+ @i = @d.instance
624
+ end
625
+
626
+ test 'returns empty string for nil' do
627
+ assert_equal '', @i.timekey_to_timeformat(nil)
628
+ end
629
+
630
+ test 'returns timestamp string with seconds for timekey smaller than 60' do
631
+ assert_equal '%Y%m%d%H%M%S', @i.timekey_to_timeformat(1)
632
+ assert_equal '%Y%m%d%H%M%S', @i.timekey_to_timeformat(30)
633
+ assert_equal '%Y%m%d%H%M%S', @i.timekey_to_timeformat(59)
634
+ end
635
+
636
+ test 'returns timestamp string with minutes for timekey smaller than 3600' do
637
+ assert_equal '%Y%m%d%H%M', @i.timekey_to_timeformat(60)
638
+ assert_equal '%Y%m%d%H%M', @i.timekey_to_timeformat(180)
639
+ assert_equal '%Y%m%d%H%M', @i.timekey_to_timeformat(1800)
640
+ assert_equal '%Y%m%d%H%M', @i.timekey_to_timeformat(3599)
641
+ end
642
+
643
+ test 'returns timestamp string with hours for timekey smaller than 86400 (1 day)' do
644
+ assert_equal '%Y%m%d%H', @i.timekey_to_timeformat(3600)
645
+ assert_equal '%Y%m%d%H', @i.timekey_to_timeformat(7200)
646
+ assert_equal '%Y%m%d%H', @i.timekey_to_timeformat(86399)
647
+ end
648
+
649
+ test 'returns timestamp string with days for timekey equal or greater than 86400' do
650
+ assert_equal '%Y%m%d', @i.timekey_to_timeformat(86400)
651
+ assert_equal '%Y%m%d', @i.timekey_to_timeformat(1000000)
652
+ assert_equal '%Y%m%d', @i.timekey_to_timeformat(1000000000)
653
+ end
654
+ end
655
+
656
+ sub_test_case '#compression_suffix' do
657
+ setup do
658
+ @i = create_driver.instance
659
+ end
660
+
661
+ test 'returns empty string for nil (no compression method specified)' do
662
+ assert_equal '', @i.compression_suffix(nil)
663
+ end
664
+
665
+ test 'returns .gz for gzip' do
666
+ assert_equal '.gz', @i.compression_suffix(:gzip)
667
+ end
668
+ end
669
+
670
+ sub_test_case '#generate_path_template' do
671
+ setup do
672
+ @i = create_driver.instance
673
+ end
674
+
675
+ data(
676
+ 'day' => [86400, '%Y%m%d', '%Y-%m-%d'],
677
+ 'hour' => [3600, '%Y%m%d%H', '%Y-%m-%d_%H'],
678
+ 'minute' => [60, '%Y%m%d%H%M', '%Y-%m-%d_%H%M'],
679
+ )
680
+ test 'generates path with timestamp placeholder for original path with tailing star with timekey' do |data|
681
+ timekey, placeholder, time_slice_format = data
682
+ # with index placeholder, without compression suffix when append disabled and compression disabled
683
+ assert_equal "/path/to/file.#{placeholder}_**", @i.generate_path_template('/path/to/file.*', timekey, false, nil)
684
+ # with index placeholder, with .gz suffix when append disabled and gzip compression enabled
685
+ assert_equal "/path/to/file.#{placeholder}_**.gz", @i.generate_path_template('/path/to/file.*', timekey, false, :gzip)
686
+ # without index placeholder, without compression suffix when append enabled and compression disabled
687
+ assert_equal "/path/to/file.#{placeholder}", @i.generate_path_template('/path/to/file.*', timekey, true, nil)
688
+ # without index placeholder, with .gz suffix when append disabled and gzip compression enabled
689
+ assert_equal "/path/to/file.#{placeholder}.gz", @i.generate_path_template('/path/to/file.*', timekey, true, :gzip)
690
+
691
+ # time_slice_format will used instead of computed placeholder if specified
692
+ assert_equal "/path/to/file.#{time_slice_format}_**", @i.generate_path_template('/path/to/file.*', timekey, false, nil, time_slice_format: time_slice_format)
693
+ assert_equal "/path/to/file.#{time_slice_format}_**.gz", @i.generate_path_template('/path/to/file.*', timekey, false, :gzip, time_slice_format: time_slice_format)
694
+ assert_equal "/path/to/file.#{time_slice_format}", @i.generate_path_template('/path/to/file.*', timekey, true, nil, time_slice_format: time_slice_format)
695
+ assert_equal "/path/to/file.#{time_slice_format}.gz", @i.generate_path_template('/path/to/file.*', timekey, true, :gzip, time_slice_format: time_slice_format)
696
+ end
697
+
698
+ data(
699
+ 'day' => [86400 * 2, '%Y%m%d', '%Y-%m-%d'],
700
+ 'hour' => [7200, '%Y%m%d%H', '%Y-%m-%d_%H'],
701
+ 'minute' => [180, '%Y%m%d%H%M', '%Y-%m-%d_%H%M'],
702
+ )
703
+ test 'generates path with timestamp placeholder for original path with star and suffix with timekey' do |data|
704
+ timekey, placeholder, time_slice_format = data
705
+ # with index placeholder, without compression suffix when append disabled and compression disabled
706
+ assert_equal "/path/to/file.#{placeholder}_**.data", @i.generate_path_template('/path/to/file.*.data', timekey, false, nil)
707
+ # with index placeholder, with .gz suffix when append disabled and gzip compression enabled
708
+ assert_equal "/path/to/file.#{placeholder}_**.data.gz", @i.generate_path_template('/path/to/file.*.data', timekey, false, :gzip)
709
+ # without index placeholder, without compression suffix when append enabled and compression disabled
710
+ assert_equal "/path/to/file.#{placeholder}.data", @i.generate_path_template('/path/to/file.*.data', timekey, true, nil)
711
+ # without index placeholder, with .gz suffix when append disabled and gzip compression enabled
712
+ assert_equal "/path/to/file.#{placeholder}.data.gz", @i.generate_path_template('/path/to/file.*.data', timekey, true, :gzip)
713
+
714
+ # time_slice_format will used instead of computed placeholder if specified
715
+ assert_equal "/path/to/file.#{time_slice_format}_**.data", @i.generate_path_template('/path/to/file.*.data', timekey, false, nil, time_slice_format: time_slice_format)
716
+ assert_equal "/path/to/file.#{time_slice_format}_**.data.gz", @i.generate_path_template('/path/to/file.*.data', timekey, false, :gzip, time_slice_format: time_slice_format)
717
+ assert_equal "/path/to/file.#{time_slice_format}.data", @i.generate_path_template('/path/to/file.*.data', timekey, true, nil, time_slice_format: time_slice_format)
718
+ assert_equal "/path/to/file.#{time_slice_format}.data.gz", @i.generate_path_template('/path/to/file.*.data', timekey, true, :gzip, time_slice_format: time_slice_format)
719
+ end
720
+
721
+ test 'raise error to show it is a bug when path including * specified without timekey' do
722
+ assert_raise "BUG: configuration error must be raised for path including '*' without timekey" do
723
+ @i.generate_path_template('/path/to/file.*.log', nil, false, nil)
724
+ end
725
+ end
726
+
727
+ data(
728
+ 'day' => [86400 * 7, '%Y%m%d', '%Y-%m-%d'],
729
+ 'hour' => [3600 * 6, '%Y%m%d%H', '%Y-%m-%d_%H'],
730
+ 'minute' => [60 * 15, '%Y%m%d%H%M', '%Y-%m-%d_%H%M'],
731
+ )
732
+ test 'generates path with timestamp placeholder for original path without time placeholders & star with timekey, and path_suffix configured' do |data|
733
+ timekey, placeholder, time_slice_format = data
734
+ # with index placeholder, without compression suffix when append disabled and compression disabled
735
+ assert_equal "/path/to/file.#{placeholder}_**.log", @i.generate_path_template('/path/to/file', timekey, false, nil, path_suffix: '.log')
736
+ # with index placeholder, with .gz suffix when append disabled and gzip compression enabled
737
+ assert_equal "/path/to/file.#{placeholder}_**.log.gz", @i.generate_path_template('/path/to/file', timekey, false, :gzip, path_suffix: '.log')
738
+ # without index placeholder, without compression suffix when append enabled and compression disabled
739
+ assert_equal "/path/to/file.#{placeholder}.log", @i.generate_path_template('/path/to/file', timekey, true, nil, path_suffix: '.log')
740
+ # without index placeholder, with compression suffix when append enabled and gzip compression enabled
741
+ assert_equal "/path/to/file.#{placeholder}.log.gz", @i.generate_path_template('/path/to/file', timekey, true, :gzip, path_suffix: '.log')
742
+
743
+ # time_slice_format will be appended always if it's specified
744
+ assert_equal "/path/to/file.#{time_slice_format}_**.log", @i.generate_path_template('/path/to/file', timekey, false, nil, path_suffix: '.log', time_slice_format: time_slice_format)
745
+ assert_equal "/path/to/file.#{time_slice_format}_**.log.gz", @i.generate_path_template('/path/to/file', timekey, false, :gzip, path_suffix: '.log', time_slice_format: time_slice_format)
746
+ assert_equal "/path/to/file.#{time_slice_format}.log", @i.generate_path_template('/path/to/file', timekey, true, nil, path_suffix: '.log', time_slice_format: time_slice_format)
747
+ assert_equal "/path/to/file.#{time_slice_format}.log.gz", @i.generate_path_template('/path/to/file', timekey, true, :gzip, path_suffix: '.log', time_slice_format: time_slice_format)
748
+ end
749
+
750
+ data(
751
+ 'day' => [86400, '%Y%m%d'],
752
+ 'hour' => [3600, '%Y%m%d%H'],
753
+ 'minute' => [60, '%Y%m%d%H%M'],
754
+ )
755
+ test 'generates path with timestamp placeholder for original path without star with timekey, and path_suffix not configured' do |data|
756
+ timekey, placeholder = data
757
+ # with index placeholder, without compression suffix when append disabled and compression disabled
758
+ assert_equal "/path/to/file.#{placeholder}_**", @i.generate_path_template('/path/to/file', timekey, false, nil)
759
+ # with index placeholder, with .gz suffix when append disabled and gzip compression enabled
760
+ assert_equal "/path/to/file.#{placeholder}_**.gz", @i.generate_path_template('/path/to/file', timekey, false, :gzip)
761
+ # without index placeholder, without compression suffix when append enabled and compression disabled
762
+ assert_equal "/path/to/file.#{placeholder}", @i.generate_path_template('/path/to/file', timekey, true, nil)
763
+ # without index placeholder, with compression suffix when append enabled and gzip compression enabled
764
+ assert_equal "/path/to/file.#{placeholder}.gz", @i.generate_path_template('/path/to/file', timekey, true, :gzip)
765
+ end
766
+
767
+ test 'generates path without adding timestamp placeholder part if original path has enough placeholders for specified timekey' do
768
+ assert_equal "/path/to/file.%Y%m%d", @i.generate_path_template('/path/to/file.%Y%m%d', 86400, true, nil)
769
+ assert_equal "/path/to/%Y%m%d/file", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, true, nil)
770
+
771
+ assert_equal "/path/to/%Y%m%d/file_**", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, false, nil)
772
+
773
+ assert_raise Fluent::ConfigError.new("insufficient timestamp placeholders in path") do
774
+ @i.generate_path_template('/path/to/%Y%m/file', 86400, true, nil)
775
+ end
776
+ assert_raise Fluent::ConfigError.new("insufficient timestamp placeholders in path") do
777
+ @i.generate_path_template('/path/to/file.%Y%m%d.log', 3600, true, nil)
778
+ end
779
+
780
+ assert_equal "/path/to/file.%Y%m%d_%H_**.log.gz", @i.generate_path_template('/path/to/file.%Y%m%d_%H', 7200, false, :gzip, path_suffix: '.log')
781
+ assert_equal "/path/to/${tag}/file.%Y%m%d_%H_**.log.gz", @i.generate_path_template('/path/to/${tag}/file.%Y%m%d_%H', 7200, false, :gzip, path_suffix: '.log')
782
+ end
783
+
784
+ test 'generates path with specified time_slice_format appended even if path has sufficient timestamp placeholders' do
785
+ assert_equal "/path/to/%Y%m%d/file.%Y-%m-%d_%H_**", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, false, nil, time_slice_format: '%Y-%m-%d_%H')
786
+ assert_equal "/path/to/%Y%m%d/file.%Y-%m-%d_%H", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, true, nil, time_slice_format: '%Y-%m-%d_%H')
787
+ assert_equal "/path/to/%Y%m%d/file.%Y-%m-%d_%H_**.log", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, false, nil, time_slice_format: '%Y-%m-%d_%H', path_suffix: '.log')
788
+ assert_equal "/path/to/%Y%m%d/file.%Y-%m-%d_%H.log", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, true, nil, time_slice_format: '%Y-%m-%d_%H', path_suffix: '.log')
789
+ assert_equal "/path/to/%Y%m%d/file.%Y-%m-%d_%H.log.gz", @i.generate_path_template('/path/to/%Y%m%d/file', 86400, true, :gzip, time_slice_format: '%Y-%m-%d_%H', path_suffix: '.log')
790
+ end
791
+
792
+ test 'generates path without timestamp placeholder when path does not include * and timekey not specified' do
793
+ assert_equal '/path/to/file.log', @i.generate_path_template('/path/to/file.log', nil, true, nil)
794
+ assert_equal '/path/to/file.log_**', @i.generate_path_template('/path/to/file.log', nil, false, nil)
795
+ assert_equal '/path/to/file.${tag}.log_**', @i.generate_path_template('/path/to/file.${tag}.log', nil, false, nil)
796
+ assert_equal '/path/to/file.${tag}_**.log', @i.generate_path_template('/path/to/file.${tag}', nil, false, nil, path_suffix: '.log')
797
+ end
798
+ end
799
+
800
+ sub_test_case '#find_filepath_available' do
801
+ setup do
802
+ @tmp = File.join(TMP_DIR, 'find_filepath_test')
803
+ FileUtils.mkdir_p @tmp
804
+ @i = create_driver.instance
805
+ end
806
+
807
+ teardown do
808
+ FileUtils.rm_rf @tmp
809
+ end
810
+
811
+ test 'raise error if argument path does not include index placeholder' do
812
+ assert_raise "BUG: index placeholder not found in path: #{@tmp}/myfile" do
813
+ @i.find_filepath_available("#{@tmp}/myfile")
814
+ end
815
+ end
816
+
817
+ data(
818
+ 'without suffix' => ['myfile_0', 'myfile_**'],
819
+ 'with timestamp' => ['myfile_20161003_0', 'myfile_20161003_**'],
820
+ 'with base suffix' => ['myfile_0.log', 'myfile_**.log'],
821
+ 'with compression suffix' => ['myfile_0.log.gz', 'myfile_**.log.gz'],
822
+ )
823
+ test 'returns filepath with _0 at first' do |data|
824
+ expected, argument = data
825
+ assert_equal File.join(@tmp, expected), @i.find_filepath_available(File.join(@tmp, argument))
826
+ end
827
+
828
+ test 'returns filepath with index which does not exist yet' do
829
+ 5.times do |i|
830
+ File.open(File.join(@tmp, "exist_#{i}.log"), 'a')
831
+ end
832
+ assert_equal File.join(@tmp, "exist_5.log"), @i.find_filepath_available(File.join(@tmp, "exist_**.log"))
833
+ end
834
+ end
835
+ end