logstash-input-elasticsearch 4.9.1 → 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,14 +7,15 @@ require "timecop"
7
7
  require "stud/temporary"
8
8
  require "time"
9
9
  require "date"
10
+ require "cabin"
11
+ require "webrick"
12
+ require "uri"
10
13
 
11
- class LogStash::Inputs::TestableElasticsearch < LogStash::Inputs::Elasticsearch
12
- attr_reader :client
13
- end
14
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
14
15
 
15
- describe LogStash::Inputs::TestableElasticsearch do
16
+ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
16
17
 
17
- let(:plugin) { LogStash::Inputs::TestableElasticsearch.new(config) }
18
+ let(:plugin) { described_class.new(config) }
18
19
  let(:queue) { Queue.new }
19
20
 
20
21
  it_behaves_like "an interruptible input plugin" do
@@ -40,7 +41,13 @@ describe LogStash::Inputs::TestableElasticsearch do
40
41
  end
41
42
  end
42
43
 
43
- context 'creating events from Elasticsearch' do
44
+
45
+ ecs_compatibility_matrix(:disabled, :v1, :v8) do |ecs_select|
46
+
47
+ before(:each) do
48
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
49
+ end
50
+
44
51
  let(:config) do
45
52
  %q[
46
53
  input {
@@ -97,7 +104,6 @@ describe LogStash::Inputs::TestableElasticsearch do
97
104
  end
98
105
 
99
106
  expect(event).to be_a(LogStash::Event)
100
- puts event.to_hash_with_metadata
101
107
  expect(event.get("message")).to eql [ "ohayo" ]
102
108
  end
103
109
 
@@ -120,10 +126,10 @@ describe LogStash::Inputs::TestableElasticsearch do
120
126
  end
121
127
 
122
128
  expect(event).to be_a(LogStash::Event)
123
- puts event.to_hash_with_metadata
124
129
  expect(event.get("[@metadata][_source][message]")).to eql [ "ohayo" ]
125
130
  end
126
131
  end
132
+
127
133
  end
128
134
 
129
135
  # This spec is an adapter-spec, ensuring that we send the right sequence of messages to our Elasticsearch Client
@@ -135,6 +141,7 @@ describe LogStash::Inputs::TestableElasticsearch do
135
141
  'query' => "#{LogStash::Json.dump(query)}",
136
142
  'slices' => slices,
137
143
  'docinfo' => true, # include ids
144
+ 'docinfo_target' => '[@metadata]'
138
145
  }
139
146
  end
140
147
  let(:query) do
@@ -166,7 +173,7 @@ describe LogStash::Inputs::TestableElasticsearch do
166
173
  end
167
174
 
168
175
  context 'without slices directive' do
169
- let(:config) { super.tap { |h| h.delete('slices') } }
176
+ let(:config) { super().tap { |h| h.delete('slices') } }
170
177
  it 'runs just one slice' do
171
178
  expect(plugin).to receive(:do_run_slice).with(duck_type(:<<))
172
179
  expect(Thread).to_not receive(:new)
@@ -405,127 +412,140 @@ describe LogStash::Inputs::TestableElasticsearch do
405
412
  allow(client).to receive(:clear_scroll).and_return(nil)
406
413
  end
407
414
 
408
- context 'when defining docinfo' do
409
- let(:config_metadata) do
410
- %q[
411
- input {
412
- elasticsearch {
413
- hosts => ["localhost"]
414
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
415
- docinfo => true
416
- }
417
- }
418
- ]
419
- end
415
+ ecs_compatibility_matrix(:disabled, :v1, :v8) do |ecs_select|
420
416
 
421
- it 'merges the values if the `docinfo_target` already exist in the `_source` document' do
422
- config_metadata_with_hash = %Q[
423
- input {
424
- elasticsearch {
425
- hosts => ["localhost"]
426
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
427
- docinfo => true
428
- docinfo_target => 'metadata_with_hash'
417
+ before(:each) do
418
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
419
+ end
420
+
421
+ context 'with docinfo enabled' do
422
+ let(:config_metadata) do
423
+ %q[
424
+ input {
425
+ elasticsearch {
426
+ hosts => ["localhost"]
427
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
428
+ docinfo => true
429
+ }
429
430
  }
430
- }
431
- ]
432
-
433
- event = input(config_metadata_with_hash) do |pipeline, queue|
434
- queue.pop
431
+ ]
435
432
  end
436
433
 
437
- expect(event.get("[metadata_with_hash][_index]")).to eq('logstash-2014.10.12')
438
- expect(event.get("[metadata_with_hash][_type]")).to eq('logs')
439
- expect(event.get("[metadata_with_hash][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
440
- expect(event.get("[metadata_with_hash][awesome]")).to eq("logstash")
441
- end
442
-
443
- context 'if the `docinfo_target` exist but is not of type hash' do
444
- let (:config) { {
445
- "hosts" => ["localhost"],
446
- "query" => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }',
447
- "docinfo" => true,
448
- "docinfo_target" => 'metadata_with_string'
449
- } }
450
- it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
451
- expect(client).not_to receive(:clear_scroll)
452
- plugin.register
453
- expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
434
+ it "provides document info under metadata" do
435
+ event = input(config_metadata) do |pipeline, queue|
436
+ queue.pop
437
+ end
438
+
439
+ if ecs_select.active_mode == :disabled
440
+ expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
441
+ expect(event.get("[@metadata][_type]")).to eq('logs')
442
+ expect(event.get("[@metadata][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
443
+ else
444
+ expect(event.get("[@metadata][input][elasticsearch][_index]")).to eq('logstash-2014.10.12')
445
+ expect(event.get("[@metadata][input][elasticsearch][_type]")).to eq('logs')
446
+ expect(event.get("[@metadata][input][elasticsearch][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
447
+ end
454
448
  end
455
- end
456
449
 
457
- it "should move the document info to the @metadata field" do
458
- event = input(config_metadata) do |pipeline, queue|
459
- queue.pop
450
+ it 'merges values if the `docinfo_target` already exist in the `_source` document' do
451
+ config_metadata_with_hash = %Q[
452
+ input {
453
+ elasticsearch {
454
+ hosts => ["localhost"]
455
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
456
+ docinfo => true
457
+ docinfo_target => 'metadata_with_hash'
458
+ }
459
+ }
460
+ ]
461
+
462
+ event = input(config_metadata_with_hash) do |pipeline, queue|
463
+ queue.pop
464
+ end
465
+
466
+ expect(event.get("[metadata_with_hash][_index]")).to eq('logstash-2014.10.12')
467
+ expect(event.get("[metadata_with_hash][_type]")).to eq('logs')
468
+ expect(event.get("[metadata_with_hash][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
469
+ expect(event.get("[metadata_with_hash][awesome]")).to eq("logstash")
460
470
  end
461
471
 
462
- expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
463
- expect(event.get("[@metadata][_type]")).to eq('logs')
464
- expect(event.get("[@metadata][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
465
- end
472
+ context 'if the `docinfo_target` exist but is not of type hash' do
473
+ let (:config) { {
474
+ "hosts" => ["localhost"],
475
+ "query" => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }',
476
+ "docinfo" => true,
477
+ "docinfo_target" => 'metadata_with_string'
478
+ } }
479
+ it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
480
+ expect(client).not_to receive(:clear_scroll)
481
+ plugin.register
482
+ expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
483
+ end
484
+ end
466
485
 
467
- it 'should move the document information to the specified field' do
468
- config = %q[
469
- input {
470
- elasticsearch {
471
- hosts => ["localhost"]
472
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
473
- docinfo => true
474
- docinfo_target => 'meta'
486
+ it 'should move the document information to the specified field' do
487
+ config = %q[
488
+ input {
489
+ elasticsearch {
490
+ hosts => ["localhost"]
491
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
492
+ docinfo => true
493
+ docinfo_target => 'meta'
494
+ }
475
495
  }
476
- }
477
- ]
478
- event = input(config) do |pipeline, queue|
479
- queue.pop
496
+ ]
497
+ event = input(config) do |pipeline, queue|
498
+ queue.pop
499
+ end
500
+
501
+ expect(event.get("[meta][_index]")).to eq('logstash-2014.10.12')
502
+ expect(event.get("[meta][_type]")).to eq('logs')
503
+ expect(event.get("[meta][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
480
504
  end
481
505
 
482
- expect(event.get("[meta][_index]")).to eq('logstash-2014.10.12')
483
- expect(event.get("[meta][_type]")).to eq('logs')
484
- expect(event.get("[meta][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
485
- end
506
+ it "allows to specify which fields from the document info to save to metadata" do
507
+ fields = ["_index"]
508
+ config = %Q[
509
+ input {
510
+ elasticsearch {
511
+ hosts => ["localhost"]
512
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
513
+ docinfo => true
514
+ docinfo_fields => #{fields}
515
+ }
516
+ }]
517
+
518
+ event = input(config) do |pipeline, queue|
519
+ queue.pop
520
+ end
521
+
522
+ meta_base = event.get(ecs_select.active_mode == :disabled ? "@metadata" : "[@metadata][input][elasticsearch]")
523
+ expect(meta_base.keys).to eq(fields)
524
+ end
486
525
 
487
- it "should allow to specify which fields from the document info to save to the @metadata field" do
488
- fields = ["_index"]
489
- config = %Q[
526
+ it 'should be able to reference metadata fields in `add_field` decorations' do
527
+ config = %q[
490
528
  input {
491
529
  elasticsearch {
492
530
  hosts => ["localhost"]
493
531
  query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
494
532
  docinfo => true
495
- docinfo_fields => #{fields}
496
- }
497
- }]
498
-
499
- event = input(config) do |pipeline, queue|
500
- queue.pop
501
- end
502
-
503
- expect(event.get("@metadata").keys).to eq(fields)
504
- expect(event.get("[@metadata][_type]")).to eq(nil)
505
- expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
506
- expect(event.get("[@metadata][_id]")).to eq(nil)
507
- end
508
-
509
- it 'should be able to reference metadata fields in `add_field` decorations' do
510
- config = %q[
511
- input {
512
- elasticsearch {
513
- hosts => ["localhost"]
514
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
515
- docinfo => true
516
- add_field => {
517
- 'identifier' => "foo:%{[@metadata][_type]}:%{[@metadata][_id]}"
533
+ add_field => {
534
+ 'identifier' => "foo:%{[@metadata][_type]}:%{[@metadata][_id]}"
535
+ }
518
536
  }
519
537
  }
520
- }
521
- ]
538
+ ]
522
539
 
523
- event = input(config) do |pipeline, queue|
524
- queue.pop
525
- end
540
+ event = input(config) do |pipeline, queue|
541
+ queue.pop
542
+ end
543
+
544
+ expect(event.get('identifier')).to eq('foo:logs:C5b2xLQwTZa76jBmHIbwHQ')
545
+ end if ecs_select.active_mode == :disabled
526
546
 
527
- expect(event.get('identifier')).to eq('foo:logs:C5b2xLQwTZa76jBmHIbwHQ')
528
547
  end
548
+
529
549
  end
530
550
 
531
551
  context "when not defining the docinfo" do
@@ -542,9 +562,7 @@ describe LogStash::Inputs::TestableElasticsearch do
542
562
  queue.pop
543
563
  end
544
564
 
545
- expect(event.get("[@metadata][_index]")).to eq(nil)
546
- expect(event.get("[@metadata][_type]")).to eq(nil)
547
- expect(event.get("[@metadata][_id]")).to eq(nil)
565
+ expect(event.get("[@metadata]")).to be_empty
548
566
  end
549
567
  end
550
568
  end
@@ -563,22 +581,22 @@ describe LogStash::Inputs::TestableElasticsearch do
563
581
  'sample:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA=='
564
582
  end
565
583
 
566
- let(:config) { super.merge({ 'cloud_id' => valid_cloud_id }) }
584
+ let(:config) { super().merge({ 'cloud_id' => valid_cloud_id }) }
567
585
 
568
586
  it "should set host(s)" do
569
587
  plugin.register
570
588
  client = plugin.send(:client)
571
- expect( client.transport.hosts ).to eql [{
572
- :scheme => "https",
573
- :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
574
- :port => 9243,
575
- :path => "",
576
- :protocol => "https"
577
- }]
589
+ expect( extract_transport(client).hosts ).to eql [{
590
+ :scheme => "https",
591
+ :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
592
+ :port => 9243,
593
+ :path => "",
594
+ :protocol => "https"
595
+ }]
578
596
  end
579
597
 
580
598
  context 'invalid' do
581
- let(:config) { super.merge({ 'cloud_id' => 'invalid:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlv' }) }
599
+ let(:config) { super().merge({ 'cloud_id' => 'invalid:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlv' }) }
582
600
 
583
601
  it "should fail" do
584
602
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_id.*? is invalid/
@@ -586,7 +604,7 @@ describe LogStash::Inputs::TestableElasticsearch do
586
604
  end
587
605
 
588
606
  context 'hosts also set' do
589
- let(:config) { super.merge({ 'cloud_id' => valid_cloud_id, 'hosts' => [ 'localhost:9200' ] }) }
607
+ let(:config) { super().merge({ 'cloud_id' => valid_cloud_id, 'hosts' => [ 'localhost:9200' ] }) }
590
608
 
591
609
  it "should fail" do
592
610
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_id and hosts/
@@ -595,18 +613,18 @@ describe LogStash::Inputs::TestableElasticsearch do
595
613
  end if LOGSTASH_VERSION > '6.0'
596
614
 
597
615
  describe "cloud.auth" do
598
- let(:config) { super.merge({ 'cloud_auth' => LogStash::Util::Password.new('elastic:my-passwd-00') }) }
616
+ let(:config) { super().merge({ 'cloud_auth' => LogStash::Util::Password.new('elastic:my-passwd-00') }) }
599
617
 
600
618
  it "should set authorization" do
601
619
  plugin.register
602
620
  client = plugin.send(:client)
603
- auth_header = client.transport.options[:transport_options][:headers][:Authorization]
621
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
604
622
 
605
623
  expect( auth_header ).to eql "Basic #{Base64.encode64('elastic:my-passwd-00').rstrip}"
606
624
  end
607
625
 
608
626
  context 'invalid' do
609
- let(:config) { super.merge({ 'cloud_auth' => 'invalid-format' }) }
627
+ let(:config) { super().merge({ 'cloud_auth' => 'invalid-format' }) }
610
628
 
611
629
  it "should fail" do
612
630
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_auth.*? format/
@@ -614,7 +632,7 @@ describe LogStash::Inputs::TestableElasticsearch do
614
632
  end
615
633
 
616
634
  context 'user also set' do
617
- let(:config) { super.merge({ 'cloud_auth' => 'elastic:my-passwd-00', 'user' => 'another' }) }
635
+ let(:config) { super().merge({ 'cloud_auth' => 'elastic:my-passwd-00', 'user' => 'another' }) }
618
636
 
619
637
  it "should fail" do
620
638
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
@@ -624,7 +642,7 @@ describe LogStash::Inputs::TestableElasticsearch do
624
642
 
625
643
  describe "api_key" do
626
644
  context "without ssl" do
627
- let(:config) { super.merge({ 'api_key' => LogStash::Util::Password.new('foo:bar') }) }
645
+ let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar') }) }
628
646
 
629
647
  it "should fail" do
630
648
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /api_key authentication requires SSL\/TLS/
@@ -632,18 +650,18 @@ describe LogStash::Inputs::TestableElasticsearch do
632
650
  end
633
651
 
634
652
  context "with ssl" do
635
- let(:config) { super.merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl" => true }) }
653
+ let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl" => true }) }
636
654
 
637
655
  it "should set authorization" do
638
656
  plugin.register
639
657
  client = plugin.send(:client)
640
- auth_header = client.transport.options[:transport_options][:headers][:Authorization]
658
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
641
659
 
642
660
  expect( auth_header ).to eql "ApiKey #{Base64.strict_encode64('foo:bar')}"
643
661
  end
644
662
 
645
663
  context 'user also set' do
646
- let(:config) { super.merge({ 'api_key' => 'foo:bar', 'user' => 'another' }) }
664
+ let(:config) { super().merge({ 'api_key' => 'foo:bar', 'user' => 'another' }) }
647
665
 
648
666
  it "should fail" do
649
667
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
@@ -653,24 +671,174 @@ describe LogStash::Inputs::TestableElasticsearch do
653
671
  end if LOGSTASH_VERSION > '6.0'
654
672
 
655
673
  describe "proxy" do
656
- let(:config) { super.merge({ 'proxy' => 'http://localhost:1234' }) }
674
+ let(:config) { super().merge({ 'proxy' => 'http://localhost:1234' }) }
657
675
 
658
676
  it "should set proxy" do
659
677
  plugin.register
660
678
  client = plugin.send(:client)
661
- proxy = client.transport.options[:transport_options][:proxy]
679
+ proxy = extract_transport(client).options[:transport_options][:proxy]
662
680
 
663
681
  expect( proxy ).to eql "http://localhost:1234"
664
682
  end
665
683
 
666
684
  context 'invalid' do
667
- let(:config) { super.merge({ 'proxy' => '${A_MISSING_ENV_VAR:}' }) }
685
+ let(:config) { super().merge({ 'proxy' => '${A_MISSING_ENV_VAR:}' }) }
668
686
 
669
687
  it "should not set proxy" do
670
688
  plugin.register
671
689
  client = plugin.send(:client)
672
690
 
673
- expect( client.transport.options[:transport_options] ).to_not include(:proxy)
691
+ expect( extract_transport(client).options[:transport_options] ).to_not include(:proxy)
692
+ end
693
+ end
694
+ end
695
+
696
+ class StoppableServer
697
+
698
+ attr_reader :port
699
+
700
+ def initialize()
701
+ queue = Queue.new
702
+ @first_req_waiter = java.util.concurrent.CountDownLatch.new(1)
703
+ @first_request = nil
704
+
705
+ @t = java.lang.Thread.new(
706
+ proc do
707
+ begin
708
+ @server = WEBrick::HTTPServer.new :Port => 0, :DocumentRoot => ".",
709
+ :Logger => Cabin::Channel.get, # silence WEBrick logging
710
+ :StartCallback => Proc.new {
711
+ queue.push("started")
712
+ }
713
+ @port = @server.config[:Port]
714
+ @server.mount_proc '/' do |req, res|
715
+ res.body = '''
716
+ {
717
+ "name": "ce7ccfb438e8",
718
+ "cluster_name": "docker-cluster",
719
+ "cluster_uuid": "DyR1hN03QvuCWXRy3jtb0g",
720
+ "version": {
721
+ "number": "7.13.1",
722
+ "build_flavor": "default",
723
+ "build_type": "docker",
724
+ "build_hash": "9a7758028e4ea59bcab41c12004603c5a7dd84a9",
725
+ "build_date": "2021-05-28T17:40:59.346932922Z",
726
+ "build_snapshot": false,
727
+ "lucene_version": "8.8.2",
728
+ "minimum_wire_compatibility_version": "6.8.0",
729
+ "minimum_index_compatibility_version": "6.0.0-beta1"
730
+ },
731
+ "tagline": "You Know, for Search"
732
+ }
733
+ '''
734
+ res.status = 200
735
+ res['Content-Type'] = 'application/json'
736
+ @first_request = req
737
+ @first_req_waiter.countDown()
738
+ end
739
+
740
+ @server.mount_proc '/logstash_unit_test/_search' do |req, res|
741
+ res.body = '''
742
+ {
743
+ "took" : 1,
744
+ "timed_out" : false,
745
+ "_shards" : {
746
+ "total" : 1,
747
+ "successful" : 1,
748
+ "skipped" : 0,
749
+ "failed" : 0
750
+ },
751
+ "hits" : {
752
+ "total" : {
753
+ "value" : 10000,
754
+ "relation" : "gte"
755
+ },
756
+ "max_score" : 1.0,
757
+ "hits" : [
758
+ {
759
+ "_index" : "test_bulk_index_2",
760
+ "_type" : "_doc",
761
+ "_id" : "sHe6A3wBesqF7ydicQvG",
762
+ "_score" : 1.0,
763
+ "_source" : {
764
+ "@timestamp" : "2021-09-20T15:02:02.557Z",
765
+ "message" : "{\"name\": \"Andrea\"}",
766
+ "@version" : "1",
767
+ "host" : "kalispera",
768
+ "sequence" : 5
769
+ }
770
+ }
771
+ ]
772
+ }
773
+ }
774
+ '''
775
+ res.status = 200
776
+ res['Content-Type'] = 'application/json'
777
+ @first_request = req
778
+ @first_req_waiter.countDown()
779
+ end
780
+
781
+
782
+
783
+ @server.start
784
+ rescue => e
785
+ puts "Error in webserver thread #{e}"
786
+ # ignore
787
+ end
788
+ end
789
+ )
790
+ @t.daemon = true
791
+ @t.start
792
+ queue.pop # blocks until the server is up
793
+ end
794
+
795
+ def stop
796
+ @server.shutdown
797
+ end
798
+
799
+ def wait_receive_request
800
+ @first_req_waiter.await(2, java.util.concurrent.TimeUnit::SECONDS)
801
+ @first_request
802
+ end
803
+ end
804
+
805
+ describe "'user-agent' header" do
806
+ let!(:webserver) { StoppableServer.new } # webserver must be started before the call, so no lazy "let"
807
+
808
+ after :each do
809
+ webserver.stop
810
+ end
811
+
812
+ it "server should be started" do
813
+ require 'net/http'
814
+ response = nil
815
+ Net::HTTP.start('localhost', webserver.port) {|http|
816
+ response = http.request_get('/')
817
+ }
818
+ expect(response.code.to_i).to eq(200)
819
+ end
820
+
821
+ context "used by plugin" do
822
+ let(:config) do
823
+ {
824
+ "hosts" => ["localhost:#{webserver.port}"],
825
+ "query" => '{ "query": { "match": { "statuscode": 200 } }, "sort": [ "_doc" ] }',
826
+ "index" => "logstash_unit_test"
827
+ }
828
+ end
829
+ let(:plugin) { described_class.new(config) }
830
+ let(:event) { LogStash::Event.new({}) }
831
+
832
+ it "client should sent the expect user-agent" do
833
+ plugin.register
834
+
835
+ queue = []
836
+ plugin.run(queue)
837
+
838
+ request = webserver.wait_receive_request
839
+
840
+ expect(request.header['user-agent'].size).to eq(1)
841
+ expect(request.header['user-agent'][0]).to match(/logstash\/\d*\.\d*\.\d* \(OS=.*; JVM=.*\) logstash-input-elasticsearch\/\d*\.\d*\.\d*/)
674
842
  end
675
843
  end
676
844
  end
@@ -756,4 +924,10 @@ describe LogStash::Inputs::TestableElasticsearch do
756
924
  end
757
925
 
758
926
  end
927
+
928
+ # @note can be removed once we depends on elasticsearch gem >= 6.x
929
+ def extract_transport(client) # on 7.x client.transport is a ES::Transport::Client
930
+ client.transport.respond_to?(:transport) ? client.transport.transport : client.transport
931
+ end
932
+
759
933
  end
@@ -11,7 +11,7 @@ describe LogStash::Inputs::Elasticsearch do
11
11
  'query' => '{ "query": { "match": { "message": "Not found"} }}' } }
12
12
  let(:plugin) { described_class.new(config) }
13
13
  let(:event) { LogStash::Event.new({}) }
14
- let(:client_options) {{}}
14
+ let(:client_options) { Hash.new }
15
15
 
16
16
  before(:each) do
17
17
  @es = ESHelper.get_client(client_options)
@@ -47,17 +47,29 @@ describe LogStash::Inputs::Elasticsearch do
47
47
  end
48
48
 
49
49
  describe 'against a secured elasticsearch', :secure_integration => true do
50
- let(:user) { 'simpleuser' }
51
- let(:password) { 'abc123' }
52
- let(:ca_file) { "spec/fixtures/test_certs/test.crt" }
53
- let(:client_options) {{:ca_file => ca_file, :user => user, :password => password}}
54
- let(:config) { super.merge({
55
- 'user' => user,
56
- 'password' => password,
57
- 'ssl' => true,
58
- 'ca_file' => ca_file })
59
- }
50
+ let(:user) { ENV['ELASTIC_USER'] || 'simpleuser' }
51
+ let(:password) { ENV['ELASTIC_PASSWORD'] || 'abc123' }
52
+ let(:ca_file) { "spec/fixtures/test_certs/ca.crt" }
53
+
54
+ let(:client_options) { { :ca_file => ca_file, :user => user, :password => password } }
55
+
56
+ let(:config) { super().merge('user' => user, 'password' => password, 'ssl' => true, 'ca_file' => ca_file) }
57
+
60
58
  it_behaves_like 'an elasticsearch index plugin'
59
+
60
+ context "incorrect auth credentials" do
61
+
62
+ let(:config) do
63
+ super().merge('user' => 'archer', 'password' => 'b0gus!')
64
+ end
65
+
66
+ let(:queue) { [] }
67
+
68
+ it "fails to run the plugin" do
69
+ plugin.register
70
+ expect { plugin.run queue }.to raise_error Elasticsearch::Transport::Transport::Errors::Unauthorized
71
+ end
72
+ end
73
+
61
74
  end
62
75
  end
63
-