logstash-output-opensearch 1.0.0-java
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.
- checksums.yaml +7 -0
 - checksums.yaml.gz.sig +0 -0
 - data.tar.gz.sig +0 -0
 - data/ADMINS.md +29 -0
 - data/CODE_OF_CONDUCT.md +25 -0
 - data/CONTRIBUTING.md +99 -0
 - data/DEVELOPER_GUIDE.md +208 -0
 - data/Gemfile +20 -0
 - data/LICENSE +202 -0
 - data/MAINTAINERS.md +71 -0
 - data/NOTICE +2 -0
 - data/README.md +37 -0
 - data/RELEASING.md +36 -0
 - data/SECURITY.md +3 -0
 - data/lib/logstash/outputs/opensearch.rb +449 -0
 - data/lib/logstash/outputs/opensearch/distribution_checker.rb +44 -0
 - data/lib/logstash/outputs/opensearch/http_client.rb +465 -0
 - data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +140 -0
 - data/lib/logstash/outputs/opensearch/http_client/pool.rb +467 -0
 - data/lib/logstash/outputs/opensearch/http_client_builder.rb +182 -0
 - data/lib/logstash/outputs/opensearch/template_manager.rb +60 -0
 - data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x.json +44 -0
 - data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x.json +44 -0
 - data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +168 -0
 - data/lib/logstash/plugin_mixins/opensearch/common.rb +294 -0
 - data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +18 -0
 - data/logstash-output-opensearch.gemspec +40 -0
 - data/spec/fixtures/_nodes/nodes.json +74 -0
 - data/spec/fixtures/htpasswd +2 -0
 - data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
 - data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
 - data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
 - data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
 - data/spec/integration/outputs/compressed_indexing_spec.rb +76 -0
 - data/spec/integration/outputs/create_spec.rb +76 -0
 - data/spec/integration/outputs/delete_spec.rb +72 -0
 - data/spec/integration/outputs/index_spec.rb +164 -0
 - data/spec/integration/outputs/index_version_spec.rb +110 -0
 - data/spec/integration/outputs/ingest_pipeline_spec.rb +82 -0
 - data/spec/integration/outputs/metrics_spec.rb +75 -0
 - data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +67 -0
 - data/spec/integration/outputs/painless_update_spec.rb +147 -0
 - data/spec/integration/outputs/parent_spec.rb +103 -0
 - data/spec/integration/outputs/retry_spec.rb +182 -0
 - data/spec/integration/outputs/routing_spec.rb +70 -0
 - data/spec/integration/outputs/sniffer_spec.rb +70 -0
 - data/spec/integration/outputs/templates_spec.rb +105 -0
 - data/spec/integration/outputs/update_spec.rb +123 -0
 - data/spec/opensearch_spec_helper.rb +141 -0
 - data/spec/spec_helper.rb +19 -0
 - data/spec/unit/http_client_builder_spec.rb +194 -0
 - data/spec/unit/outputs/error_whitelist_spec.rb +62 -0
 - data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +159 -0
 - data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +306 -0
 - data/spec/unit/outputs/opensearch/http_client_spec.rb +292 -0
 - data/spec/unit/outputs/opensearch/template_manager_spec.rb +36 -0
 - data/spec/unit/outputs/opensearch_proxy_spec.rb +112 -0
 - data/spec/unit/outputs/opensearch_spec.rb +800 -0
 - data/spec/unit/outputs/opensearch_ssl_spec.rb +179 -0
 - metadata +289 -0
 - metadata.gz.sig +0 -0
 
| 
         @@ -0,0 +1,306 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: Apache-2.0
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            #  The OpenSearch Contributors require contributions made to
         
     | 
| 
      
 4 
     | 
    
         
            +
            #  this file be licensed under the Apache-2.0 license or a
         
     | 
| 
      
 5 
     | 
    
         
            +
            #  compatible open source license.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            #  Modifications Copyright OpenSearch Contributors. See
         
     | 
| 
      
 8 
     | 
    
         
            +
            #  GitHub history for details.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            require "logstash/devutils/rspec/spec_helper"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "logstash/outputs/opensearch/http_client"
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'cabin'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            describe LogStash::Outputs::OpenSearch::HttpClient::Pool do
         
     | 
| 
      
 15 
     | 
    
         
            +
              let(:logger) { Cabin::Channel.get }
         
     | 
| 
      
 16 
     | 
    
         
            +
              let(:adapter) { LogStash::Outputs::OpenSearch::HttpClient::ManticoreAdapter.new(logger) }
         
     | 
| 
      
 17 
     | 
    
         
            +
              let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
         
     | 
| 
      
 18 
     | 
    
         
            +
              let(:options) { {:resurrect_delay => 2, :url_normalizer => proc {|u| u}} } # Shorten the delay a bit to speed up tests
         
     | 
| 
      
 19 
     | 
    
         
            +
              let(:node_versions) { [ "7.0.0" ] }
         
     | 
| 
      
 20 
     | 
    
         
            +
              let(:get_distribution) { "oss" }
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              subject { described_class.new(logger, adapter, initial_urls, options) }
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              let(:manticore_double) { double("manticore a") }
         
     | 
| 
      
 25 
     | 
    
         
            +
              before(:each) do
         
     | 
| 
      
 26 
     | 
    
         
            +
                response_double = double("manticore response").as_null_object
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Allow healtchecks
         
     | 
| 
      
 28 
     | 
    
         
            +
                allow(manticore_double).to receive(:head).with(any_args).and_return(response_double)
         
     | 
| 
      
 29 
     | 
    
         
            +
                allow(manticore_double).to receive(:get).with(any_args).and_return(response_double)
         
     | 
| 
      
 30 
     | 
    
         
            +
                allow(manticore_double).to receive(:close)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                allow(::Manticore::Client).to receive(:new).and_return(manticore_double)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                allow(subject).to receive(:get_version).with(any_args).and_return(*node_versions)
         
     | 
| 
      
 35 
     | 
    
         
            +
                allow(subject.distribution_checker).to receive(:get_distribution).and_return(get_distribution)
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              after do
         
     | 
| 
      
 39 
     | 
    
         
            +
                subject.close
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              describe "initialization" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                it "should be successful" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  expect { subject }.not_to raise_error
         
     | 
| 
      
 45 
     | 
    
         
            +
                  subject.start
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              describe "the resurrectionist" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                before(:each) { subject.start }
         
     | 
| 
      
 51 
     | 
    
         
            +
                it "should start the resurrectionist when created" do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  expect(subject.resurrectionist_alive?).to eql(true)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                it "should attempt to resurrect connections after the ressurrect delay" do
         
     | 
| 
      
 56 
     | 
    
         
            +
                  expect(subject).to receive(:healthcheck!).once
         
     | 
| 
      
 57 
     | 
    
         
            +
                  sleep(subject.resurrect_delay + 1)
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                describe "healthcheck url handling" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                  let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  context "and not setting healthcheck_path" do
         
     | 
| 
      
 64 
     | 
    
         
            +
                    it "performs the healthcheck to the root" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                      expect(adapter).to receive(:perform_request) do |url, method, req_path, _, _|
         
     | 
| 
      
 66 
     | 
    
         
            +
                        expect(method).to eq(:head)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        expect(url.path).to be_empty
         
     | 
| 
      
 68 
     | 
    
         
            +
                        expect(req_path).to eq("/")
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                      subject.healthcheck!
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  context "and setting healthcheck_path" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    let(:healthcheck_path) { "/my/health" }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    let(:options) { super().merge(:healthcheck_path => healthcheck_path) }
         
     | 
| 
      
 77 
     | 
    
         
            +
                    it "performs the healthcheck to the healthcheck_path" do
         
     | 
| 
      
 78 
     | 
    
         
            +
                      expect(adapter).to receive(:perform_request) do |url, method, req_path, _, _|
         
     | 
| 
      
 79 
     | 
    
         
            +
                        expect(method).to eq(:head)
         
     | 
| 
      
 80 
     | 
    
         
            +
                        expect(url.path).to be_empty
         
     | 
| 
      
 81 
     | 
    
         
            +
                        expect(req_path).to eq(healthcheck_path)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      end
         
     | 
| 
      
 83 
     | 
    
         
            +
                      subject.healthcheck!
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              describe 'resolving the address from OpenSearch node info' do
         
     | 
| 
      
 90 
     | 
    
         
            +
                let(:host) { "unit-test-node"}
         
     | 
| 
      
 91 
     | 
    
         
            +
                let(:ip_address) { "192.168.1.0"}
         
     | 
| 
      
 92 
     | 
    
         
            +
                let(:port) { 9200 }
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                context 'with host and ip address' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                  let(:publish_address) { "#{host}/#{ip_address}:#{port}"}
         
     | 
| 
      
 96 
     | 
    
         
            +
                  it 'should correctly extract the host' do
         
     | 
| 
      
 97 
     | 
    
         
            +
                    expect(subject.address_str_to_uri(publish_address)).to eq (LogStash::Util::SafeURI.new("#{host}:#{port}"))
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
                context 'with ip address' do
         
     | 
| 
      
 101 
     | 
    
         
            +
                  let(:publish_address) { "#{ip_address}:#{port}"}
         
     | 
| 
      
 102 
     | 
    
         
            +
                  it 'should correctly extract the ip address' do
         
     | 
| 
      
 103 
     | 
    
         
            +
                    expect(subject.address_str_to_uri(publish_address)).to eq (LogStash::Util::SafeURI.new("#{ip_address}:#{port}"))
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
              end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              describe "the sniffer" do
         
     | 
| 
      
 109 
     | 
    
         
            +
                before(:each) { subject.start }
         
     | 
| 
      
 110 
     | 
    
         
            +
                it "should not start the sniffer by default" do
         
     | 
| 
      
 111 
     | 
    
         
            +
                  expect(subject.sniffer_alive?).to eql(nil)
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                context "when enabled" do
         
     | 
| 
      
 115 
     | 
    
         
            +
                  let(:options) { super().merge(:sniffing => true)}
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  it "should start the sniffer" do
         
     | 
| 
      
 118 
     | 
    
         
            +
                    expect(subject.sniffer_alive?).to eql(true)
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
              end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
              describe "closing" do
         
     | 
| 
      
 124 
     | 
    
         
            +
                before do
         
     | 
| 
      
 125 
     | 
    
         
            +
                  subject.start
         
     | 
| 
      
 126 
     | 
    
         
            +
                  # Simulate a single in use connection on the first check of this
         
     | 
| 
      
 127 
     | 
    
         
            +
                  allow(adapter).to receive(:close).and_call_original
         
     | 
| 
      
 128 
     | 
    
         
            +
                  allow(subject).to receive(:wait_for_in_use_connections).and_call_original
         
     | 
| 
      
 129 
     | 
    
         
            +
                  allow(subject).to receive(:in_use_connections).and_return([subject.empty_url_meta()],[])
         
     | 
| 
      
 130 
     | 
    
         
            +
                  allow(subject).to receive(:start)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  subject.close
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                it "should close the adapter" do
         
     | 
| 
      
 135 
     | 
    
         
            +
                  expect(adapter).to have_received(:close)
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                it "should stop the resurrectionist" do
         
     | 
| 
      
 139 
     | 
    
         
            +
                  expect(subject.resurrectionist_alive?).to eql(false)
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                it "should stop the sniffer" do
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # If no sniffer (the default) returns nil
         
     | 
| 
      
 144 
     | 
    
         
            +
                  expect(subject.sniffer_alive?).to be_falsey
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                it "should wait for in use connections to terminate" do
         
     | 
| 
      
 148 
     | 
    
         
            +
                  expect(subject).to have_received(:wait_for_in_use_connections).once
         
     | 
| 
      
 149 
     | 
    
         
            +
                  expect(subject).to have_received(:in_use_connections).twice
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
              describe "connection management" do
         
     | 
| 
      
 154 
     | 
    
         
            +
                before(:each) { subject.start }
         
     | 
| 
      
 155 
     | 
    
         
            +
                context "with only one URL in the list" do
         
     | 
| 
      
 156 
     | 
    
         
            +
                  it "should use the only URL in 'with_connection'" do
         
     | 
| 
      
 157 
     | 
    
         
            +
                    subject.with_connection do |c|
         
     | 
| 
      
 158 
     | 
    
         
            +
                      expect(c).to eq(initial_urls.first)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    end
         
     | 
| 
      
 160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                context "with multiple URLs in the list" do
         
     | 
| 
      
 164 
     | 
    
         
            +
                  before :each do
         
     | 
| 
      
 165 
     | 
    
         
            +
                    allow(adapter).to receive(:perform_request).with(anything, :head, subject.healthcheck_path, {}, nil)
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
                  let(:initial_urls) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200"), ::LogStash::Util::SafeURI.new("http://localhost:9201"), ::LogStash::Util::SafeURI.new("http://localhost:9202") ] }
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                  it "should minimize the number of connections to a single URL" do
         
     | 
| 
      
 170 
     | 
    
         
            +
                    connected_urls = []
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    # If we make 2x the number requests as we have URLs we should
         
     | 
| 
      
 173 
     | 
    
         
            +
                    # connect to each URL exactly 2 times
         
     | 
| 
      
 174 
     | 
    
         
            +
                    (initial_urls.size*2).times do
         
     | 
| 
      
 175 
     | 
    
         
            +
                      u, meta = subject.get_connection
         
     | 
| 
      
 176 
     | 
    
         
            +
                      connected_urls << u
         
     | 
| 
      
 177 
     | 
    
         
            +
                    end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                    connected_urls.each {|u| subject.return_connection(u) }
         
     | 
| 
      
 180 
     | 
    
         
            +
                    initial_urls.each do |url|
         
     | 
| 
      
 181 
     | 
    
         
            +
                      conn_count = connected_urls.select {|u| u == url}.size
         
     | 
| 
      
 182 
     | 
    
         
            +
                      expect(conn_count).to eql(2)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    end
         
     | 
| 
      
 184 
     | 
    
         
            +
                  end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                  it "should correctly resurrect the dead" do
         
     | 
| 
      
 187 
     | 
    
         
            +
                    u,m = subject.get_connection
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                    # The resurrectionist will call this to check on the backend
         
     | 
| 
      
 190 
     | 
    
         
            +
                    response = double("response")
         
     | 
| 
      
 191 
     | 
    
         
            +
                    expect(adapter).to receive(:perform_request).with(u, :head, subject.healthcheck_path, {}, nil).and_return(response)
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                    subject.return_connection(u)
         
     | 
| 
      
 194 
     | 
    
         
            +
                    subject.mark_dead(u, Exception.new)
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                    expect(subject.url_meta(u)[:state]).to eql(:dead)
         
     | 
| 
      
 197 
     | 
    
         
            +
                    sleep subject.resurrect_delay + 1
         
     | 
| 
      
 198 
     | 
    
         
            +
                    expect(subject.url_meta(u)[:state]).to eql(:alive)
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              describe "version tracking" do
         
     | 
| 
      
 204 
     | 
    
         
            +
                let(:initial_urls) { [
         
     | 
| 
      
 205 
     | 
    
         
            +
                  ::LogStash::Util::SafeURI.new("http://somehost:9200"),
         
     | 
| 
      
 206 
     | 
    
         
            +
                  ::LogStash::Util::SafeURI.new("http://otherhost:9201")
         
     | 
| 
      
 207 
     | 
    
         
            +
                ] }
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                before(:each) do
         
     | 
| 
      
 210 
     | 
    
         
            +
                  allow(subject).to receive(:perform_request_to_url).and_return(nil)
         
     | 
| 
      
 211 
     | 
    
         
            +
                  subject.start
         
     | 
| 
      
 212 
     | 
    
         
            +
                end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                it "picks the largest major version" do
         
     | 
| 
      
 215 
     | 
    
         
            +
                  expect(subject.maximum_seen_major_version).to eq(7)
         
     | 
| 
      
 216 
     | 
    
         
            +
                end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                context "if there are nodes with multiple major versions" do
         
     | 
| 
      
 219 
     | 
    
         
            +
                  let(:node_versions) { [ "0.0.0", "7.0.0" ] }
         
     | 
| 
      
 220 
     | 
    
         
            +
                  it "picks the largest major version" do
         
     | 
| 
      
 221 
     | 
    
         
            +
                    expect(subject.maximum_seen_major_version).to eq(7)
         
     | 
| 
      
 222 
     | 
    
         
            +
                  end
         
     | 
| 
      
 223 
     | 
    
         
            +
                end
         
     | 
| 
      
 224 
     | 
    
         
            +
              end
         
     | 
| 
      
 225 
     | 
    
         
            +
              describe "distribution checking" do
         
     | 
| 
      
 226 
     | 
    
         
            +
                before(:each) do
         
     | 
| 
      
 227 
     | 
    
         
            +
                  allow(subject).to receive(:health_check_request)
         
     | 
| 
      
 228 
     | 
    
         
            +
                end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                let(:options) do
         
     | 
| 
      
 231 
     | 
    
         
            +
                  super().merge(:distribution_checker => distribution_checker)
         
     | 
| 
      
 232 
     | 
    
         
            +
                end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                context 'when DistributionChecker#is_supported? returns false' do
         
     | 
| 
      
 235 
     | 
    
         
            +
                  let(:distribution_checker) { double('DistributionChecker', :is_supported? => false) }
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  it 'does not mark the URL as active' do
         
     | 
| 
      
 238 
     | 
    
         
            +
                    subject.update_initial_urls
         
     | 
| 
      
 239 
     | 
    
         
            +
                    expect(subject.alive_urls_count).to eq(0)
         
     | 
| 
      
 240 
     | 
    
         
            +
                  end
         
     | 
| 
      
 241 
     | 
    
         
            +
                end
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
                context 'when DistributionChecker#is_supported? returns true' do
         
     | 
| 
      
 244 
     | 
    
         
            +
                  let(:distribution_checker) { double('DistributionChecker', :is_supported? => true) }
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                  it 'marks the URL as active' do
         
     | 
| 
      
 247 
     | 
    
         
            +
                    subject.update_initial_urls
         
     | 
| 
      
 248 
     | 
    
         
            +
                    expect(subject.alive_urls_count).to eq(1)
         
     | 
| 
      
 249 
     | 
    
         
            +
                  end
         
     | 
| 
      
 250 
     | 
    
         
            +
                end
         
     | 
| 
      
 251 
     | 
    
         
            +
              end
         
     | 
| 
      
 252 
     | 
    
         
            +
              describe 'distribution checking with cluster output' do
         
     | 
| 
      
 253 
     | 
    
         
            +
                let(:options) do
         
     | 
| 
      
 254 
     | 
    
         
            +
                  super().merge(:distribution_checker => LogStash::Outputs::OpenSearch::DistributionChecker.new(logger))
         
     | 
| 
      
 255 
     | 
    
         
            +
                end
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                before(:each) do
         
     | 
| 
      
 258 
     | 
    
         
            +
                  allow(subject).to receive(:health_check_request)
         
     | 
| 
      
 259 
     | 
    
         
            +
                end
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                context 'when using opensearch' do
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
                  context "if cluster doesn't return a valid distribution" do
         
     | 
| 
      
 264 
     | 
    
         
            +
                    let(:get_distribution) { nil }
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
                    it 'marks the url as dead' do
         
     | 
| 
      
 267 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 268 
     | 
    
         
            +
                      expect(subject.alive_urls_count).to eq(0)
         
     | 
| 
      
 269 
     | 
    
         
            +
                    end
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
                    it 'logs message' do
         
     | 
| 
      
 272 
     | 
    
         
            +
                      expect(subject.distribution_checker).to receive(:log_not_supported).once.and_call_original
         
     | 
| 
      
 273 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 274 
     | 
    
         
            +
                    end
         
     | 
| 
      
 275 
     | 
    
         
            +
                  end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                  context 'if cluster returns opensearch' do
         
     | 
| 
      
 278 
     | 
    
         
            +
                    let(:get_distribution) { 'opensearch' }
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                    it "marks the url as active" do
         
     | 
| 
      
 281 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 282 
     | 
    
         
            +
                      expect(subject.alive_urls_count).to eq(1)
         
     | 
| 
      
 283 
     | 
    
         
            +
                    end
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
      
 285 
     | 
    
         
            +
                    it 'does not log message' do
         
     | 
| 
      
 286 
     | 
    
         
            +
                      expect(subject.distribution_checker).to_not receive(:log_not_supported)
         
     | 
| 
      
 287 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 288 
     | 
    
         
            +
                    end
         
     | 
| 
      
 289 
     | 
    
         
            +
                  end
         
     | 
| 
      
 290 
     | 
    
         
            +
             
     | 
| 
      
 291 
     | 
    
         
            +
                  context 'if cluster returns oss' do
         
     | 
| 
      
 292 
     | 
    
         
            +
                    let(:get_distribution) { 'oss' }
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                    it 'marks the url as active' do
         
     | 
| 
      
 295 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 296 
     | 
    
         
            +
                      expect(subject.alive_urls_count).to eq(1)
         
     | 
| 
      
 297 
     | 
    
         
            +
                    end
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
                    it 'does not log message' do
         
     | 
| 
      
 300 
     | 
    
         
            +
                      expect(subject.distribution_checker).to_not receive(:log_not_supported)
         
     | 
| 
      
 301 
     | 
    
         
            +
                      subject.update_initial_urls
         
     | 
| 
      
 302 
     | 
    
         
            +
                    end
         
     | 
| 
      
 303 
     | 
    
         
            +
                  end
         
     | 
| 
      
 304 
     | 
    
         
            +
                end
         
     | 
| 
      
 305 
     | 
    
         
            +
              end
         
     | 
| 
      
 306 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,292 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # SPDX-License-Identifier: Apache-2.0
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            #  The OpenSearch Contributors require contributions made to
         
     | 
| 
      
 4 
     | 
    
         
            +
            #  this file be licensed under the Apache-2.0 license or a
         
     | 
| 
      
 5 
     | 
    
         
            +
            #  compatible open source license.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            #  Modifications Copyright OpenSearch Contributors. See
         
     | 
| 
      
 8 
     | 
    
         
            +
            #  GitHub history for details.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative "../../../../spec/spec_helper"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "logstash/outputs/opensearch/http_client"
         
     | 
| 
      
 12 
     | 
    
         
            +
            require "cabin"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            describe LogStash::Outputs::OpenSearch::HttpClient do
         
     | 
| 
      
 15 
     | 
    
         
            +
              let(:ssl) { nil }
         
     | 
| 
      
 16 
     | 
    
         
            +
              let(:base_options) do
         
     | 
| 
      
 17 
     | 
    
         
            +
                opts = {
         
     | 
| 
      
 18 
     | 
    
         
            +
                  :hosts => [::LogStash::Util::SafeURI.new("127.0.0.1")],
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :logger => Cabin::Channel.get,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :metric => ::LogStash::Instrument::NullMetric.new(:dummy).namespace(:alsodummy)
         
     | 
| 
      
 21 
     | 
    
         
            +
                }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                if !ssl.nil? # Shortcut to set this
         
     | 
| 
      
 24 
     | 
    
         
            +
                  opts[:client_settings] = {:ssl => {:enabled => ssl}}
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                opts
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              describe "Host/URL Parsing" do
         
     | 
| 
      
 31 
     | 
    
         
            +
                subject { described_class.new(base_options) }
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                let(:true_hostname) { "my-dash.hostname" }
         
     | 
| 
      
 34 
     | 
    
         
            +
                let(:ipv6_hostname) { "[::1]" }
         
     | 
| 
      
 35 
     | 
    
         
            +
                let(:ipv4_hostname) { "127.0.0.1" }
         
     | 
| 
      
 36 
     | 
    
         
            +
                let(:port) { 9202 }
         
     | 
| 
      
 37 
     | 
    
         
            +
                let(:hostname_port) { "#{hostname}:#{port}" }
         
     | 
| 
      
 38 
     | 
    
         
            +
                let(:hostname_port_uri) { ::LogStash::Util::SafeURI.new("//#{hostname_port}") }
         
     | 
| 
      
 39 
     | 
    
         
            +
                let(:http_hostname_port) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}") }
         
     | 
| 
      
 40 
     | 
    
         
            +
                let(:https_hostname_port) { ::LogStash::Util::SafeURI.new("https://#{hostname_port}") }
         
     | 
| 
      
 41 
     | 
    
         
            +
                let(:http_hostname_port_path) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}/path") }
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                shared_examples("proper host handling") do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  it "should properly transform a host:port string to a URL" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    expect(subject.host_to_url(hostname_port_uri).to_s).to eq(http_hostname_port.to_s + "/")
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  it "should not raise an error with a / for a path" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                    expect(subject.host_to_url(::LogStash::Util::SafeURI.new("#{http_hostname_port}/"))).to eq(LogStash::Util::SafeURI.new("#{http_hostname_port}/"))
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  it "should parse full URLs correctly" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                    expect(subject.host_to_url(http_hostname_port).to_s).to eq(http_hostname_port.to_s + "/")
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  describe "ssl" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                    context "when SSL is true" do
         
     | 
| 
      
 58 
     | 
    
         
            +
                      let(:ssl) { true }
         
     | 
| 
      
 59 
     | 
    
         
            +
                      let(:base_options) { super().merge(:hosts => [http_hostname_port]) }
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                      it "should refuse to handle an http url" do
         
     | 
| 
      
 62 
     | 
    
         
            +
                        expect {
         
     | 
| 
      
 63 
     | 
    
         
            +
                          subject.host_to_url(http_hostname_port)
         
     | 
| 
      
 64 
     | 
    
         
            +
                        }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    context "when SSL is false" do
         
     | 
| 
      
 69 
     | 
    
         
            +
                      let(:ssl) { false }
         
     | 
| 
      
 70 
     | 
    
         
            +
                      let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
         
     | 
| 
      
 71 
     | 
    
         
            +
                      
         
     | 
| 
      
 72 
     | 
    
         
            +
                      it "should refuse to handle an https url" do
         
     | 
| 
      
 73 
     | 
    
         
            +
                        expect {
         
     | 
| 
      
 74 
     | 
    
         
            +
                          subject.host_to_url(https_hostname_port)
         
     | 
| 
      
 75 
     | 
    
         
            +
                        }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    describe "ssl is nil" do
         
     | 
| 
      
 80 
     | 
    
         
            +
                      let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
         
     | 
| 
      
 81 
     | 
    
         
            +
                      it "should handle an ssl url correctly when SSL is nil" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                        subject
         
     | 
| 
      
 83 
     | 
    
         
            +
                        expect(subject.host_to_url(https_hostname_port).to_s).to eq(https_hostname_port.to_s + "/")
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end       
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  describe "path" do
         
     | 
| 
      
 89 
     | 
    
         
            +
                    let(:url) { http_hostname_port_path }
         
     | 
| 
      
 90 
     | 
    
         
            +
                    let(:base_options) { super().merge(:hosts => [url]) }
         
     | 
| 
      
 91 
     | 
    
         
            +
                    
         
     | 
| 
      
 92 
     | 
    
         
            +
                    it "should allow paths in a url" do
         
     | 
| 
      
 93 
     | 
    
         
            +
                      expect(subject.host_to_url(url)).to eq(url)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    context "with the path option set" do
         
     | 
| 
      
 97 
     | 
    
         
            +
                      let(:base_options) { super().merge(:client_settings => {:path => "/otherpath"}) }
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                      it "should not allow paths in two places" do
         
     | 
| 
      
 100 
     | 
    
         
            +
                        expect {
         
     | 
| 
      
 101 
     | 
    
         
            +
                          subject.host_to_url(url)
         
     | 
| 
      
 102 
     | 
    
         
            +
                        }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                    
         
     | 
| 
      
 106 
     | 
    
         
            +
                    context "with a path missing a leading /" do
         
     | 
| 
      
 107 
     | 
    
         
            +
                      let(:url) { http_hostname_port }
         
     | 
| 
      
 108 
     | 
    
         
            +
                      let(:base_options) { super().merge(:client_settings => {:path => "otherpath"}) }
         
     | 
| 
      
 109 
     | 
    
         
            +
                      
         
     | 
| 
      
 110 
     | 
    
         
            +
                      
         
     | 
| 
      
 111 
     | 
    
         
            +
                      it "should automatically insert a / in front of path overlays" do
         
     | 
| 
      
 112 
     | 
    
         
            +
                        expected = url.clone
         
     | 
| 
      
 113 
     | 
    
         
            +
                        expected.path = url.path + "/otherpath"
         
     | 
| 
      
 114 
     | 
    
         
            +
                        expect(subject.host_to_url(url)).to eq(expected)
         
     | 
| 
      
 115 
     | 
    
         
            +
                      end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    end
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                describe "an regular hostname" do
         
     | 
| 
      
 121 
     | 
    
         
            +
                  let(:hostname) { true_hostname }
         
     | 
| 
      
 122 
     | 
    
         
            +
                  include_examples("proper host handling")
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                describe "an ipv4 host" do
         
     | 
| 
      
 126 
     | 
    
         
            +
                  let(:hostname) { ipv4_hostname }
         
     | 
| 
      
 127 
     | 
    
         
            +
                  include_examples("proper host handling")
         
     | 
| 
      
 128 
     | 
    
         
            +
                end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                describe "an ipv6 host" do
         
     | 
| 
      
 131 
     | 
    
         
            +
                  let(:hostname) { ipv6_hostname }
         
     | 
| 
      
 132 
     | 
    
         
            +
                  include_examples("proper host handling")
         
     | 
| 
      
 133 
     | 
    
         
            +
                end
         
     | 
| 
      
 134 
     | 
    
         
            +
              end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
              describe "get" do
         
     | 
| 
      
 137 
     | 
    
         
            +
                subject { described_class.new(base_options) }
         
     | 
| 
      
 138 
     | 
    
         
            +
                let(:body) { "foobar" }
         
     | 
| 
      
 139 
     | 
    
         
            +
                let(:path) { "/hello-id" }
         
     | 
| 
      
 140 
     | 
    
         
            +
                let(:get_response) {
         
     | 
| 
      
 141 
     | 
    
         
            +
                  double("response", :body => LogStash::Json::dump( { "body" => body }))
         
     | 
| 
      
 142 
     | 
    
         
            +
                }
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                it "returns the hash response" do
         
     | 
| 
      
 145 
     | 
    
         
            +
                  expect(subject.pool).to receive(:get).with(path, nil).and_return(get_response)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  expect(subject.get(path)["body"]).to eq(body)
         
     | 
| 
      
 147 
     | 
    
         
            +
                end
         
     | 
| 
      
 148 
     | 
    
         
            +
              end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              describe "index template" do
         
     | 
| 
      
 151 
     | 
    
         
            +
                subject { described_class.new(base_options) }
         
     | 
| 
      
 152 
     | 
    
         
            +
                let(:template_name) { "logstash" }
         
     | 
| 
      
 153 
     | 
    
         
            +
                let(:template) { {} }
         
     | 
| 
      
 154 
     | 
    
         
            +
                let(:get_response) {
         
     | 
| 
      
 155 
     | 
    
         
            +
                  double("response", :body => {})
         
     | 
| 
      
 156 
     | 
    
         
            +
                }
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                it "should call index template" do
         
     | 
| 
      
 159 
     | 
    
         
            +
                  expect(subject.pool).to receive(:put).with("_template/#{template_name}", nil, anything).and_return(get_response)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  subject.template_put(template_name, template)
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
              end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
              describe "join_bulk_responses" do
         
     | 
| 
      
 165 
     | 
    
         
            +
                subject { described_class.new(base_options) }
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                context "when items key is available" do
         
     | 
| 
      
 168 
     | 
    
         
            +
                  require "json"
         
     | 
| 
      
 169 
     | 
    
         
            +
                  let(:bulk_response) {
         
     | 
| 
      
 170 
     | 
    
         
            +
                    LogStash::Json.load ('[{
         
     | 
| 
      
 171 
     | 
    
         
            +
                      "items": [{
         
     | 
| 
      
 172 
     | 
    
         
            +
                        "delete": {
         
     | 
| 
      
 173 
     | 
    
         
            +
                          "_index":   "website",
         
     | 
| 
      
 174 
     | 
    
         
            +
                          "_type":    "blog",
         
     | 
| 
      
 175 
     | 
    
         
            +
                          "_id":      "123",
         
     | 
| 
      
 176 
     | 
    
         
            +
                          "_version": 2,
         
     | 
| 
      
 177 
     | 
    
         
            +
                          "status":   200,
         
     | 
| 
      
 178 
     | 
    
         
            +
                          "found":    true
         
     | 
| 
      
 179 
     | 
    
         
            +
                        }
         
     | 
| 
      
 180 
     | 
    
         
            +
                      }],
         
     | 
| 
      
 181 
     | 
    
         
            +
                      "errors": false
         
     | 
| 
      
 182 
     | 
    
         
            +
                    }]')
         
     | 
| 
      
 183 
     | 
    
         
            +
                  }
         
     | 
| 
      
 184 
     | 
    
         
            +
                  it "should be handled properly" do
         
     | 
| 
      
 185 
     | 
    
         
            +
                    s = subject.send(:join_bulk_responses, bulk_response)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    expect(s["errors"]).to be false
         
     | 
| 
      
 187 
     | 
    
         
            +
                    expect(s["items"].size).to be 1
         
     | 
| 
      
 188 
     | 
    
         
            +
                  end
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                context "when items key is not available" do
         
     | 
| 
      
 192 
     | 
    
         
            +
                  require "json"
         
     | 
| 
      
 193 
     | 
    
         
            +
                  let(:bulk_response) {
         
     | 
| 
      
 194 
     | 
    
         
            +
                    JSON.parse ('[{
         
     | 
| 
      
 195 
     | 
    
         
            +
                      "took": 4,
         
     | 
| 
      
 196 
     | 
    
         
            +
                      "errors": false
         
     | 
| 
      
 197 
     | 
    
         
            +
                    }]')
         
     | 
| 
      
 198 
     | 
    
         
            +
                  }
         
     | 
| 
      
 199 
     | 
    
         
            +
                  it "should be handled properly" do
         
     | 
| 
      
 200 
     | 
    
         
            +
                    s = subject.send(:join_bulk_responses, bulk_response)
         
     | 
| 
      
 201 
     | 
    
         
            +
                    expect(s["errors"]).to be false
         
     | 
| 
      
 202 
     | 
    
         
            +
                    expect(s["items"].size).to be 0
         
     | 
| 
      
 203 
     | 
    
         
            +
                  end
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
              describe "#bulk" do
         
     | 
| 
      
 208 
     | 
    
         
            +
                subject(:http_client) { described_class.new(base_options) }
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                require "json"
         
     | 
| 
      
 211 
     | 
    
         
            +
                let(:message) { "hey" }
         
     | 
| 
      
 212 
     | 
    
         
            +
                let(:actions) { [
         
     | 
| 
      
 213 
     | 
    
         
            +
                  ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message}],
         
     | 
| 
      
 214 
     | 
    
         
            +
                ]}
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                [true,false].each do |http_compression_enabled|
         
     | 
| 
      
 217 
     | 
    
         
            +
                  context "with `http_compression => #{http_compression_enabled}`" do
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
                    let(:base_options) { super().merge(:client_settings => {:http_compression => http_compression_enabled}) }
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    before(:each) do
         
     | 
| 
      
 222 
     | 
    
         
            +
                      if http_compression_enabled
         
     | 
| 
      
 223 
     | 
    
         
            +
                        expect(http_client).to receive(:gzip_writer).at_least(:once).and_call_original
         
     | 
| 
      
 224 
     | 
    
         
            +
                      else
         
     | 
| 
      
 225 
     | 
    
         
            +
                        expect(http_client).to_not receive(:gzip_writer)
         
     | 
| 
      
 226 
     | 
    
         
            +
                      end
         
     | 
| 
      
 227 
     | 
    
         
            +
                    end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                    context "if a message is over TARGET_BULK_BYTES" do
         
     | 
| 
      
 230 
     | 
    
         
            +
                      let(:target_bulk_bytes) { LogStash::Outputs::OpenSearch::TARGET_BULK_BYTES }
         
     | 
| 
      
 231 
     | 
    
         
            +
                      let(:message) { "a" * (target_bulk_bytes + 1) }
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                      it "should be handled properly" do
         
     | 
| 
      
 234 
     | 
    
         
            +
                        allow(subject).to receive(:join_bulk_responses)
         
     | 
| 
      
 235 
     | 
    
         
            +
                        expect(subject).to receive(:bulk_send).once do |data|
         
     | 
| 
      
 236 
     | 
    
         
            +
                          if !http_compression_enabled
         
     | 
| 
      
 237 
     | 
    
         
            +
                            expect(data.size).to be > target_bulk_bytes
         
     | 
| 
      
 238 
     | 
    
         
            +
                          else
         
     | 
| 
      
 239 
     | 
    
         
            +
                            expect(Zlib::gunzip(data.string).size).to be > target_bulk_bytes
         
     | 
| 
      
 240 
     | 
    
         
            +
                          end
         
     | 
| 
      
 241 
     | 
    
         
            +
                        end
         
     | 
| 
      
 242 
     | 
    
         
            +
                        s = subject.send(:bulk, actions)
         
     | 
| 
      
 243 
     | 
    
         
            +
                      end
         
     | 
| 
      
 244 
     | 
    
         
            +
                    end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                    context "with two messages" do
         
     | 
| 
      
 247 
     | 
    
         
            +
                      let(:message1) { "hey" }
         
     | 
| 
      
 248 
     | 
    
         
            +
                      let(:message2) { "you" }
         
     | 
| 
      
 249 
     | 
    
         
            +
                      let(:actions) { [
         
     | 
| 
      
 250 
     | 
    
         
            +
                        ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message1}],
         
     | 
| 
      
 251 
     | 
    
         
            +
                        ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message2}],
         
     | 
| 
      
 252 
     | 
    
         
            +
                      ]}
         
     | 
| 
      
 253 
     | 
    
         
            +
                      it "executes one bulk_send operation" do
         
     | 
| 
      
 254 
     | 
    
         
            +
                        allow(subject).to receive(:join_bulk_responses)
         
     | 
| 
      
 255 
     | 
    
         
            +
                        expect(subject).to receive(:bulk_send).once
         
     | 
| 
      
 256 
     | 
    
         
            +
                        s = subject.send(:bulk, actions)
         
     | 
| 
      
 257 
     | 
    
         
            +
                      end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                      context "if one exceeds TARGET_BULK_BYTES" do
         
     | 
| 
      
 260 
     | 
    
         
            +
                        let(:target_bulk_bytes) { LogStash::Outputs::OpenSearch::TARGET_BULK_BYTES }
         
     | 
| 
      
 261 
     | 
    
         
            +
                        let(:message1) { "a" * (target_bulk_bytes + 1) }
         
     | 
| 
      
 262 
     | 
    
         
            +
                        it "executes two bulk_send operations" do
         
     | 
| 
      
 263 
     | 
    
         
            +
                          allow(subject).to receive(:join_bulk_responses)
         
     | 
| 
      
 264 
     | 
    
         
            +
                          expect(subject).to receive(:bulk_send).twice
         
     | 
| 
      
 265 
     | 
    
         
            +
                          s = subject.send(:bulk, actions)
         
     | 
| 
      
 266 
     | 
    
         
            +
                        end
         
     | 
| 
      
 267 
     | 
    
         
            +
                      end
         
     | 
| 
      
 268 
     | 
    
         
            +
                    end
         
     | 
| 
      
 269 
     | 
    
         
            +
                   end
         
     | 
| 
      
 270 
     | 
    
         
            +
                 end
         
     | 
| 
      
 271 
     | 
    
         
            +
              end
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
              describe "sniffing" do
         
     | 
| 
      
 274 
     | 
    
         
            +
                let(:client) { LogStash::Outputs::OpenSearch::HttpClient.new(base_options.merge(client_opts)) }
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                context "with sniffing enabled" do
         
     | 
| 
      
 277 
     | 
    
         
            +
                  let(:client_opts) { {:sniffing => true, :sniffing_delay => 1 } }
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                  it "should start the sniffer" do
         
     | 
| 
      
 280 
     | 
    
         
            +
                    expect(client.pool.sniffing).to be_truthy
         
     | 
| 
      
 281 
     | 
    
         
            +
                  end
         
     | 
| 
      
 282 
     | 
    
         
            +
                end
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
                context "with sniffing disabled" do
         
     | 
| 
      
 285 
     | 
    
         
            +
                  let(:client_opts) { {:sniffing => false} }
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
                  it "should not start the sniffer" do
         
     | 
| 
      
 288 
     | 
    
         
            +
                    expect(client.pool.sniffing).to be_falsey
         
     | 
| 
      
 289 
     | 
    
         
            +
                  end
         
     | 
| 
      
 290 
     | 
    
         
            +
                end
         
     | 
| 
      
 291 
     | 
    
         
            +
              end
         
     | 
| 
      
 292 
     | 
    
         
            +
            end
         
     |