fluent-plugin-elasticsearch 3.5.4 → 3.5.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1001 +1,1001 @@
1
- require 'helper'
2
- require 'date'
3
- require 'fluent/test/helpers'
4
- require 'fluent/test/driver/output'
5
- require 'flexmock/test_unit'
6
-
7
- class ElasticsearchOutputDynamic < Test::Unit::TestCase
8
- include FlexMock::TestCase
9
- include Fluent::Test::Helpers
10
-
11
- attr_accessor :index_cmds, :index_command_counts
12
-
13
- def setup
14
- Fluent::Test.setup
15
- require 'fluent/plugin/out_elasticsearch_dynamic'
16
- @driver = nil
17
- end
18
-
19
- def driver(conf='', es_version=5)
20
- # For request stub to detect compatibility.
21
- @es_version ||= es_version
22
- Fluent::Plugin::ElasticsearchOutputDynamic.module_eval(<<-CODE)
23
- def detect_es_major_version
24
- #{@es_version}
25
- end
26
- CODE
27
- @driver ||= Fluent::Test::Driver::Output.new(Fluent::Plugin::ElasticsearchOutputDynamic) {
28
- # v0.12's test driver assume format definition. This simulates ObjectBufferedOutput format
29
- if !defined?(Fluent::Plugin::Output)
30
- def format(tag, time, record)
31
- [time, record].to_msgpack
32
- end
33
- end
34
- }.configure(conf)
35
- end
36
-
37
- def default_type_name
38
- Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME
39
- end
40
-
41
- def sample_record
42
- {'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
43
- end
44
-
45
- def nested_sample_record
46
- {'nested' =>
47
- {'age' => 26, 'parent_id' => 'parent', 'routing_id' => 'routing', 'request_id' => '42'}
48
- }
49
- end
50
-
51
- def stub_elastic(url="http://localhost:9200/_bulk")
52
- stub_request(:post, url).with do |req|
53
- @index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
54
- end
55
- end
56
-
57
- def stub_elastic_unavailable(url="http://localhost:9200/_bulk")
58
- stub_request(:post, url).to_return(:status => [503, "Service Unavailable"])
59
- end
60
-
61
- def stub_elastic_timeout(url="http://localhost:9200/_bulk")
62
- stub_request(:post, url).to_timeout
63
- end
64
-
65
- def stub_elastic_with_store_index_command_counts(url="http://localhost:9200/_bulk")
66
- if @index_command_counts == nil
67
- @index_command_counts = {}
68
- @index_command_counts.default = 0
69
- end
70
-
71
- stub_request(:post, url).with do |req|
72
- index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
73
- @index_command_counts[url] += index_cmds.size
74
- end
75
- end
76
-
77
- def assert_logs_include(logs, msg, exp_matches=1)
78
- matches = logs.grep /#{msg}/
79
- assert_equal(exp_matches, matches.length, "Logs do not contain '#{msg}' '#{logs}'")
80
- end
81
-
82
- def test_configure
83
- config = %{
84
- host logs.google.com
85
- port 777
86
- scheme https
87
- path /es/
88
- user john
89
- password doe
90
- }
91
- instance = driver(config).instance
92
-
93
- conf = instance.dynamic_config
94
- assert_equal 'logs.google.com', conf['host']
95
- assert_equal "777", conf['port']
96
- assert_equal :https, instance.scheme
97
- assert_equal 'john', instance.user
98
- assert_equal 'doe', instance.password
99
- assert_equal '/es/', instance.path
100
- assert_equal :TLSv1, instance.ssl_version
101
- assert_nil instance.client_key
102
- assert_nil instance.client_cert
103
- assert_nil instance.client_key_pass
104
- assert_false instance.with_transporter_log
105
- assert_equal :"application/json", instance.content_type
106
- assert_equal :excon, instance.http_backend
107
- end
108
-
109
- test 'configure Content-Type' do
110
- config = %{
111
- content_type application/x-ndjson
112
- }
113
- instance = driver(config).instance
114
- assert_equal :"application/x-ndjson", instance.content_type
115
- end
116
-
117
- test 'invalid Content-Type' do
118
- config = %{
119
- content_type nonexistent/invalid
120
- }
121
- assert_raise(Fluent::ConfigError) {
122
- instance = driver(config).instance
123
- }
124
- end
125
-
126
- test 'Detected Elasticsearch 7' do
127
- config = %{
128
- type_name changed
129
- }
130
- instance = driver(config, 7).instance
131
- assert_equal '_doc', instance.type_name
132
- end
133
-
134
- sub_test_case 'connection exceptions' do
135
- test 'default connection exception' do
136
- driver(Fluent::Config::Element.new(
137
- 'ROOT', '', {
138
- '@type' => 'elasticsearch',
139
- 'host' => 'log.google.com',
140
- 'port' => 777,
141
- 'scheme' => 'https',
142
- 'path' => '/es/',
143
- 'user' => 'john',
144
- 'pasword' => 'doe',
145
- }, [
146
- Fluent::Config::Element.new('buffer', 'tag', {
147
- }, [])
148
- ]
149
- ))
150
- logs = driver.logs
151
- assert_logs_include(logs, /you should specify 2 or more 'flush_thread_count'/, 1)
152
- end
153
- end
154
-
155
- def test_defaults
156
- config = %{
157
- host logs.google.com
158
- scheme https
159
- path /es/
160
- user john
161
- password doe
162
- }
163
- instance = driver(config).instance
164
-
165
- conf = instance.dynamic_config
166
- assert_equal "9200", conf['port']
167
- assert_equal "false", conf['logstash_format']
168
- assert_equal "true", conf['utc_index']
169
- assert_equal false, instance.time_key_exclude_timestamp
170
- end
171
-
172
- def test_legacy_hosts_list
173
- config = %{
174
- hosts host1:50,host2:100,host3
175
- scheme https
176
- path /es/
177
- port 123
178
- }
179
- instance = driver(config).instance
180
-
181
- assert_equal 3, instance.get_connection_options(nil)[:hosts].length
182
- host1, host2, host3 = instance.get_connection_options(nil)[:hosts]
183
-
184
- assert_equal 'host1', host1[:host]
185
- assert_equal 50, host1[:port]
186
- assert_equal 'https', host1[:scheme]
187
- assert_equal '/es/', host2[:path]
188
- assert_equal 'host3', host3[:host]
189
- assert_equal 123, host3[:port]
190
- assert_equal 'https', host3[:scheme]
191
- assert_equal '/es/', host3[:path]
192
- end
193
-
194
- def test_hosts_list
195
- config = %{
196
- hosts https://john:password@host1:443/elastic/,http://host2
197
- path /default_path
198
- user default_user
199
- password default_password
200
- }
201
- instance = driver(config).instance
202
-
203
- assert_equal 2, instance.get_connection_options(nil)[:hosts].length
204
- host1, host2 = instance.get_connection_options(nil)[:hosts]
205
-
206
- assert_equal 'host1', host1[:host]
207
- assert_equal 443, host1[:port]
208
- assert_equal 'https', host1[:scheme]
209
- assert_equal 'john', host1[:user]
210
- assert_equal 'password', host1[:password]
211
- assert_equal '/elastic/', host1[:path]
212
-
213
- assert_equal 'host2', host2[:host]
214
- assert_equal 'http', host2[:scheme]
215
- assert_equal 'default_user', host2[:user]
216
- assert_equal 'default_password', host2[:password]
217
- assert_equal '/default_path', host2[:path]
218
- end
219
-
220
- def test_hosts_list_with_escape_placeholders
221
- config = %{
222
- hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
223
- path /default_path
224
- user default_user
225
- password default_password
226
- }
227
- instance = driver(config).instance
228
-
229
- assert_equal 2, instance.get_connection_options(nil)[:hosts].length
230
- host1, host2 = instance.get_connection_options(nil)[:hosts]
231
-
232
- assert_equal 'host1', host1[:host]
233
- assert_equal 443, host1[:port]
234
- assert_equal 'https', host1[:scheme]
235
- assert_equal 'j%2Bhn', host1[:user]
236
- assert_equal 'passw%40rd', host1[:password]
237
- assert_equal '/elastic/', host1[:path]
238
-
239
- assert_equal 'host2', host2[:host]
240
- assert_equal 'http', host2[:scheme]
241
- assert_equal 'default_user', host2[:user]
242
- assert_equal 'default_password', host2[:password]
243
- assert_equal '/default_path', host2[:path]
244
- end
245
-
246
- def test_single_host_params_and_defaults
247
- config = %{
248
- host logs.google.com
249
- user john
250
- password doe
251
- }
252
- instance = driver(config).instance
253
-
254
- assert_equal 1, instance.get_connection_options(nil)[:hosts].length
255
- host1 = instance.get_connection_options(nil)[:hosts][0]
256
-
257
- assert_equal 'logs.google.com', host1[:host]
258
- assert_equal 9200, host1[:port]
259
- assert_equal 'http', host1[:scheme]
260
- assert_equal 'john', host1[:user]
261
- assert_equal 'doe', host1[:password]
262
- assert_equal nil, host1[:path]
263
- end
264
-
265
- def test_single_host_params_and_defaults_with_escape_placeholders
266
- config = %{
267
- host logs.google.com
268
- user %{j+hn}
269
- password %{d@e}
270
- }
271
- instance = driver(config).instance
272
-
273
- assert_equal 1, instance.get_connection_options(nil)[:hosts].length
274
- host1 = instance.get_connection_options(nil)[:hosts][0]
275
-
276
- assert_equal 'logs.google.com', host1[:host]
277
- assert_equal 9200, host1[:port]
278
- assert_equal 'http', host1[:scheme]
279
- assert_equal 'j%2Bhn', host1[:user]
280
- assert_equal 'd%40e', host1[:password]
281
- assert_equal nil, host1[:path]
282
- end
283
-
284
- def test_content_type_header
285
- stub_request(:head, "http://localhost:9200/").
286
- to_return(:status => 200, :body => "", :headers => {})
287
- if Elasticsearch::VERSION >= "6.0.2"
288
- elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
289
- with(headers: { "Content-Type" => "application/x-ndjson" })
290
- else
291
- elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
292
- with(headers: { "Content-Type" => "application/json" })
293
- end
294
- driver.run(default_tag: 'test') do
295
- driver.feed(sample_record)
296
- end
297
- assert_requested(elastic_request)
298
- end
299
-
300
- def test_writes_to_default_index
301
- stub_elastic
302
- driver.run(default_tag: 'test') do
303
- driver.feed(sample_record)
304
- end
305
- assert_equal('fluentd', index_cmds.first['index']['_index'])
306
- end
307
-
308
- def test_writes_to_default_type
309
- stub_elastic
310
- driver.run(default_tag: 'test') do
311
- driver.feed(sample_record)
312
- end
313
- assert_equal(default_type_name, index_cmds.first['index']['_type'])
314
- end
315
-
316
- def test_writes_to_specified_index
317
- driver.configure("index_name myindex\n")
318
- stub_elastic
319
- driver.run(default_tag: 'test') do
320
- driver.feed(sample_record)
321
- end
322
- assert_equal('myindex', index_cmds.first['index']['_index'])
323
- end
324
-
325
- def test_writes_to_specified_index_uppercase
326
- driver.configure("index_name MyIndex\n")
327
- stub_elastic
328
- driver.run(default_tag: 'test') do
329
- driver.feed(sample_record)
330
- end
331
- assert_equal('myindex', index_cmds.first['index']['_index'])
332
- end
333
-
334
- def test_writes_to_specified_type
335
- driver.configure("type_name mytype\n")
336
- stub_elastic
337
- driver.run(default_tag: 'test') do
338
- driver.feed(sample_record)
339
- end
340
- assert_equal('mytype', index_cmds.first['index']['_type'])
341
- end
342
-
343
- def test_writes_to_specified_host
344
- driver.configure("host 192.168.33.50\n")
345
- elastic_request = stub_elastic("http://192.168.33.50:9200/_bulk")
346
- driver.run(default_tag: 'test') do
347
- driver.feed(sample_record)
348
- end
349
- assert_requested(elastic_request)
350
- end
351
-
352
- def test_writes_to_specified_port
353
- driver.configure("port 9201\n")
354
- elastic_request = stub_elastic("http://localhost:9201/_bulk")
355
- driver.run(default_tag: 'test') do
356
- driver.feed(sample_record)
357
- end
358
- assert_requested(elastic_request)
359
- end
360
-
361
- def test_writes_to_multi_hosts
362
- hosts = [['192.168.33.50', 9201], ['192.168.33.51', 9201], ['192.168.33.52', 9201]]
363
- hosts_string = hosts.map {|x| "#{x[0]}:#{x[1]}"}.compact.join(',')
364
-
365
- driver.configure("hosts #{hosts_string}")
366
-
367
- hosts.each do |host_info|
368
- host, port = host_info
369
- stub_elastic_with_store_index_command_counts("http://#{host}:#{port}/_bulk")
370
- end
371
-
372
- driver.run(default_tag: 'test') do
373
- 1000.times do
374
- driver.feed(sample_record.merge('age'=>rand(100)))
375
- end
376
- end
377
- # @note: we cannot make multi chunks with options (flush_interval, buffer_chunk_limit)
378
- # it's Fluentd test driver's constraint
379
- # so @index_command_counts.size is always 1
380
-
381
- assert(@index_command_counts.size > 0, "not working with hosts options")
382
-
383
- total = 0
384
- @index_command_counts.each do |url, count|
385
- total += count
386
- end
387
- assert_equal(2000, total)
388
- end
389
-
390
- def test_makes_bulk_request
391
- stub_elastic
392
- driver.run(default_tag: 'test') do
393
- driver.feed(sample_record)
394
- driver.feed(sample_record.merge('age' => 27))
395
- end
396
- assert_equal(4, index_cmds.count)
397
- end
398
-
399
- def test_all_records_are_preserved_in_bulk
400
- stub_elastic
401
- driver.run(default_tag: 'test') do
402
- driver.feed(sample_record)
403
- driver.feed(sample_record.merge('age' => 27))
404
- end
405
- assert_equal(26, index_cmds[1]['age'])
406
- assert_equal(27, index_cmds[3]['age'])
407
- end
408
-
409
- def test_writes_to_logstash_index
410
- driver.configure("logstash_format true\n")
411
- time = Time.parse Date.today.iso8601
412
- logstash_index = "logstash-#{time.getutc.strftime("%Y.%m.%d")}"
413
- stub_elastic
414
- driver.run(default_tag: 'test') do
415
- driver.feed(time.to_i, sample_record)
416
- end
417
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
418
- end
419
-
420
- def test_writes_to_logstash_utc_index
421
- driver.configure("logstash_format true
422
- utc_index false")
423
- time = Time.parse Date.today.iso8601
424
- utc_index = "logstash-#{time.strftime("%Y.%m.%d")}"
425
- stub_elastic
426
- driver.run(default_tag: 'test') do
427
- driver.feed(time.to_i, sample_record)
428
- end
429
- assert_equal(utc_index, index_cmds.first['index']['_index'])
430
- end
431
-
432
- def test_writes_to_logstash_index_with_specified_prefix
433
- driver.configure("logstash_format true
434
- logstash_prefix myprefix")
435
- time = Time.parse Date.today.iso8601
436
- logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
437
- stub_elastic
438
- driver.run(default_tag: 'test') do
439
- driver.feed(time.to_i, sample_record)
440
- end
441
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
442
- end
443
-
444
- def test_writes_to_logstash_index_with_specified_prefix_and_separator
445
- separator = '_'
446
- driver.configure("logstash_format true
447
- logstash_prefix_separator #{separator}
448
- logstash_prefix myprefix")
449
- time = Time.parse Date.today.iso8601
450
- logstash_index = "myprefix#{separator}#{time.getutc.strftime("%Y.%m.%d")}"
451
- stub_elastic
452
- driver.run(default_tag: 'test') do
453
- driver.feed(time.to_i, sample_record)
454
- end
455
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
456
- end
457
-
458
- def test_writes_to_logstash_index_with_specified_prefix_uppercase
459
- driver.configure("logstash_format true
460
- logstash_prefix MyPrefix")
461
- time = Time.parse Date.today.iso8601
462
- logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
463
- stub_elastic
464
- driver.run(default_tag: 'test') do
465
- driver.feed(time.to_i, sample_record)
466
- end
467
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
468
- end
469
-
470
- def test_writes_to_logstash_index_with_specified_dateformat
471
- driver.configure("logstash_format true
472
- logstash_dateformat %Y.%m")
473
- time = Time.parse Date.today.iso8601
474
- logstash_index = "logstash-#{time.getutc.strftime("%Y.%m")}"
475
- stub_elastic
476
- driver.run(default_tag: 'test') do
477
- driver.feed(time.to_i, sample_record)
478
- end
479
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
480
- end
481
-
482
- def test_writes_to_logstash_index_with_specified_prefix_and_dateformat
483
- driver.configure("logstash_format true
484
- logstash_prefix myprefix
485
- logstash_dateformat %Y.%m")
486
- time = Time.parse Date.today.iso8601
487
- logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m")}"
488
- stub_elastic
489
- driver.run(default_tag: 'test') do
490
- driver.feed(time.to_i, sample_record)
491
- end
492
- assert_equal(logstash_index, index_cmds.first['index']['_index'])
493
- end
494
-
495
- def test_doesnt_add_logstash_timestamp_by_default
496
- stub_elastic
497
- driver.run(default_tag: 'test') do
498
- driver.feed(sample_record)
499
- end
500
- assert_nil(index_cmds[1]['@timestamp'])
501
- end
502
-
503
- def test_adds_logstash_timestamp_when_configured
504
- driver.configure("logstash_format true\n")
505
- stub_elastic
506
- time = Fluent::EventTime.new(Time.now.to_i, 123456789)
507
- driver.run(default_tag: 'test') do
508
- driver.feed(time, sample_record)
509
- end
510
- assert(index_cmds[1].has_key? '@timestamp')
511
- assert_equal(index_cmds[1]['@timestamp'], Time.at(time).iso8601(9))
512
- end
513
-
514
- def test_uses_subsecond_precision_when_configured
515
- driver.configure("logstash_format true
516
- time_precision 3\n")
517
- stub_elastic
518
- time = Fluent::EventTime.new(Time.now.to_i, 123456789)
519
- driver.run(default_tag: 'test') do
520
- driver.feed(time, sample_record)
521
- end
522
- assert(index_cmds[1].has_key? '@timestamp')
523
- assert_equal(index_cmds[1]['@timestamp'], Time.at(time).iso8601(3))
524
- end
525
-
526
- def test_uses_custom_timestamp_when_included_in_record
527
- driver.configure("include_timestamp true\n")
528
- stub_elastic
529
- ts = DateTime.new(2001,2,3).iso8601
530
- driver.run(default_tag: 'test') do
531
- driver.feed(sample_record.merge!('@timestamp' => ts))
532
- end
533
- assert(index_cmds[1].has_key? '@timestamp')
534
- assert_equal(index_cmds[1]['@timestamp'], ts)
535
- end
536
-
537
- def test_uses_custom_timestamp_when_included_in_record_logstash
538
- driver.configure("logstash_format true\n")
539
- stub_elastic
540
- ts = DateTime.new(2001,2,3).iso8601
541
- driver.run(default_tag: 'test') do
542
- driver.feed(sample_record.merge!('@timestamp' => ts))
543
- end
544
- assert(index_cmds[1].has_key? '@timestamp')
545
- assert_equal(index_cmds[1]['@timestamp'], ts)
546
- end
547
-
548
- def test_uses_custom_time_key_logstash
549
- driver.configure("logstash_format true
550
- time_key vtm\n")
551
- stub_elastic
552
- ts = DateTime.new(2001,2,3).iso8601
553
- driver.run(default_tag: 'test') do
554
- driver.feed(sample_record.merge!('vtm' => ts))
555
- end
556
- assert(index_cmds[1].has_key? '@timestamp')
557
- assert_equal(index_cmds[1]['@timestamp'], ts)
558
- end
559
-
560
- def test_uses_custom_time_key_timestamp
561
- driver.configure("include_timestamp true
562
- time_key vtm\n")
563
- stub_elastic
564
- ts = DateTime.new(2001,2,3).iso8601
565
- driver.run(default_tag: 'test') do
566
- driver.feed(sample_record.merge!('vtm' => ts))
567
- end
568
- assert(index_cmds[1].has_key? '@timestamp')
569
- assert_equal(index_cmds[1]['@timestamp'], ts)
570
- end
571
-
572
- def test_uses_custom_time_key_timestamp_custom_index
573
- driver.configure("include_timestamp true
574
- index_name test
575
- time_key vtm\n")
576
- stub_elastic
577
- ts = DateTime.new(2001,2,3).iso8601
578
- driver.run(default_tag: 'test') do
579
- driver.feed(sample_record.merge!('vtm' => ts))
580
- end
581
- assert(index_cmds[1].has_key? '@timestamp')
582
- assert_equal(index_cmds[1]['@timestamp'], ts)
583
- assert_equal('test', index_cmds.first['index']['_index'])
584
- end
585
-
586
- def test_uses_custom_time_key_exclude_timestamp
587
- driver.configure("include_timestamp true
588
- time_key vtm
589
- time_key_exclude_timestamp true\n")
590
- stub_elastic
591
- ts = DateTime.new(2001,2,3).iso8601
592
- driver.run(default_tag: 'test') do
593
- driver.feed(sample_record.merge!('vtm' => ts))
594
- end
595
- assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be missing')
596
- end
597
-
598
- def test_uses_custom_time_key_exclude_timestamp_logstash
599
- driver.configure("logstash_format true
600
- time_key vtm
601
- time_key_exclude_timestamp true\n")
602
- stub_elastic
603
- ts = DateTime.new(2001,2,3).iso8601
604
- driver.run(default_tag: 'test') do
605
- driver.feed(sample_record.merge!('vtm' => ts))
606
- end
607
- assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be missing')
608
- end
609
-
610
- def test_doesnt_add_tag_key_by_default
611
- stub_elastic
612
- driver.run(default_tag: 'test') do
613
- driver.feed(sample_record)
614
- end
615
- assert_nil(index_cmds[1]['tag'])
616
- end
617
-
618
- def test_adds_tag_key_when_configured
619
- driver.configure("include_tag_key true\n")
620
- stub_elastic
621
- driver.run(default_tag: 'mytag') do
622
- driver.feed(sample_record)
623
- end
624
- assert(index_cmds[1].has_key?('tag'))
625
- assert_equal(index_cmds[1]['tag'], 'mytag')
626
- end
627
-
628
- def test_adds_id_key_when_configured
629
- driver.configure("id_key request_id\n")
630
- stub_elastic
631
- driver.run(default_tag: 'test') do
632
- driver.feed(sample_record)
633
- end
634
- assert_equal(index_cmds[0]['index']['_id'], '42')
635
- end
636
-
637
- class NestedIdKeyTest < self
638
- def test_adds_nested_id_key_with_dot
639
- driver.configure("id_key nested.request_id\n")
640
- stub_elastic
641
- driver.run(default_tag: 'test') do
642
- driver.feed(nested_sample_record)
643
- end
644
- assert_equal(index_cmds[0]['index']['_id'], '42')
645
- end
646
-
647
- def test_adds_nested_id_key_with_dollar_dot
648
- driver.configure("id_key $.nested.request_id\n")
649
- stub_elastic
650
- driver.run(default_tag: 'test') do
651
- driver.feed(nested_sample_record)
652
- end
653
- assert_equal(index_cmds[0]['index']['_id'], '42')
654
- end
655
-
656
- def test_adds_nested_id_key_with_bracket
657
- driver.configure("id_key $['nested']['request_id']\n")
658
- stub_elastic
659
- driver.run(default_tag: 'test') do
660
- driver.feed(nested_sample_record)
661
- end
662
- assert_equal(index_cmds[0]['index']['_id'], '42')
663
- end
664
- end
665
-
666
- def test_doesnt_add_id_key_if_missing_when_configured
667
- driver.configure("id_key another_request_id\n")
668
- stub_elastic
669
- driver.run(default_tag: 'test') do
670
- driver.feed(sample_record)
671
- end
672
- assert(!index_cmds[0]['index'].has_key?('_id'))
673
- end
674
-
675
- def test_adds_id_key_when_not_configured
676
- stub_elastic
677
- driver.run(default_tag: 'test') do
678
- driver.feed(sample_record)
679
- end
680
- assert(!index_cmds[0]['index'].has_key?('_id'))
681
- end
682
-
683
- def test_adds_parent_key_when_configured
684
- driver.configure("parent_key parent_id\n")
685
- stub_elastic
686
- driver.run(default_tag: 'test') do
687
- driver.feed(sample_record)
688
- end
689
- assert_equal(index_cmds[0]['index']['_parent'], 'parent')
690
- end
691
-
692
- class NestedParentKeyTest < self
693
- def test_adds_nested_parent_key_with_dot
694
- driver.configure("parent_key nested.parent_id\n")
695
- stub_elastic
696
- driver.run(default_tag: 'test') do
697
- driver.feed(nested_sample_record)
698
- end
699
- assert_equal(index_cmds[0]['index']['_parent'], 'parent')
700
- end
701
-
702
- def test_adds_nested_parent_key_with_dollar_dot
703
- driver.configure("parent_key $.nested.parent_id\n")
704
- stub_elastic
705
- driver.run(default_tag: 'test') do
706
- driver.feed(nested_sample_record)
707
- end
708
- assert_equal(index_cmds[0]['index']['_parent'], 'parent')
709
- end
710
-
711
- def test_adds_nested_parent_key_with_bracket
712
- driver.configure("parent_key $['nested']['parent_id']\n")
713
- stub_elastic
714
- driver.run(default_tag: 'test') do
715
- driver.feed(nested_sample_record)
716
- end
717
- assert_equal(index_cmds[0]['index']['_parent'], 'parent')
718
- end
719
- end
720
-
721
- def test_doesnt_add_parent_key_if_missing_when_configured
722
- driver.configure("parent_key another_parent_id\n")
723
- stub_elastic
724
- driver.run(default_tag: 'test') do
725
- driver.feed(sample_record)
726
- end
727
- assert(!index_cmds[0]['index'].has_key?('_parent'))
728
- end
729
-
730
- def test_adds_parent_key_when_not_configured
731
- stub_elastic
732
- driver.run(default_tag: 'test') do
733
- driver.feed(sample_record)
734
- end
735
- assert(!index_cmds[0]['index'].has_key?('_parent'))
736
- end
737
-
738
- class AddsRoutingKeyWhenConfiguredTest < self
739
- def test_es6
740
- driver("routing_key routing_id\n", 6)
741
- stub_elastic
742
- driver.run(default_tag: 'test') do
743
- driver.feed(sample_record)
744
- end
745
- assert_equal(index_cmds[0]['index']['_routing'], 'routing')
746
- end
747
-
748
- def test_es7
749
- driver("routing_key routing_id\n", 7)
750
- stub_elastic
751
- driver.run(default_tag: 'test') do
752
- driver.feed(sample_record)
753
- end
754
- assert_equal(index_cmds[0]['index']['routing'], 'routing')
755
- end
756
- end
757
-
758
- class NestedRoutingKeyTest < self
759
- def test_adds_nested_routing_key_with_dot
760
- driver.configure("routing_key nested.routing_id\n")
761
- stub_elastic
762
- driver.run(default_tag: 'test') do
763
- driver.feed(nested_sample_record)
764
- end
765
- assert_equal(index_cmds[0]['index']['_routing'], 'routing')
766
- end
767
-
768
- def test_adds_nested_routing_key_with_dollar_dot
769
- driver.configure("routing_key $.nested.routing_id\n")
770
- stub_elastic
771
- driver.run(default_tag: 'test') do
772
- driver.feed(nested_sample_record)
773
- end
774
- assert_equal(index_cmds[0]['index']['_routing'], 'routing')
775
- end
776
-
777
- def test_adds_nested_routing_key_with_bracket
778
- driver.configure("routing_key $['nested']['routing_id']\n")
779
- stub_elastic
780
- driver.run(default_tag: 'test') do
781
- driver.feed(nested_sample_record)
782
- end
783
- assert_equal(index_cmds[0]['index']['_routing'], 'routing')
784
- end
785
- end
786
-
787
- def test_doesnt_add_routing_key_if_missing_when_configured
788
- driver.configure("routing_key another_routing_id\n")
789
- stub_elastic
790
- driver.run(default_tag: 'test') do
791
- driver.feed(sample_record)
792
- end
793
- assert(!index_cmds[0]['index'].has_key?('_routing'))
794
- end
795
-
796
- def test_adds_routing_key_when_not_configured
797
- stub_elastic
798
- driver.run(default_tag: 'test') do
799
- driver.feed(sample_record)
800
- end
801
- assert(!index_cmds[0]['index'].has_key?('_routing'))
802
- end
803
-
804
- def test_remove_one_key
805
- driver.configure("remove_keys key1\n")
806
- stub_elastic
807
- driver.run(default_tag: 'test') do
808
- driver.feed(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
809
- end
810
- assert(!index_cmds[1].has_key?('key1'))
811
- assert(index_cmds[1].has_key?('key2'))
812
- end
813
-
814
- def test_remove_multi_keys
815
- driver.configure("remove_keys key1, key2\n")
816
- stub_elastic
817
- driver.run(default_tag: 'test') do
818
- driver.feed(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
819
- end
820
- assert(!index_cmds[1].has_key?('key1'))
821
- assert(!index_cmds[1].has_key?('key2'))
822
- end
823
-
824
- def test_request_error
825
- stub_elastic_unavailable
826
- assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
827
- driver.run(default_tag: 'test', shutdown: false) do
828
- driver.feed(sample_record)
829
- end
830
- }
831
- end
832
-
833
- def test_request_forever
834
- omit("retry_forever test is unstable.") if ENV["CI"]
835
-
836
- stub_elastic
837
- driver.configure(Fluent::Config::Element.new(
838
- 'ROOT', '', {
839
- '@type' => 'elasticsearch',
840
- }, [
841
- Fluent::Config::Element.new('buffer', '', {
842
- 'retry_forever' => true
843
- }, [])
844
- ]
845
- ))
846
- stub_elastic_timeout
847
- assert_raise(Timeout::Error) {
848
- driver.run(default_tag: 'test', timeout: 10, force_flush_retry: true) do
849
- driver.feed(sample_record)
850
- end
851
- }
852
- end
853
-
854
- def test_tag_parts_index_error_event
855
- stub_elastic
856
- driver.configure("logstash_prefix ${tag_parts[1]}\n")
857
- flexmock(driver.instance.router).should_receive(:emit_error_event)
858
- .with('test', Fluent::EventTime, Hash, TypeError).once
859
- driver.run(default_tag: 'test') do
860
- driver.feed(sample_record)
861
- end
862
- end
863
-
864
- def test_connection_failed
865
- connection_resets = 0
866
-
867
- stub_request(:post, "http://localhost:9200/_bulk").with do |req|
868
- connection_resets += 1
869
- raise Faraday::ConnectionFailed, "Test message"
870
- end
871
-
872
- assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
873
- driver.run(default_tag: 'test', shutdown: false) do
874
- driver.feed(sample_record)
875
- end
876
- }
877
- assert_equal(connection_resets, 1)
878
- end
879
-
880
- def test_reconnect_on_error_enabled
881
- connection_resets = 0
882
-
883
- stub_request(:post, "http://localhost:9200/_bulk").with do |req|
884
- connection_resets += 1
885
- raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
886
- end
887
-
888
- driver.configure("reconnect_on_error true\n")
889
-
890
- assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
891
- driver.run(default_tag: 'test', shutdown: false) do
892
- driver.feed(sample_record)
893
- end
894
- }
895
-
896
- assert_raise(Timeout::Error) {
897
- driver.run(default_tag: 'test', shutdown: false) do
898
- driver.feed(sample_record)
899
- end
900
- }
901
- # FIXME: Consider keywords arguments in #run and how to test this later.
902
- # Because v0.14 test driver does not have 1 to 1 correspondence between #run and #flush in tests.
903
- assert_equal(connection_resets, 1)
904
- end
905
-
906
- def test_reconnect_on_error_disabled
907
- connection_resets = 0
908
-
909
- stub_request(:post, "http://localhost:9200/_bulk").with do |req|
910
- connection_resets += 1
911
- raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
912
- end
913
-
914
- driver.configure("reconnect_on_error false\n")
915
-
916
- assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
917
- driver.run(default_tag: 'test', shutdown: false) do
918
- driver.feed(sample_record)
919
- end
920
- }
921
-
922
- assert_raise(Timeout::Error) {
923
- driver.run(default_tag: 'test', shutdown: false) do
924
- driver.feed(sample_record)
925
- end
926
- }
927
- assert_equal(connection_resets, 1)
928
- end
929
-
930
- def test_update_should_not_write_if_theres_no_id
931
- driver.configure("write_operation update\n")
932
- stub_elastic
933
- driver.run(default_tag: 'test') do
934
- driver.feed(sample_record)
935
- end
936
- assert_nil(index_cmds)
937
- end
938
-
939
- def test_upsert_should_not_write_if_theres_no_id
940
- driver.configure("write_operation upsert\n")
941
- stub_elastic
942
- driver.run(default_tag: 'test') do
943
- driver.feed(sample_record)
944
- end
945
- assert_nil(index_cmds)
946
- end
947
-
948
- def test_create_should_not_write_if_theres_no_id
949
- driver.configure("write_operation create\n")
950
- stub_elastic
951
- driver.run(default_tag: 'test') do
952
- driver.feed(sample_record)
953
- end
954
- assert_nil(index_cmds)
955
- end
956
-
957
- def test_update_should_write_update_op_and_doc_as_upsert_is_false
958
- driver.configure("write_operation update
959
- id_key request_id")
960
- stub_elastic
961
- driver.run(default_tag: 'test') do
962
- driver.feed(sample_record)
963
- end
964
- assert(index_cmds[0].has_key?("update"))
965
- assert(!index_cmds[1]["doc_as_upsert"])
966
- end
967
-
968
- def test_upsert_should_write_update_op_and_doc_as_upsert_is_true
969
- driver.configure("write_operation upsert
970
- id_key request_id")
971
- stub_elastic
972
- driver.run(default_tag: 'test') do
973
- driver.feed(sample_record)
974
- end
975
- assert(index_cmds[0].has_key?("update"))
976
- assert(index_cmds[1]["doc_as_upsert"])
977
- end
978
-
979
- def test_create_should_write_create_op
980
- driver.configure("write_operation create
981
- id_key request_id")
982
- stub_elastic
983
- driver.run(default_tag: 'test') do
984
- driver.feed(sample_record)
985
- end
986
- assert(index_cmds[0].has_key?("create"))
987
- end
988
-
989
- def test_include_index_in_url
990
- stub_elastic('http://localhost:9200/logstash-2018.01.01/_bulk')
991
-
992
- driver.configure("index_name logstash-2018.01.01
993
- include_index_in_url true")
994
- driver.run(default_tag: 'test') do
995
- driver.feed(sample_record)
996
- end
997
-
998
- assert_equal(index_cmds.length, 2)
999
- assert_equal(index_cmds.first['index']['_index'], nil)
1000
- end
1001
- end
1
+ require 'helper'
2
+ require 'date'
3
+ require 'fluent/test/helpers'
4
+ require 'fluent/test/driver/output'
5
+ require 'flexmock/test_unit'
6
+
7
+ class ElasticsearchOutputDynamic < Test::Unit::TestCase
8
+ include FlexMock::TestCase
9
+ include Fluent::Test::Helpers
10
+
11
+ attr_accessor :index_cmds, :index_command_counts
12
+
13
+ def setup
14
+ Fluent::Test.setup
15
+ require 'fluent/plugin/out_elasticsearch_dynamic'
16
+ @driver = nil
17
+ end
18
+
19
+ def driver(conf='', es_version=5)
20
+ # For request stub to detect compatibility.
21
+ @es_version ||= es_version
22
+ Fluent::Plugin::ElasticsearchOutputDynamic.module_eval(<<-CODE)
23
+ def detect_es_major_version
24
+ #{@es_version}
25
+ end
26
+ CODE
27
+ @driver ||= Fluent::Test::Driver::Output.new(Fluent::Plugin::ElasticsearchOutputDynamic) {
28
+ # v0.12's test driver assume format definition. This simulates ObjectBufferedOutput format
29
+ if !defined?(Fluent::Plugin::Output)
30
+ def format(tag, time, record)
31
+ [time, record].to_msgpack
32
+ end
33
+ end
34
+ }.configure(conf)
35
+ end
36
+
37
+ def default_type_name
38
+ Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME
39
+ end
40
+
41
+ def sample_record
42
+ {'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
43
+ end
44
+
45
+ def nested_sample_record
46
+ {'nested' =>
47
+ {'age' => 26, 'parent_id' => 'parent', 'routing_id' => 'routing', 'request_id' => '42'}
48
+ }
49
+ end
50
+
51
+ def stub_elastic(url="http://localhost:9200/_bulk")
52
+ stub_request(:post, url).with do |req|
53
+ @index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
54
+ end
55
+ end
56
+
57
+ def stub_elastic_unavailable(url="http://localhost:9200/_bulk")
58
+ stub_request(:post, url).to_return(:status => [503, "Service Unavailable"])
59
+ end
60
+
61
+ def stub_elastic_timeout(url="http://localhost:9200/_bulk")
62
+ stub_request(:post, url).to_timeout
63
+ end
64
+
65
+ def stub_elastic_with_store_index_command_counts(url="http://localhost:9200/_bulk")
66
+ if @index_command_counts == nil
67
+ @index_command_counts = {}
68
+ @index_command_counts.default = 0
69
+ end
70
+
71
+ stub_request(:post, url).with do |req|
72
+ index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
73
+ @index_command_counts[url] += index_cmds.size
74
+ end
75
+ end
76
+
77
+ def assert_logs_include(logs, msg, exp_matches=1)
78
+ matches = logs.grep /#{msg}/
79
+ assert_equal(exp_matches, matches.length, "Logs do not contain '#{msg}' '#{logs}'")
80
+ end
81
+
82
+ def test_configure
83
+ config = %{
84
+ host logs.google.com
85
+ port 777
86
+ scheme https
87
+ path /es/
88
+ user john
89
+ password doe
90
+ }
91
+ instance = driver(config).instance
92
+
93
+ conf = instance.dynamic_config
94
+ assert_equal 'logs.google.com', conf['host']
95
+ assert_equal "777", conf['port']
96
+ assert_equal :https, instance.scheme
97
+ assert_equal 'john', instance.user
98
+ assert_equal 'doe', instance.password
99
+ assert_equal '/es/', instance.path
100
+ assert_equal :TLSv1, instance.ssl_version
101
+ assert_nil instance.client_key
102
+ assert_nil instance.client_cert
103
+ assert_nil instance.client_key_pass
104
+ assert_false instance.with_transporter_log
105
+ assert_equal :"application/json", instance.content_type
106
+ assert_equal :excon, instance.http_backend
107
+ end
108
+
109
+ test 'configure Content-Type' do
110
+ config = %{
111
+ content_type application/x-ndjson
112
+ }
113
+ instance = driver(config).instance
114
+ assert_equal :"application/x-ndjson", instance.content_type
115
+ end
116
+
117
+ test 'invalid Content-Type' do
118
+ config = %{
119
+ content_type nonexistent/invalid
120
+ }
121
+ assert_raise(Fluent::ConfigError) {
122
+ driver(config)
123
+ }
124
+ end
125
+
126
+ test 'Detected Elasticsearch 7' do
127
+ config = %{
128
+ type_name changed
129
+ }
130
+ instance = driver(config, 7).instance
131
+ assert_equal '_doc', instance.type_name
132
+ end
133
+
134
+ sub_test_case 'connection exceptions' do
135
+ test 'default connection exception' do
136
+ driver(Fluent::Config::Element.new(
137
+ 'ROOT', '', {
138
+ '@type' => 'elasticsearch',
139
+ 'host' => 'log.google.com',
140
+ 'port' => 777,
141
+ 'scheme' => 'https',
142
+ 'path' => '/es/',
143
+ 'user' => 'john',
144
+ 'pasword' => 'doe',
145
+ }, [
146
+ Fluent::Config::Element.new('buffer', 'tag', {
147
+ }, [])
148
+ ]
149
+ ))
150
+ logs = driver.logs
151
+ assert_logs_include(logs, /you should specify 2 or more 'flush_thread_count'/, 1)
152
+ end
153
+ end
154
+
155
+ def test_defaults
156
+ config = %{
157
+ host logs.google.com
158
+ scheme https
159
+ path /es/
160
+ user john
161
+ password doe
162
+ }
163
+ instance = driver(config).instance
164
+
165
+ conf = instance.dynamic_config
166
+ assert_equal "9200", conf['port']
167
+ assert_equal "false", conf['logstash_format']
168
+ assert_equal "true", conf['utc_index']
169
+ assert_equal false, instance.time_key_exclude_timestamp
170
+ end
171
+
172
+ def test_legacy_hosts_list
173
+ config = %{
174
+ hosts host1:50,host2:100,host3
175
+ scheme https
176
+ path /es/
177
+ port 123
178
+ }
179
+ instance = driver(config).instance
180
+
181
+ assert_equal 3, instance.get_connection_options(nil)[:hosts].length
182
+ host1, host2, host3 = instance.get_connection_options(nil)[:hosts]
183
+
184
+ assert_equal 'host1', host1[:host]
185
+ assert_equal 50, host1[:port]
186
+ assert_equal 'https', host1[:scheme]
187
+ assert_equal '/es/', host2[:path]
188
+ assert_equal 'host3', host3[:host]
189
+ assert_equal 123, host3[:port]
190
+ assert_equal 'https', host3[:scheme]
191
+ assert_equal '/es/', host3[:path]
192
+ end
193
+
194
+ def test_hosts_list
195
+ config = %{
196
+ hosts https://john:password@host1:443/elastic/,http://host2
197
+ path /default_path
198
+ user default_user
199
+ password default_password
200
+ }
201
+ instance = driver(config).instance
202
+
203
+ assert_equal 2, instance.get_connection_options(nil)[:hosts].length
204
+ host1, host2 = instance.get_connection_options(nil)[:hosts]
205
+
206
+ assert_equal 'host1', host1[:host]
207
+ assert_equal 443, host1[:port]
208
+ assert_equal 'https', host1[:scheme]
209
+ assert_equal 'john', host1[:user]
210
+ assert_equal 'password', host1[:password]
211
+ assert_equal '/elastic/', host1[:path]
212
+
213
+ assert_equal 'host2', host2[:host]
214
+ assert_equal 'http', host2[:scheme]
215
+ assert_equal 'default_user', host2[:user]
216
+ assert_equal 'default_password', host2[:password]
217
+ assert_equal '/default_path', host2[:path]
218
+ end
219
+
220
+ def test_hosts_list_with_escape_placeholders
221
+ config = %{
222
+ hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
223
+ path /default_path
224
+ user default_user
225
+ password default_password
226
+ }
227
+ instance = driver(config).instance
228
+
229
+ assert_equal 2, instance.get_connection_options(nil)[:hosts].length
230
+ host1, host2 = instance.get_connection_options(nil)[:hosts]
231
+
232
+ assert_equal 'host1', host1[:host]
233
+ assert_equal 443, host1[:port]
234
+ assert_equal 'https', host1[:scheme]
235
+ assert_equal 'j%2Bhn', host1[:user]
236
+ assert_equal 'passw%40rd', host1[:password]
237
+ assert_equal '/elastic/', host1[:path]
238
+
239
+ assert_equal 'host2', host2[:host]
240
+ assert_equal 'http', host2[:scheme]
241
+ assert_equal 'default_user', host2[:user]
242
+ assert_equal 'default_password', host2[:password]
243
+ assert_equal '/default_path', host2[:path]
244
+ end
245
+
246
+ def test_single_host_params_and_defaults
247
+ config = %{
248
+ host logs.google.com
249
+ user john
250
+ password doe
251
+ }
252
+ instance = driver(config).instance
253
+
254
+ assert_equal 1, instance.get_connection_options(nil)[:hosts].length
255
+ host1 = instance.get_connection_options(nil)[:hosts][0]
256
+
257
+ assert_equal 'logs.google.com', host1[:host]
258
+ assert_equal 9200, host1[:port]
259
+ assert_equal 'http', host1[:scheme]
260
+ assert_equal 'john', host1[:user]
261
+ assert_equal 'doe', host1[:password]
262
+ assert_equal nil, host1[:path]
263
+ end
264
+
265
+ def test_single_host_params_and_defaults_with_escape_placeholders
266
+ config = %{
267
+ host logs.google.com
268
+ user %{j+hn}
269
+ password %{d@e}
270
+ }
271
+ instance = driver(config).instance
272
+
273
+ assert_equal 1, instance.get_connection_options(nil)[:hosts].length
274
+ host1 = instance.get_connection_options(nil)[:hosts][0]
275
+
276
+ assert_equal 'logs.google.com', host1[:host]
277
+ assert_equal 9200, host1[:port]
278
+ assert_equal 'http', host1[:scheme]
279
+ assert_equal 'j%2Bhn', host1[:user]
280
+ assert_equal 'd%40e', host1[:password]
281
+ assert_equal nil, host1[:path]
282
+ end
283
+
284
+ def test_content_type_header
285
+ stub_request(:head, "http://localhost:9200/").
286
+ to_return(:status => 200, :body => "", :headers => {})
287
+ if Elasticsearch::VERSION >= "6.0.2"
288
+ elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
289
+ with(headers: { "Content-Type" => "application/x-ndjson" })
290
+ else
291
+ elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
292
+ with(headers: { "Content-Type" => "application/json" })
293
+ end
294
+ driver.run(default_tag: 'test') do
295
+ driver.feed(sample_record)
296
+ end
297
+ assert_requested(elastic_request)
298
+ end
299
+
300
+ def test_writes_to_default_index
301
+ stub_elastic
302
+ driver.run(default_tag: 'test') do
303
+ driver.feed(sample_record)
304
+ end
305
+ assert_equal('fluentd', index_cmds.first['index']['_index'])
306
+ end
307
+
308
+ def test_writes_to_default_type
309
+ stub_elastic
310
+ driver.run(default_tag: 'test') do
311
+ driver.feed(sample_record)
312
+ end
313
+ assert_equal(default_type_name, index_cmds.first['index']['_type'])
314
+ end
315
+
316
+ def test_writes_to_specified_index
317
+ driver.configure("index_name myindex\n")
318
+ stub_elastic
319
+ driver.run(default_tag: 'test') do
320
+ driver.feed(sample_record)
321
+ end
322
+ assert_equal('myindex', index_cmds.first['index']['_index'])
323
+ end
324
+
325
+ def test_writes_to_specified_index_uppercase
326
+ driver.configure("index_name MyIndex\n")
327
+ stub_elastic
328
+ driver.run(default_tag: 'test') do
329
+ driver.feed(sample_record)
330
+ end
331
+ assert_equal('myindex', index_cmds.first['index']['_index'])
332
+ end
333
+
334
+ def test_writes_to_specified_type
335
+ driver.configure("type_name mytype\n")
336
+ stub_elastic
337
+ driver.run(default_tag: 'test') do
338
+ driver.feed(sample_record)
339
+ end
340
+ assert_equal('mytype', index_cmds.first['index']['_type'])
341
+ end
342
+
343
+ def test_writes_to_specified_host
344
+ driver.configure("host 192.168.33.50\n")
345
+ elastic_request = stub_elastic("http://192.168.33.50:9200/_bulk")
346
+ driver.run(default_tag: 'test') do
347
+ driver.feed(sample_record)
348
+ end
349
+ assert_requested(elastic_request)
350
+ end
351
+
352
+ def test_writes_to_specified_port
353
+ driver.configure("port 9201\n")
354
+ elastic_request = stub_elastic("http://localhost:9201/_bulk")
355
+ driver.run(default_tag: 'test') do
356
+ driver.feed(sample_record)
357
+ end
358
+ assert_requested(elastic_request)
359
+ end
360
+
361
+ def test_writes_to_multi_hosts
362
+ hosts = [['192.168.33.50', 9201], ['192.168.33.51', 9201], ['192.168.33.52', 9201]]
363
+ hosts_string = hosts.map {|x| "#{x[0]}:#{x[1]}"}.compact.join(',')
364
+
365
+ driver.configure("hosts #{hosts_string}")
366
+
367
+ hosts.each do |host_info|
368
+ host, port = host_info
369
+ stub_elastic_with_store_index_command_counts("http://#{host}:#{port}/_bulk")
370
+ end
371
+
372
+ driver.run(default_tag: 'test') do
373
+ 1000.times do
374
+ driver.feed(sample_record.merge('age'=>rand(100)))
375
+ end
376
+ end
377
+ # @note: we cannot make multi chunks with options (flush_interval, buffer_chunk_limit)
378
+ # it's Fluentd test driver's constraint
379
+ # so @index_command_counts.size is always 1
380
+
381
+ assert(@index_command_counts.size > 0, "not working with hosts options")
382
+
383
+ total = 0
384
+ @index_command_counts.each do |url, count|
385
+ total += count
386
+ end
387
+ assert_equal(2000, total)
388
+ end
389
+
390
+ def test_makes_bulk_request
391
+ stub_elastic
392
+ driver.run(default_tag: 'test') do
393
+ driver.feed(sample_record)
394
+ driver.feed(sample_record.merge('age' => 27))
395
+ end
396
+ assert_equal(4, index_cmds.count)
397
+ end
398
+
399
+ def test_all_records_are_preserved_in_bulk
400
+ stub_elastic
401
+ driver.run(default_tag: 'test') do
402
+ driver.feed(sample_record)
403
+ driver.feed(sample_record.merge('age' => 27))
404
+ end
405
+ assert_equal(26, index_cmds[1]['age'])
406
+ assert_equal(27, index_cmds[3]['age'])
407
+ end
408
+
409
+ def test_writes_to_logstash_index
410
+ driver.configure("logstash_format true\n")
411
+ time = Time.parse Date.today.iso8601
412
+ logstash_index = "logstash-#{time.getutc.strftime("%Y.%m.%d")}"
413
+ stub_elastic
414
+ driver.run(default_tag: 'test') do
415
+ driver.feed(time.to_i, sample_record)
416
+ end
417
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
418
+ end
419
+
420
+ def test_writes_to_logstash_utc_index
421
+ driver.configure("logstash_format true
422
+ utc_index false")
423
+ time = Time.parse Date.today.iso8601
424
+ utc_index = "logstash-#{time.strftime("%Y.%m.%d")}"
425
+ stub_elastic
426
+ driver.run(default_tag: 'test') do
427
+ driver.feed(time.to_i, sample_record)
428
+ end
429
+ assert_equal(utc_index, index_cmds.first['index']['_index'])
430
+ end
431
+
432
+ def test_writes_to_logstash_index_with_specified_prefix
433
+ driver.configure("logstash_format true
434
+ logstash_prefix myprefix")
435
+ time = Time.parse Date.today.iso8601
436
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
437
+ stub_elastic
438
+ driver.run(default_tag: 'test') do
439
+ driver.feed(time.to_i, sample_record)
440
+ end
441
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
442
+ end
443
+
444
+ def test_writes_to_logstash_index_with_specified_prefix_and_separator
445
+ separator = '_'
446
+ driver.configure("logstash_format true
447
+ logstash_prefix_separator #{separator}
448
+ logstash_prefix myprefix")
449
+ time = Time.parse Date.today.iso8601
450
+ logstash_index = "myprefix#{separator}#{time.getutc.strftime("%Y.%m.%d")}"
451
+ stub_elastic
452
+ driver.run(default_tag: 'test') do
453
+ driver.feed(time.to_i, sample_record)
454
+ end
455
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
456
+ end
457
+
458
+ def test_writes_to_logstash_index_with_specified_prefix_uppercase
459
+ driver.configure("logstash_format true
460
+ logstash_prefix MyPrefix")
461
+ time = Time.parse Date.today.iso8601
462
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
463
+ stub_elastic
464
+ driver.run(default_tag: 'test') do
465
+ driver.feed(time.to_i, sample_record)
466
+ end
467
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
468
+ end
469
+
470
+ def test_writes_to_logstash_index_with_specified_dateformat
471
+ driver.configure("logstash_format true
472
+ logstash_dateformat %Y.%m")
473
+ time = Time.parse Date.today.iso8601
474
+ logstash_index = "logstash-#{time.getutc.strftime("%Y.%m")}"
475
+ stub_elastic
476
+ driver.run(default_tag: 'test') do
477
+ driver.feed(time.to_i, sample_record)
478
+ end
479
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
480
+ end
481
+
482
+ def test_writes_to_logstash_index_with_specified_prefix_and_dateformat
483
+ driver.configure("logstash_format true
484
+ logstash_prefix myprefix
485
+ logstash_dateformat %Y.%m")
486
+ time = Time.parse Date.today.iso8601
487
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m")}"
488
+ stub_elastic
489
+ driver.run(default_tag: 'test') do
490
+ driver.feed(time.to_i, sample_record)
491
+ end
492
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
493
+ end
494
+
495
+ def test_doesnt_add_logstash_timestamp_by_default
496
+ stub_elastic
497
+ driver.run(default_tag: 'test') do
498
+ driver.feed(sample_record)
499
+ end
500
+ assert_nil(index_cmds[1]['@timestamp'])
501
+ end
502
+
503
+ def test_adds_logstash_timestamp_when_configured
504
+ driver.configure("logstash_format true\n")
505
+ stub_elastic
506
+ time = Fluent::EventTime.new(Time.now.to_i, 123456789)
507
+ driver.run(default_tag: 'test') do
508
+ driver.feed(time, sample_record)
509
+ end
510
+ assert(index_cmds[1].has_key? '@timestamp')
511
+ assert_equal(Time.at(time).iso8601(9), index_cmds[1]['@timestamp'])
512
+ end
513
+
514
+ def test_uses_subsecond_precision_when_configured
515
+ driver.configure("logstash_format true
516
+ time_precision 3\n")
517
+ stub_elastic
518
+ time = Fluent::EventTime.new(Time.now.to_i, 123456789)
519
+ driver.run(default_tag: 'test') do
520
+ driver.feed(time, sample_record)
521
+ end
522
+ assert(index_cmds[1].has_key? '@timestamp')
523
+ assert_equal(Time.at(time).iso8601(3), index_cmds[1]['@timestamp'])
524
+ end
525
+
526
+ def test_uses_custom_timestamp_when_included_in_record
527
+ driver.configure("include_timestamp true\n")
528
+ stub_elastic
529
+ ts = DateTime.new(2001,2,3).iso8601
530
+ driver.run(default_tag: 'test') do
531
+ driver.feed(sample_record.merge!('@timestamp' => ts))
532
+ end
533
+ assert(index_cmds[1].has_key? '@timestamp')
534
+ assert_equal(ts, index_cmds[1]['@timestamp'])
535
+ end
536
+
537
+ def test_uses_custom_timestamp_when_included_in_record_logstash
538
+ driver.configure("logstash_format true\n")
539
+ stub_elastic
540
+ ts = DateTime.new(2001,2,3).iso8601
541
+ driver.run(default_tag: 'test') do
542
+ driver.feed(sample_record.merge!('@timestamp' => ts))
543
+ end
544
+ assert(index_cmds[1].has_key? '@timestamp')
545
+ assert_equal(ts, index_cmds[1]['@timestamp'])
546
+ end
547
+
548
+ def test_uses_custom_time_key_logstash
549
+ driver.configure("logstash_format true
550
+ time_key vtm\n")
551
+ stub_elastic
552
+ ts = DateTime.new(2001,2,3).iso8601
553
+ driver.run(default_tag: 'test') do
554
+ driver.feed(sample_record.merge!('vtm' => ts))
555
+ end
556
+ assert(index_cmds[1].has_key? '@timestamp')
557
+ assert_equal(ts, index_cmds[1]['@timestamp'])
558
+ end
559
+
560
+ def test_uses_custom_time_key_timestamp
561
+ driver.configure("include_timestamp true
562
+ time_key vtm\n")
563
+ stub_elastic
564
+ ts = DateTime.new(2001,2,3).iso8601
565
+ driver.run(default_tag: 'test') do
566
+ driver.feed(sample_record.merge!('vtm' => ts))
567
+ end
568
+ assert(index_cmds[1].has_key? '@timestamp')
569
+ assert_equal(ts, index_cmds[1]['@timestamp'])
570
+ end
571
+
572
+ def test_uses_custom_time_key_timestamp_custom_index
573
+ driver.configure("include_timestamp true
574
+ index_name test
575
+ time_key vtm\n")
576
+ stub_elastic
577
+ ts = DateTime.new(2001,2,3).iso8601
578
+ driver.run(default_tag: 'test') do
579
+ driver.feed(sample_record.merge!('vtm' => ts))
580
+ end
581
+ assert(index_cmds[1].has_key? '@timestamp')
582
+ assert_equal(ts, index_cmds[1]['@timestamp'])
583
+ assert_equal('test', index_cmds.first['index']['_index'])
584
+ end
585
+
586
+ def test_uses_custom_time_key_exclude_timestamp
587
+ driver.configure("include_timestamp true
588
+ time_key vtm
589
+ time_key_exclude_timestamp true\n")
590
+ stub_elastic
591
+ ts = DateTime.new(2001,2,3).iso8601
592
+ driver.run(default_tag: 'test') do
593
+ driver.feed(sample_record.merge!('vtm' => ts))
594
+ end
595
+ assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be missing')
596
+ end
597
+
598
+ def test_uses_custom_time_key_exclude_timestamp_logstash
599
+ driver.configure("logstash_format true
600
+ time_key vtm
601
+ time_key_exclude_timestamp true\n")
602
+ stub_elastic
603
+ ts = DateTime.new(2001,2,3).iso8601
604
+ driver.run(default_tag: 'test') do
605
+ driver.feed(sample_record.merge!('vtm' => ts))
606
+ end
607
+ assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be missing')
608
+ end
609
+
610
+ def test_doesnt_add_tag_key_by_default
611
+ stub_elastic
612
+ driver.run(default_tag: 'test') do
613
+ driver.feed(sample_record)
614
+ end
615
+ assert_nil(index_cmds[1]['tag'])
616
+ end
617
+
618
+ def test_adds_tag_key_when_configured
619
+ driver.configure("include_tag_key true\n")
620
+ stub_elastic
621
+ driver.run(default_tag: 'mytag') do
622
+ driver.feed(sample_record)
623
+ end
624
+ assert(index_cmds[1].has_key?('tag'))
625
+ assert_equal('mytag', index_cmds[1]['tag'])
626
+ end
627
+
628
+ def test_adds_id_key_when_configured
629
+ driver.configure("id_key request_id\n")
630
+ stub_elastic
631
+ driver.run(default_tag: 'test') do
632
+ driver.feed(sample_record)
633
+ end
634
+ assert_equal('42', index_cmds[0]['index']['_id'])
635
+ end
636
+
637
+ class NestedIdKeyTest < self
638
+ def test_adds_nested_id_key_with_dot
639
+ driver.configure("id_key nested.request_id\n")
640
+ stub_elastic
641
+ driver.run(default_tag: 'test') do
642
+ driver.feed(nested_sample_record)
643
+ end
644
+ assert_equal('42', index_cmds[0]['index']['_id'])
645
+ end
646
+
647
+ def test_adds_nested_id_key_with_dollar_dot
648
+ driver.configure("id_key $.nested.request_id\n")
649
+ stub_elastic
650
+ driver.run(default_tag: 'test') do
651
+ driver.feed(nested_sample_record)
652
+ end
653
+ assert_equal('42', index_cmds[0]['index']['_id'])
654
+ end
655
+
656
+ def test_adds_nested_id_key_with_bracket
657
+ driver.configure("id_key $['nested']['request_id']\n")
658
+ stub_elastic
659
+ driver.run(default_tag: 'test') do
660
+ driver.feed(nested_sample_record)
661
+ end
662
+ assert_equal('42', index_cmds[0]['index']['_id'])
663
+ end
664
+ end
665
+
666
+ def test_doesnt_add_id_key_if_missing_when_configured
667
+ driver.configure("id_key another_request_id\n")
668
+ stub_elastic
669
+ driver.run(default_tag: 'test') do
670
+ driver.feed(sample_record)
671
+ end
672
+ assert(!index_cmds[0]['index'].has_key?('_id'))
673
+ end
674
+
675
+ def test_adds_id_key_when_not_configured
676
+ stub_elastic
677
+ driver.run(default_tag: 'test') do
678
+ driver.feed(sample_record)
679
+ end
680
+ assert(!index_cmds[0]['index'].has_key?('_id'))
681
+ end
682
+
683
+ def test_adds_parent_key_when_configured
684
+ driver.configure("parent_key parent_id\n")
685
+ stub_elastic
686
+ driver.run(default_tag: 'test') do
687
+ driver.feed(sample_record)
688
+ end
689
+ assert_equal('parent', index_cmds[0]['index']['_parent'])
690
+ end
691
+
692
+ class NestedParentKeyTest < self
693
+ def test_adds_nested_parent_key_with_dot
694
+ driver.configure("parent_key nested.parent_id\n")
695
+ stub_elastic
696
+ driver.run(default_tag: 'test') do
697
+ driver.feed(nested_sample_record)
698
+ end
699
+ assert_equal('parent', index_cmds[0]['index']['_parent'])
700
+ end
701
+
702
+ def test_adds_nested_parent_key_with_dollar_dot
703
+ driver.configure("parent_key $.nested.parent_id\n")
704
+ stub_elastic
705
+ driver.run(default_tag: 'test') do
706
+ driver.feed(nested_sample_record)
707
+ end
708
+ assert_equal('parent', index_cmds[0]['index']['_parent'])
709
+ end
710
+
711
+ def test_adds_nested_parent_key_with_bracket
712
+ driver.configure("parent_key $['nested']['parent_id']\n")
713
+ stub_elastic
714
+ driver.run(default_tag: 'test') do
715
+ driver.feed(nested_sample_record)
716
+ end
717
+ assert_equal('parent', index_cmds[0]['index']['_parent'])
718
+ end
719
+ end
720
+
721
+ def test_doesnt_add_parent_key_if_missing_when_configured
722
+ driver.configure("parent_key another_parent_id\n")
723
+ stub_elastic
724
+ driver.run(default_tag: 'test') do
725
+ driver.feed(sample_record)
726
+ end
727
+ assert(!index_cmds[0]['index'].has_key?('_parent'))
728
+ end
729
+
730
+ def test_adds_parent_key_when_not_configured
731
+ stub_elastic
732
+ driver.run(default_tag: 'test') do
733
+ driver.feed(sample_record)
734
+ end
735
+ assert(!index_cmds[0]['index'].has_key?('_parent'))
736
+ end
737
+
738
+ class AddsRoutingKeyWhenConfiguredTest < self
739
+ def test_es6
740
+ driver("routing_key routing_id\n", 6)
741
+ stub_elastic
742
+ driver.run(default_tag: 'test') do
743
+ driver.feed(sample_record)
744
+ end
745
+ assert_equal('routing', index_cmds[0]['index']['_routing'])
746
+ end
747
+
748
+ def test_es7
749
+ driver("routing_key routing_id\n", 7)
750
+ stub_elastic
751
+ driver.run(default_tag: 'test') do
752
+ driver.feed(sample_record)
753
+ end
754
+ assert_equal('routing', index_cmds[0]['index']['routing'])
755
+ end
756
+ end
757
+
758
+ class NestedRoutingKeyTest < self
759
+ def test_adds_nested_routing_key_with_dot
760
+ driver.configure("routing_key nested.routing_id\n")
761
+ stub_elastic
762
+ driver.run(default_tag: 'test') do
763
+ driver.feed(nested_sample_record)
764
+ end
765
+ assert_equal('routing', index_cmds[0]['index']['_routing'])
766
+ end
767
+
768
+ def test_adds_nested_routing_key_with_dollar_dot
769
+ driver.configure("routing_key $.nested.routing_id\n")
770
+ stub_elastic
771
+ driver.run(default_tag: 'test') do
772
+ driver.feed(nested_sample_record)
773
+ end
774
+ assert_equal('routing', index_cmds[0]['index']['_routing'])
775
+ end
776
+
777
+ def test_adds_nested_routing_key_with_bracket
778
+ driver.configure("routing_key $['nested']['routing_id']\n")
779
+ stub_elastic
780
+ driver.run(default_tag: 'test') do
781
+ driver.feed(nested_sample_record)
782
+ end
783
+ assert_equal('routing', index_cmds[0]['index']['_routing'])
784
+ end
785
+ end
786
+
787
+ def test_doesnt_add_routing_key_if_missing_when_configured
788
+ driver.configure("routing_key another_routing_id\n")
789
+ stub_elastic
790
+ driver.run(default_tag: 'test') do
791
+ driver.feed(sample_record)
792
+ end
793
+ assert(!index_cmds[0]['index'].has_key?('_routing'))
794
+ end
795
+
796
+ def test_adds_routing_key_when_not_configured
797
+ stub_elastic
798
+ driver.run(default_tag: 'test') do
799
+ driver.feed(sample_record)
800
+ end
801
+ assert(!index_cmds[0]['index'].has_key?('_routing'))
802
+ end
803
+
804
+ def test_remove_one_key
805
+ driver.configure("remove_keys key1\n")
806
+ stub_elastic
807
+ driver.run(default_tag: 'test') do
808
+ driver.feed(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
809
+ end
810
+ assert(!index_cmds[1].has_key?('key1'))
811
+ assert(index_cmds[1].has_key?('key2'))
812
+ end
813
+
814
+ def test_remove_multi_keys
815
+ driver.configure("remove_keys key1, key2\n")
816
+ stub_elastic
817
+ driver.run(default_tag: 'test') do
818
+ driver.feed(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
819
+ end
820
+ assert(!index_cmds[1].has_key?('key1'))
821
+ assert(!index_cmds[1].has_key?('key2'))
822
+ end
823
+
824
+ def test_request_error
825
+ stub_elastic_unavailable
826
+ assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
827
+ driver.run(default_tag: 'test', shutdown: false) do
828
+ driver.feed(sample_record)
829
+ end
830
+ }
831
+ end
832
+
833
+ def test_request_forever
834
+ omit("retry_forever test is unstable.") if ENV["CI"]
835
+
836
+ stub_elastic
837
+ driver.configure(Fluent::Config::Element.new(
838
+ 'ROOT', '', {
839
+ '@type' => 'elasticsearch',
840
+ }, [
841
+ Fluent::Config::Element.new('buffer', '', {
842
+ 'retry_forever' => true
843
+ }, [])
844
+ ]
845
+ ))
846
+ stub_elastic_timeout
847
+ assert_raise(Timeout::Error) {
848
+ driver.run(default_tag: 'test', timeout: 10, force_flush_retry: true) do
849
+ driver.feed(sample_record)
850
+ end
851
+ }
852
+ end
853
+
854
+ def test_tag_parts_index_error_event
855
+ stub_elastic
856
+ driver.configure("logstash_prefix ${tag_parts[1]}\n")
857
+ flexmock(driver.instance.router).should_receive(:emit_error_event)
858
+ .with('test', Fluent::EventTime, Hash, TypeError).once
859
+ driver.run(default_tag: 'test') do
860
+ driver.feed(sample_record)
861
+ end
862
+ end
863
+
864
+ def test_connection_failed
865
+ connection_resets = 0
866
+
867
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
868
+ connection_resets += 1
869
+ raise Faraday::ConnectionFailed, "Test message"
870
+ end
871
+
872
+ assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
873
+ driver.run(default_tag: 'test', shutdown: false) do
874
+ driver.feed(sample_record)
875
+ end
876
+ }
877
+ assert_equal(1, connection_resets)
878
+ end
879
+
880
+ def test_reconnect_on_error_enabled
881
+ connection_resets = 0
882
+
883
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
884
+ connection_resets += 1
885
+ raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
886
+ end
887
+
888
+ driver.configure("reconnect_on_error true\n")
889
+
890
+ assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
891
+ driver.run(default_tag: 'test', shutdown: false) do
892
+ driver.feed(sample_record)
893
+ end
894
+ }
895
+
896
+ assert_raise(Timeout::Error) {
897
+ driver.run(default_tag: 'test', shutdown: false) do
898
+ driver.feed(sample_record)
899
+ end
900
+ }
901
+ # FIXME: Consider keywords arguments in #run and how to test this later.
902
+ # Because v0.14 test driver does not have 1 to 1 correspondence between #run and #flush in tests.
903
+ assert_equal(1, connection_resets)
904
+ end
905
+
906
+ def test_reconnect_on_error_disabled
907
+ connection_resets = 0
908
+
909
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
910
+ connection_resets += 1
911
+ raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
912
+ end
913
+
914
+ driver.configure("reconnect_on_error false\n")
915
+
916
+ assert_raise(Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure) {
917
+ driver.run(default_tag: 'test', shutdown: false) do
918
+ driver.feed(sample_record)
919
+ end
920
+ }
921
+
922
+ assert_raise(Timeout::Error) {
923
+ driver.run(default_tag: 'test', shutdown: false) do
924
+ driver.feed(sample_record)
925
+ end
926
+ }
927
+ assert_equal(1, connection_resets)
928
+ end
929
+
930
+ def test_update_should_not_write_if_theres_no_id
931
+ driver.configure("write_operation update\n")
932
+ stub_elastic
933
+ driver.run(default_tag: 'test') do
934
+ driver.feed(sample_record)
935
+ end
936
+ assert_nil(index_cmds)
937
+ end
938
+
939
+ def test_upsert_should_not_write_if_theres_no_id
940
+ driver.configure("write_operation upsert\n")
941
+ stub_elastic
942
+ driver.run(default_tag: 'test') do
943
+ driver.feed(sample_record)
944
+ end
945
+ assert_nil(index_cmds)
946
+ end
947
+
948
+ def test_create_should_not_write_if_theres_no_id
949
+ driver.configure("write_operation create\n")
950
+ stub_elastic
951
+ driver.run(default_tag: 'test') do
952
+ driver.feed(sample_record)
953
+ end
954
+ assert_nil(index_cmds)
955
+ end
956
+
957
+ def test_update_should_write_update_op_and_doc_as_upsert_is_false
958
+ driver.configure("write_operation update
959
+ id_key request_id")
960
+ stub_elastic
961
+ driver.run(default_tag: 'test') do
962
+ driver.feed(sample_record)
963
+ end
964
+ assert(index_cmds[0].has_key?("update"))
965
+ assert(!index_cmds[1]["doc_as_upsert"])
966
+ end
967
+
968
+ def test_upsert_should_write_update_op_and_doc_as_upsert_is_true
969
+ driver.configure("write_operation upsert
970
+ id_key request_id")
971
+ stub_elastic
972
+ driver.run(default_tag: 'test') do
973
+ driver.feed(sample_record)
974
+ end
975
+ assert(index_cmds[0].has_key?("update"))
976
+ assert(index_cmds[1]["doc_as_upsert"])
977
+ end
978
+
979
+ def test_create_should_write_create_op
980
+ driver.configure("write_operation create
981
+ id_key request_id")
982
+ stub_elastic
983
+ driver.run(default_tag: 'test') do
984
+ driver.feed(sample_record)
985
+ end
986
+ assert(index_cmds[0].has_key?("create"))
987
+ end
988
+
989
+ def test_include_index_in_url
990
+ stub_elastic('http://localhost:9200/logstash-2018.01.01/_bulk')
991
+
992
+ driver.configure("index_name logstash-2018.01.01
993
+ include_index_in_url true")
994
+ driver.run(default_tag: 'test') do
995
+ driver.feed(sample_record)
996
+ end
997
+
998
+ assert_equal(2, index_cmds.length)
999
+ assert_equal(nil, index_cmds.first['index']['_index'])
1000
+ end
1001
+ end