fluentd 1.12.1 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.deepsource.toml +13 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  4. data/.github/workflows/linux-test.yaml +36 -0
  5. data/.github/workflows/{build.yaml → macos-test.yaml} +8 -7
  6. data/.github/workflows/windows-test.yaml +46 -0
  7. data/.gitlab-ci.yml +19 -19
  8. data/CHANGELOG.md +163 -0
  9. data/CONTRIBUTING.md +2 -2
  10. data/MAINTAINERS.md +5 -2
  11. data/README.md +6 -3
  12. data/example/counter.conf +1 -1
  13. data/fluentd.gemspec +4 -2
  14. data/lib/fluent/command/bundler_injection.rb +1 -1
  15. data/lib/fluent/command/cat.rb +19 -4
  16. data/lib/fluent/command/fluentd.rb +1 -2
  17. data/lib/fluent/command/plugin_config_formatter.rb +2 -1
  18. data/lib/fluent/command/plugin_generator.rb +31 -1
  19. data/lib/fluent/compat/parser.rb +2 -2
  20. data/lib/fluent/config/section.rb +6 -1
  21. data/lib/fluent/config/types.rb +2 -2
  22. data/lib/fluent/event.rb +3 -13
  23. data/lib/fluent/load.rb +0 -1
  24. data/lib/fluent/log.rb +1 -0
  25. data/lib/fluent/plugin/file_wrapper.rb +49 -4
  26. data/lib/fluent/plugin/formatter_ltsv.rb +2 -2
  27. data/lib/fluent/plugin/in_http.rb +11 -1
  28. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  29. data/lib/fluent/plugin/in_tail.rb +140 -41
  30. data/lib/fluent/plugin/in_tail/position_file.rb +15 -1
  31. data/lib/fluent/plugin/out_copy.rb +18 -5
  32. data/lib/fluent/plugin/out_exec_filter.rb +3 -3
  33. data/lib/fluent/plugin/out_forward.rb +75 -61
  34. data/lib/fluent/plugin/output.rb +11 -9
  35. data/lib/fluent/plugin/parser_csv.rb +2 -2
  36. data/lib/fluent/plugin/parser_syslog.rb +2 -2
  37. data/lib/fluent/plugin/service_discovery.rb +0 -15
  38. data/lib/fluent/plugin/storage_local.rb +4 -4
  39. data/lib/fluent/plugin_helper/http_server/router.rb +1 -1
  40. data/lib/fluent/plugin_helper/server.rb +4 -2
  41. data/lib/fluent/plugin_helper/service_discovery.rb +39 -1
  42. data/lib/fluent/plugin_helper/service_discovery/manager.rb +11 -5
  43. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  44. data/lib/fluent/supervisor.rb +16 -1
  45. data/lib/fluent/system_config.rb +14 -0
  46. data/lib/fluent/time.rb +57 -1
  47. data/lib/fluent/version.rb +1 -1
  48. data/templates/new_gem/fluent-plugin.gemspec.erb +3 -3
  49. data/test/command/test_cat.rb +99 -0
  50. data/test/command/test_fluentd.rb +8 -0
  51. data/test/config/test_configurable.rb +1 -1
  52. data/test/config/test_section.rb +9 -0
  53. data/test/config/test_system_config.rb +46 -0
  54. data/test/plugin/in_tail/test_io_handler.rb +4 -4
  55. data/test/plugin/in_tail/test_position_file.rb +58 -4
  56. data/test/plugin/test_file_wrapper.rb +115 -0
  57. data/test/plugin/test_in_exec.rb +1 -1
  58. data/test/plugin/test_in_forward.rb +59 -83
  59. data/test/plugin/test_in_http.rb +58 -40
  60. data/test/plugin/test_in_syslog.rb +66 -56
  61. data/test/plugin/test_in_tail.rb +298 -26
  62. data/test/plugin/test_in_tcp.rb +45 -32
  63. data/test/plugin/test_in_udp.rb +47 -33
  64. data/test/plugin/test_out_copy.rb +87 -0
  65. data/test/plugin/test_out_forward.rb +198 -91
  66. data/test/plugin/test_out_http.rb +1 -1
  67. data/test/plugin/test_out_stream.rb +18 -8
  68. data/test/plugin/test_output.rb +15 -3
  69. data/test/plugin/test_output_as_buffered_backup.rb +2 -0
  70. data/test/plugin/test_parser_csv.rb +14 -0
  71. data/test/plugin/test_parser_syslog.rb +14 -0
  72. data/test/plugin_helper/http_server/test_route.rb +1 -1
  73. data/test/plugin_helper/service_discovery/test_manager.rb +1 -1
  74. data/test/plugin_helper/test_child_process.rb +6 -3
  75. data/test/plugin_helper/test_http_server_helper.rb +34 -27
  76. data/test/plugin_helper/test_server.rb +144 -139
  77. data/test/plugin_helper/test_service_discovery.rb +74 -14
  78. data/test/plugin_helper/test_socket.rb +16 -9
  79. data/test/test_config.rb +2 -1
  80. data/test/test_event.rb +16 -0
  81. data/test/test_formatter.rb +30 -0
  82. data/test/test_output.rb +2 -2
  83. data/test/test_supervisor.rb +35 -0
  84. data/test/test_time_parser.rb +109 -0
  85. metadata +33 -9
  86. data/.travis.yml +0 -77
  87. data/appveyor.yml +0 -31
@@ -17,6 +17,24 @@ class ServiceDiscoveryHelper < Test::Unit::TestCase
17
17
  end
18
18
  end
19
19
 
20
+ class DummyPlugin < Fluent::Plugin::TestBase
21
+ helpers :service_discovery
22
+
23
+ def configure(conf)
24
+ super
25
+ service_discovery_configure(:service_discovery_helper_test, static_default_service_directive: 'node')
26
+ end
27
+
28
+ def select_service(&block)
29
+ service_discovery_select_service(&block)
30
+ end
31
+
32
+ # Make these mehtod public
33
+ def discovery_manager
34
+ super
35
+ end
36
+ end
37
+
20
38
  setup do
21
39
  @sd_file_dir = File.expand_path('../plugin/data/sd_file', __dir__)
22
40
 
@@ -33,7 +51,7 @@ class ServiceDiscoveryHelper < Test::Unit::TestCase
33
51
  end
34
52
  end
35
53
 
36
- test 'start discovery manager' do
54
+ test 'support calling #service_discovery_create_manager and #discovery_manager from plugin' do
37
55
  d = @d = Dummy.new
38
56
 
39
57
  d.service_discovery_create_manager(
@@ -55,13 +73,30 @@ class ServiceDiscoveryHelper < Test::Unit::TestCase
55
73
  assert_equal 1234, services[0].port
56
74
  end
57
75
 
58
- test 'call timer_execute if dynamic configuration' do
59
- d = @d = Dummy.new
76
+ test 'start discovery manager' do
77
+ d = @d = DummyPlugin.new
60
78
 
61
- d.service_discovery_create_manager(
62
- :service_discovery_helper_test,
63
- configurations: [{ type: :file, conf: config_element('file_config', '', { 'path' => File.join(@sd_file_dir, 'config.yml') }) }],
64
- )
79
+ services = [config_element('service', '', { 'host' => '127.0.0.1', 'port' => '1234' })]
80
+ d.configure(config_element('root', '', {}, [config_element('service_discovery', '', {'@type' => 'static'}, services)]))
81
+
82
+ assert_true !!d.discovery_manager
83
+
84
+ mock.proxy(d.discovery_manager).start.once
85
+ mock.proxy(d).timer_execute(:service_discovery_helper_test, anything).never
86
+
87
+ d.start
88
+ d.event_loop_wait_until_start
89
+
90
+ assert_equal 1, d.discovery_manager.services.size
91
+ d.select_service do |serv|
92
+ assert_equal "127.0.0.1", serv.host
93
+ assert_equal 1234, serv.port
94
+ end
95
+ end
96
+
97
+ test 'call timer_execute if dynamic configuration' do
98
+ d = @d = DummyPlugin.new
99
+ d.configure(config_element('root', '', {}, [config_element('service_discovery', '', { '@type' => 'file', 'path' => File.join(@sd_file_dir, 'config.yml' )})]))
65
100
 
66
101
  assert_true !!d.discovery_manager
67
102
  mock.proxy(d.discovery_manager).start.once
@@ -71,25 +106,22 @@ class ServiceDiscoveryHelper < Test::Unit::TestCase
71
106
  end
72
107
 
73
108
  test 'exits service discovery instances without any errors' do
74
- d = @d = Dummy.new
109
+ d = @d = DummyPlugin.new
75
110
  mockv = flexmock('dns_resolver', getaddress: '127.0.0.1')
76
111
  .should_receive(:getresources)
77
112
  .and_return([Resolv::DNS::Resource::IN::SRV.new(1, 10, 8081, 'service1.example.com')])
78
113
  .mock
79
114
  mock(Resolv::DNS).new { mockv }
80
115
 
81
- d.service_discovery_create_manager(
82
- :service_discovery_helper_test2,
83
- configurations: [{ type: :srv, conf: config_element('service_discovery', '', { 'service' => 'service1', 'hostname' => 'example.com' }) }],
84
- )
116
+ d.configure(config_element('root', '', {}, [config_element('service_discovery', '', { '@type' => 'srv', 'service' => 'service1', 'hostname' => 'example.com' })]))
85
117
 
86
118
  assert_true !!d.discovery_manager
87
119
  mock.proxy(d.discovery_manager).start.once
88
- mock(d).timer_execute(:service_discovery_helper_test2, anything).once
120
+ mock(d).timer_execute(:service_discovery_helper_test, anything).once
89
121
 
90
122
  # To avoid claring `@logs` during `terminate` step
91
123
  # https://github.com/fluent/fluentd/blob/bc78d889f93dad8c2a4e0ad1ca802546185dacba/lib/fluent/test/log.rb#L33
92
- mock(d.log).reset.twice
124
+ mock(d.log).reset.times(3)
93
125
 
94
126
  d.start
95
127
  d.event_loop_wait_until_start
@@ -102,4 +134,32 @@ class ServiceDiscoveryHelper < Test::Unit::TestCase
102
134
 
103
135
  assert_false(d.log.out.logs.any? { |e| e.match?(/thread doesn't exit correctly/) })
104
136
  end
137
+
138
+ test 'static service discovery will be configured automatically when default service directive is specified' do
139
+ d = @d = DummyPlugin.new
140
+
141
+ nodes = [
142
+ config_element('node', '', { 'host' => '192.168.0.1', 'port' => '24224' }),
143
+ config_element('node', '', { 'host' => '192.168.0.2', 'port' => '24224' })
144
+ ]
145
+ d.configure(config_element('root', '', {}, nodes))
146
+
147
+ assert_true !!d.discovery_manager
148
+
149
+ mock.proxy(d.discovery_manager).start.once
150
+ mock.proxy(d).timer_execute(:service_discovery_helper_test, anything).never
151
+
152
+ d.start
153
+ d.event_loop_wait_until_start
154
+
155
+ assert_equal 2, d.discovery_manager.services.size
156
+ d.select_service do |serv|
157
+ assert_equal "192.168.0.1", serv.host
158
+ assert_equal 24224, serv.port
159
+ end
160
+ d.select_service do |serv|
161
+ assert_equal "192.168.0.2", serv.host
162
+ assert_equal 24224, serv.port
163
+ end
164
+ end
105
165
  end
@@ -6,17 +6,24 @@ require 'socket'
6
6
  require 'openssl'
7
7
 
8
8
  class SocketHelperTest < Test::Unit::TestCase
9
- PORT = unused_port
10
9
  CERT_DIR = File.expand_path(File.dirname(__FILE__) + '/data/cert/without_ca')
11
10
  CA_CERT_DIR = File.expand_path(File.dirname(__FILE__) + '/data/cert/with_ca')
12
11
  CERT_CHAINS_DIR = File.expand_path(File.dirname(__FILE__) + '/data/cert/cert_chains')
13
12
 
13
+ def setup
14
+ @port = unused_port
15
+ end
16
+
17
+ def teardown
18
+ @port = nil
19
+ end
20
+
14
21
  class SocketHelperTestPlugin < Fluent::Plugin::TestBase
15
22
  helpers :socket
16
23
  end
17
24
 
18
25
  class EchoTLSServer
19
- def initialize(host = '127.0.0.1', port = PORT, cert_path: nil, private_key_path: nil, ca_path: nil)
26
+ def initialize(port, host: '127.0.0.1', cert_path: nil, private_key_path: nil, ca_path: nil)
20
27
  server = TCPServer.open(host, port)
21
28
  ctx = OpenSSL::SSL::SSLContext.new
22
29
  ctx.cert = OpenSSL::X509::Certificate.new(File.open(cert_path)) if cert_path
@@ -91,8 +98,8 @@ class SocketHelperTest < Test::Unit::TestCase
91
98
  cert_path = File.join(CERT_DIR, 'cert.pem')
92
99
  private_key_path = File.join(CERT_DIR, 'cert-key.pem')
93
100
 
94
- EchoTLSServer.new(cert_path: cert_path, private_key_path: private_key_path).start do
95
- client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', PORT, verify_fqdn: false, cert_paths: [cert_path])
101
+ EchoTLSServer.new(@port, cert_path: cert_path, private_key_path: private_key_path).start do
102
+ client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', @port, verify_fqdn: false, cert_paths: [cert_path])
96
103
  client.write('hello')
97
104
  assert_equal 'hello', client.readpartial(100)
98
105
  client.close
@@ -105,8 +112,8 @@ class SocketHelperTest < Test::Unit::TestCase
105
112
 
106
113
  ca_cert_path = File.join(CA_CERT_DIR, 'ca-cert.pem')
107
114
 
108
- EchoTLSServer.new(cert_path: cert_path, private_key_path: private_key_path).start do
109
- client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', PORT, verify_fqdn: false, cert_paths: [ca_cert_path])
115
+ EchoTLSServer.new(@port, cert_path: cert_path, private_key_path: private_key_path).start do
116
+ client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', @port, verify_fqdn: false, cert_paths: [ca_cert_path])
110
117
  client.write('hello')
111
118
  assert_equal 'hello', client.readpartial(100)
112
119
  client.close
@@ -121,8 +128,8 @@ class SocketHelperTest < Test::Unit::TestCase
121
128
  client_cert_path = File.join(CERT_CHAINS_DIR, 'cert.pem')
122
129
  client_private_key_path = File.join(CERT_CHAINS_DIR, 'cert-key.pem')
123
130
 
124
- EchoTLSServer.new(cert_path: cert_path, private_key_path: private_key_path, ca_path: client_ca_cert_path).start do
125
- client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', PORT, verify_fqdn: false, cert_path: client_cert_path, private_key_path: client_private_key_path, cert_paths: [cert_path])
131
+ EchoTLSServer.new(@port, cert_path: cert_path, private_key_path: private_key_path, ca_path: client_ca_cert_path).start do
132
+ client = SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', @port, verify_fqdn: false, cert_path: client_cert_path, private_key_path: client_private_key_path, cert_paths: [cert_path])
126
133
  client.write('hello')
127
134
  assert_equal 'hello', client.readpartial(100)
128
135
  client.close
@@ -133,7 +140,7 @@ class SocketHelperTest < Test::Unit::TestCase
133
140
  cert_path = File.expand_path(File.dirname(__FILE__) + '/data/cert/empty.pem')
134
141
 
135
142
  assert_raise Fluent::ConfigError do
136
- SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', PORT, cert_path: cert_path)
143
+ SocketHelperTestPlugin.new.socket_create_tls('127.0.0.1', @port, cert_path: cert_path)
137
144
  end
138
145
  end
139
146
  end
data/test/test_config.rb CHANGED
@@ -160,7 +160,8 @@ class ConfigTest < Test::Unit::TestCase
160
160
  prepare_config
161
161
  opts = {
162
162
  :config_path => "#{TMP_DIR}/config_test_1.conf",
163
- :inline_config => "<source>\n type http\n port 2222\n </source>"
163
+ :inline_config => "<source>\n type http\n port 2222\n </source>",
164
+ :use_v1_config => false
164
165
  }
165
166
  assert_nothing_raised do
166
167
  Fluent::Supervisor.new(opts)
data/test/test_event.rb CHANGED
@@ -401,6 +401,22 @@ module EventTest
401
401
  i += 1
402
402
  }
403
403
  end
404
+
405
+ # `any?` represents an Enumerable method which calls `each` internally
406
+ test 'size_after_any' do
407
+ @es.any?
408
+
409
+ assert_equal 2, @es.size
410
+ end
411
+
412
+ # `any?` represents an Enumerable method which calls `each` internally
413
+ test 'each_after_any' do
414
+ @es.any?
415
+
416
+ count = 0
417
+ @es.each { |time, record| count += 1 }
418
+ assert_equal 2, count
419
+ end
404
420
  end
405
421
 
406
422
  class CompressedMessagePackEventStreamTest < ::Test::Unit::TestCase
@@ -184,6 +184,36 @@ module FormatterTest
184
184
 
185
185
  assert_equal("message=awesome,greeting=hello#{@newline}", formatted)
186
186
  end
187
+
188
+ def record_with_tab
189
+ {'message' => "awe\tsome", 'greeting' => "hello\t"}
190
+ end
191
+
192
+ def test_format_suppresses_tab
193
+ @formatter.configure({})
194
+ formatted = @formatter.format(tag, @time, record_with_tab)
195
+
196
+ assert_equal("message:awe some\tgreeting:hello #{@newline}", formatted)
197
+ end
198
+
199
+ def test_format_suppresses_tab_custom_replacement
200
+ @formatter.configure(
201
+ 'replacement' => 'X',
202
+ )
203
+ formatted = @formatter.format(tag, @time, record_with_tab)
204
+
205
+ assert_equal("message:aweXsome\tgreeting:helloX#{@newline}", formatted)
206
+ end
207
+
208
+ def test_format_suppresses_custom_delimiter
209
+ @formatter.configure(
210
+ 'delimiter' => 'w',
211
+ 'label_delimiter' => '=',
212
+ )
213
+ formatted = @formatter.format(tag, @time, record)
214
+
215
+ assert_equal("message=a esomewgreeting=hello#{@newline}", formatted)
216
+ end
187
217
  end
188
218
 
189
219
  class CsvFormatterTest < ::Test::Unit::TestCase
data/test/test_output.rb CHANGED
@@ -117,7 +117,7 @@ module FluentOutputTest
117
117
  end
118
118
 
119
119
  mock(d.instance.log).warn("Use different plugin for secondary. Check the plugin works with primary like secondary_file",
120
- { primary: d.instance.class.to_s, secondary: "Fluent::Plugin::Test2Output" })
120
+ primary: d.instance.class.to_s, secondary: "Fluent::Plugin::Test2Output")
121
121
  d.configure(CONFIG + %[
122
122
  <secondary>
123
123
  type test2
@@ -133,7 +133,7 @@ module FluentOutputTest
133
133
  d = Fluent::Test::BufferedOutputTestDriver.new(Fluent::ObjectBufferedOutput)
134
134
 
135
135
  mock(d.instance.log).warn("Use different plugin for secondary. Check the plugin works with primary like secondary_file",
136
- { primary: d.instance.class.to_s, secondary: "Fluent::Plugin::Test2Output" }).never
136
+ primary: d.instance.class.to_s, secondary: "Fluent::Plugin::Test2Output").never
137
137
  d.configure(CONFIG + %[
138
138
  <secondary>
139
139
  type test2
@@ -7,6 +7,7 @@ require_relative 'test_plugin_classes'
7
7
  require 'net/http'
8
8
  require 'uri'
9
9
  require 'fileutils'
10
+ require 'tempfile'
10
11
 
11
12
  if Fluent.windows?
12
13
  require 'win32/event'
@@ -489,6 +490,40 @@ class SupervisorTest < ::Test::Unit::TestCase
489
490
  assert_equal 10, $log.out.instance_variable_get(:@shift_size)
490
491
  end
491
492
 
493
+ sub_test_case "system log rotation" do
494
+ def parse_text(text)
495
+ basepath = File.expand_path(File.dirname(__FILE__) + '/../../')
496
+ Fluent::Config.parse(text, '(test)', basepath, true).elements.find { |e| e.name == 'system' }
497
+ end
498
+
499
+ def test_override_default_log_rotate
500
+ Tempfile.open do |file|
501
+ config = parse_text(<<-EOS)
502
+ <system>
503
+ <log>
504
+ rotate_age 3
505
+ rotate_size 300
506
+ </log>
507
+ </system>
508
+ EOS
509
+ file.puts(config)
510
+ file.flush
511
+ opts = Fluent::Supervisor.default_options.merge(
512
+ log_path: "#{TMP_DIR}/test.log", config_path: file.path
513
+ )
514
+ sv = Fluent::Supervisor.new(opts)
515
+
516
+ log = sv.instance_variable_get(:@log)
517
+ log.init(:standalone, 0)
518
+ logger = $log.instance_variable_get(:@logger)
519
+
520
+ assert_equal([3, 300],
521
+ [logger.instance_variable_get(:@rotate_age),
522
+ logger.instance_variable_get(:@rotate_size)])
523
+ end
524
+ end
525
+ end
526
+
492
527
  def test_inline_config
493
528
  omit 'this feature is deprecated. see https://github.com/fluent/fluentd/issues/2711'
494
529
 
@@ -228,4 +228,113 @@ class TimeParserTest < ::Test::Unit::TestCase
228
228
  assert_equal_event_time(time, parser.parse("#{time.sec}.#{time.nsec}"))
229
229
  end
230
230
  end
231
+
232
+ sub_test_case 'MixedTimeParser fallback' do
233
+ class DummyForTimeParser
234
+ include Fluent::Configurable
235
+ include Fluent::TimeMixin::Parser
236
+ end
237
+
238
+ test 'no time_format_fallbacks failure' do
239
+ i = DummyForTimeParser.new
240
+ assert_raise(Fluent::ConfigError.new("time_type is :mixed but time_format and time_format_fallbacks is empty.")) do
241
+ i.configure(config_element('parse', '', {'time_type' => 'mixed'}))
242
+ end
243
+ end
244
+
245
+ test 'fallback time format failure' do
246
+ i = DummyForTimeParser.new
247
+ i.configure(config_element('parse', '',
248
+ {'time_type' => 'mixed',
249
+ 'time_format_fallbacks' => ['%iso8601']}))
250
+ parser = i.time_parser_create
251
+ assert_raise(Fluent::TimeParser::TimeParseError.new("invalid time format: value = INVALID, even though fallbacks: Fluent::TimeParser")) do
252
+ parser.parse("INVALID")
253
+ end
254
+ end
255
+
256
+ test 'primary format is unixtime, secondary %iso8601 is used' do
257
+ i = DummyForTimeParser.new
258
+ i.configure(config_element('parse', '',
259
+ {'time_type' => 'mixed',
260
+ 'time_format' => 'unixtime',
261
+ 'time_format_fallbacks' => ['%iso8601']}))
262
+ parser = i.time_parser_create
263
+ time = event_time('2021-01-01T12:00:00+0900')
264
+ assert_equal_event_time(time, parser.parse('2021-01-01T12:00:00+0900'))
265
+ end
266
+
267
+ test 'primary format is %iso8601, secondary unixtime is used' do
268
+ i = DummyForTimeParser.new
269
+ i.configure(config_element('parse', '',
270
+ {'time_type' => 'mixed',
271
+ 'time_format' => '%iso8601',
272
+ 'time_format_fallbacks' => ['unixtime']}))
273
+ parser = i.time_parser_create
274
+ time = event_time('2021-01-01T12:00:00+0900')
275
+ assert_equal_event_time(time, parser.parse("#{time.sec}"))
276
+ end
277
+
278
+ test 'primary format is %iso8601, no secondary is used' do
279
+ i = DummyForTimeParser.new
280
+ i.configure(config_element('parse', '',
281
+ {'time_type' => 'mixed',
282
+ 'time_format' => '%iso8601'}))
283
+ parser = i.time_parser_create
284
+ time = event_time('2021-01-01T12:00:00+0900')
285
+ assert_equal_event_time(time, parser.parse("2021-01-01T12:00:00+0900"))
286
+ end
287
+
288
+ test 'primary format is unixtime, no secondary is used' do
289
+ i = DummyForTimeParser.new
290
+ i.configure(config_element('parse', '',
291
+ {'time_type' => 'mixed',
292
+ 'time_format' => 'unixtime'}))
293
+ parser = i.time_parser_create
294
+ time = event_time('2021-01-01T12:00:00+0900')
295
+ assert_equal_event_time(time, parser.parse("#{time.sec}"))
296
+ end
297
+
298
+ test 'primary format is %iso8601, raise error because of no appropriate secondary' do
299
+ i = DummyForTimeParser.new
300
+ i.configure(config_element('parse', '',
301
+ {'time_type' => 'mixed',
302
+ 'time_format' => '%iso8601'}))
303
+ parser = i.time_parser_create
304
+ time = event_time('2021-01-01T12:00:00+0900')
305
+ assert_raise("Fluent::TimeParser::TimeParseError: invalid time format: value = #{time.sec}, even though fallbacks: Fluent::TimeParser") do
306
+ parser.parse("#{time.sec}")
307
+ end
308
+ end
309
+
310
+ test 'primary format is unixtime, raise error because of no appropriate secondary' do
311
+ i = DummyForTimeParser.new
312
+ i.configure(config_element('parse', '',
313
+ {'time_type' => 'mixed',
314
+ 'time_format' => 'unixtime'}))
315
+ parser = i.time_parser_create
316
+ time = event_time('2021-01-01T12:00:00+0900')
317
+ assert_raise("Fluent::TimeParser::TimeParseError: invalid time format: value = #{time}, even though fallbacks: Fluent::NumericTimeParser") do
318
+ parser.parse("2021-01-01T12:00:00+0900")
319
+ end
320
+ end
321
+
322
+ test 'fallback to unixtime' do
323
+ i = DummyForTimeParser.new
324
+ i.configure(config_element('parse', '', {'time_type' => 'mixed',
325
+ 'time_format_fallbacks' => ['%iso8601', 'unixtime']}))
326
+ parser = i.time_parser_create
327
+ time = event_time('2021-01-01T12:00:00+0900')
328
+ assert_equal_event_time(Fluent::EventTime.new(time.to_i), parser.parse("#{time.sec}"))
329
+ end
330
+
331
+ test 'fallback to %iso8601' do
332
+ i = DummyForTimeParser.new
333
+ i.configure(config_element('parse', '', {'time_type' => 'mixed',
334
+ 'time_format_fallbacks' => ['unixtime', '%iso8601']}))
335
+ parser = i.time_parser_create
336
+ time = event_time('2021-01-01T12:00:00+0900')
337
+ assert_equal_event_time(time, parser.parse('2021-01-01T12:00:00+0900'))
338
+ end
339
+ end
231
340
  end