fluent-plugin-elasticsearch 2.10.2 → 2.10.3

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