fluentd 0.14.8 → 0.14.9

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