logstash-output-elasticsearch-test 10.3.0-x86_64-linux

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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +397 -0
  3. data/CONTRIBUTORS +33 -0
  4. data/Gemfile +15 -0
  5. data/LICENSE +13 -0
  6. data/NOTICE.TXT +5 -0
  7. data/README.md +106 -0
  8. data/docs/index.asciidoc +899 -0
  9. data/lib/logstash/outputs/elasticsearch/common.rb +441 -0
  10. data/lib/logstash/outputs/elasticsearch/common_configs.rb +167 -0
  11. data/lib/logstash/outputs/elasticsearch/default-ilm-policy.json +14 -0
  12. data/lib/logstash/outputs/elasticsearch/elasticsearch-template-es2x.json +95 -0
  13. data/lib/logstash/outputs/elasticsearch/elasticsearch-template-es5x.json +46 -0
  14. data/lib/logstash/outputs/elasticsearch/elasticsearch-template-es6x.json +45 -0
  15. data/lib/logstash/outputs/elasticsearch/elasticsearch-template-es7x.json +44 -0
  16. data/lib/logstash/outputs/elasticsearch/elasticsearch-template-es8x.json +44 -0
  17. data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +131 -0
  18. data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +495 -0
  19. data/lib/logstash/outputs/elasticsearch/http_client.rb +432 -0
  20. data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +159 -0
  21. data/lib/logstash/outputs/elasticsearch/ilm.rb +113 -0
  22. data/lib/logstash/outputs/elasticsearch/template_manager.rb +61 -0
  23. data/lib/logstash/outputs/elasticsearch.rb +263 -0
  24. data/logstash-output-elasticsearch.gemspec +33 -0
  25. data/spec/es_spec_helper.rb +189 -0
  26. data/spec/fixtures/_nodes/2x_1x.json +27 -0
  27. data/spec/fixtures/_nodes/5x_6x.json +81 -0
  28. data/spec/fixtures/_nodes/7x.json +92 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  31. data/spec/fixtures/scripts/groovy/scripted_update.groovy +2 -0
  32. data/spec/fixtures/scripts/groovy/scripted_update_nested.groovy +2 -0
  33. data/spec/fixtures/scripts/groovy/scripted_upsert.groovy +2 -0
  34. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  35. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  36. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  37. data/spec/fixtures/template-with-policy-es6x.json +48 -0
  38. data/spec/fixtures/template-with-policy-es7x.json +45 -0
  39. data/spec/fixtures/test_certs/ca/ca.crt +32 -0
  40. data/spec/fixtures/test_certs/ca/ca.key +51 -0
  41. data/spec/fixtures/test_certs/test.crt +36 -0
  42. data/spec/fixtures/test_certs/test.key +51 -0
  43. data/spec/integration/outputs/compressed_indexing_spec.rb +69 -0
  44. data/spec/integration/outputs/create_spec.rb +67 -0
  45. data/spec/integration/outputs/delete_spec.rb +65 -0
  46. data/spec/integration/outputs/groovy_update_spec.rb +150 -0
  47. data/spec/integration/outputs/ilm_spec.rb +531 -0
  48. data/spec/integration/outputs/index_spec.rb +178 -0
  49. data/spec/integration/outputs/index_version_spec.rb +102 -0
  50. data/spec/integration/outputs/ingest_pipeline_spec.rb +74 -0
  51. data/spec/integration/outputs/metrics_spec.rb +70 -0
  52. data/spec/integration/outputs/no_es_on_startup_spec.rb +58 -0
  53. data/spec/integration/outputs/painless_update_spec.rb +189 -0
  54. data/spec/integration/outputs/parent_spec.rb +102 -0
  55. data/spec/integration/outputs/retry_spec.rb +169 -0
  56. data/spec/integration/outputs/routing_spec.rb +61 -0
  57. data/spec/integration/outputs/sniffer_spec.rb +133 -0
  58. data/spec/integration/outputs/templates_5x_spec.rb +98 -0
  59. data/spec/integration/outputs/templates_spec.rb +98 -0
  60. data/spec/integration/outputs/update_spec.rb +116 -0
  61. data/spec/support/elasticsearch/api/actions/delete_ilm_policy.rb +19 -0
  62. data/spec/support/elasticsearch/api/actions/get_alias.rb +18 -0
  63. data/spec/support/elasticsearch/api/actions/get_ilm_policy.rb +18 -0
  64. data/spec/support/elasticsearch/api/actions/put_alias.rb +24 -0
  65. data/spec/support/elasticsearch/api/actions/put_ilm_policy.rb +25 -0
  66. data/spec/unit/http_client_builder_spec.rb +185 -0
  67. data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +149 -0
  68. data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +274 -0
  69. data/spec/unit/outputs/elasticsearch/http_client_spec.rb +250 -0
  70. data/spec/unit/outputs/elasticsearch/template_manager_spec.rb +25 -0
  71. data/spec/unit/outputs/elasticsearch_proxy_spec.rb +72 -0
  72. data/spec/unit/outputs/elasticsearch_spec.rb +675 -0
  73. data/spec/unit/outputs/elasticsearch_ssl_spec.rb +82 -0
  74. data/spec/unit/outputs/error_whitelist_spec.rb +54 -0
  75. metadata +300 -0
@@ -0,0 +1,116 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+
3
+ if ESHelper.es_version_satisfies?(">= 2")
4
+ describe "Update actions without scripts", :integration => true do
5
+ require "logstash/outputs/elasticsearch"
6
+
7
+ def get_es_output( options={} )
8
+ settings = {
9
+ "manage_template" => true,
10
+ "index" => "logstash-update",
11
+ "template_overwrite" => true,
12
+ "hosts" => get_host_port(),
13
+ "action" => "update"
14
+ }
15
+ LogStash::Outputs::ElasticSearch.new(settings.merge!(options))
16
+ end
17
+
18
+ before :each do
19
+ @es = get_client
20
+ # Delete all templates first.
21
+ # Clean ES of data before we start.
22
+ @es.indices.delete_template(:name => "*")
23
+ # This can fail if there are no indexes, ignore failure.
24
+ @es.indices.delete(:index => "*") rescue nil
25
+ @es.index(
26
+ :index => 'logstash-update',
27
+ :type => doc_type,
28
+ :id => "123",
29
+ :body => { :message => 'Test', :counter => 1 }
30
+ )
31
+ @es.indices.refresh
32
+ end
33
+
34
+ it "should fail without a document_id" do
35
+ subject = get_es_output
36
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
37
+ end
38
+
39
+ context "when update only" do
40
+ it "should not create new document" do
41
+ subject = get_es_output({ 'document_id' => "456" } )
42
+ subject.register
43
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
44
+ expect {@es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
45
+ end
46
+
47
+ it "should update existing document" do
48
+ subject = get_es_output({ 'document_id' => "123" })
49
+ subject.register
50
+ subject.multi_receive([LogStash::Event.new("message" => "updated message here")])
51
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
52
+ expect(r["_source"]["message"]).to eq('updated message here')
53
+ end
54
+
55
+ # The es ruby client treats the data field differently. Make sure this doesn't
56
+ # raise an exception
57
+ it "should update an existing document that has a 'data' field" do
58
+ subject = get_es_output({ 'document_id' => "123" })
59
+ subject.register
60
+ subject.multi_receive([LogStash::Event.new("data" => "updated message here", "message" => "foo")])
61
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "123", :refresh => true)
62
+ expect(r["_source"]["data"]).to eq('updated message here')
63
+ expect(r["_source"]["message"]).to eq('foo')
64
+ end
65
+
66
+ it "should allow default (internal) version" do
67
+ subject = get_es_output({ 'document_id' => "123", "version" => "99" })
68
+ subject.register
69
+ end
70
+
71
+ it "should allow internal version" do
72
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "internal" })
73
+ subject.register
74
+ end
75
+
76
+ it "should not allow external version" do
77
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external" })
78
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
79
+ end
80
+
81
+ it "should not allow external_gt version" do
82
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gt" })
83
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
84
+ end
85
+
86
+ it "should not allow external_gte version" do
87
+ subject = get_es_output({ 'document_id' => "123", "version" => "99", "version_type" => "external_gte" })
88
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
89
+ end
90
+
91
+ end
92
+
93
+ context "when update with upsert" do
94
+ it "should create new documents with provided upsert" do
95
+ subject = get_es_output({ 'document_id' => "456", 'upsert' => '{"message": "upsert message"}' })
96
+ subject.register
97
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
98
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
99
+ expect(r["_source"]["message"]).to eq('upsert message')
100
+ end
101
+
102
+ it "should create new documents with event/doc as upsert" do
103
+ subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true })
104
+ subject.register
105
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
106
+ r = @es.get(:index => 'logstash-update', :type => doc_type, :id => "456", :refresh => true)
107
+ expect(r["_source"]["message"]).to eq('sample message here')
108
+ end
109
+
110
+ it "should fail on documents with event/doc as upsert at external version" do
111
+ subject = get_es_output({ 'document_id' => "456", 'doc_as_upsert' => true, 'version' => 999, "version_type" => "external" })
112
+ expect { subject.register }.to raise_error(LogStash::ConfigurationError)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Update the password of the specified user
10
+ def delete_ilm_policy(arguments={})
11
+ method = HTTP_DELETE
12
+ path = Utils.__pathify '_ilm/policy/',
13
+ Utils.__escape(arguments[:name])
14
+ params = {}
15
+ perform_request(method, path, params, nil).body
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Retrieve the list of index lifecycle management policies
10
+ def get_alias(arguments={})
11
+ method = HTTP_GET
12
+ path = Utils.__pathify '_alias', Utils.__escape(arguments[:name])
13
+ params = {}
14
+ perform_request(method, path, params, nil).body
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # Retrieve the list of index lifecycle management policies
10
+ def get_ilm_policy(arguments={})
11
+ method = HTTP_GET
12
+ path = Utils.__pathify '_ilm/policy', Utils.__escape(arguments[:name])
13
+ params = {}
14
+ perform_request(method, path, params, nil).body
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # @option arguments [String] :name The name of the alias (*Required*)
10
+ # @option arguments [Hash] :The alias definition(*Required*)
11
+
12
+ def put_alias(arguments={})
13
+ raise ArgumentError, "Required argument 'name' missing" unless arguments[:name]
14
+ raise ArgumentError, "Required argument 'body' missing" unless arguments[:body]
15
+ method = HTTP_PUT
16
+ path = Utils.__pathify Utils.__escape(arguments[:name])
17
+
18
+ params = Utils.__validate_and_extract_params arguments
19
+ body = arguments[:body]
20
+ perform_request(method, path, params, body.to_json).body
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2
+ # or more contributor license agreements. Licensed under the Elastic License;
3
+ # you may not use this file except in compliance with the Elastic License.
4
+
5
+ module Elasticsearch
6
+ module API
7
+ module Actions
8
+
9
+ # @option arguments [String] :name The name of the policy (*Required*)
10
+ # @option arguments [Hash] :body The policy definition (*Required*)
11
+
12
+ def put_ilm_policy(arguments={})
13
+ raise ArgumentError, "Required argument 'name' missing" unless arguments[:name]
14
+ raise ArgumentError, "Required argument 'body' missing" unless arguments[:body]
15
+ method = HTTP_PUT
16
+ path = Utils.__pathify '_ilm/policy/', Utils.__escape(arguments[:name])
17
+
18
+ params = Utils.__validate_and_extract_params arguments
19
+
20
+ body = arguments[:body]
21
+ perform_request(method, path, params, body.to_json).body
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,185 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/outputs/elasticsearch"
3
+ require "logstash/outputs/elasticsearch/http_client"
4
+ require "logstash/outputs/elasticsearch/http_client_builder"
5
+
6
+ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
7
+ describe "auth setup with url encodable passwords" do
8
+ let(:klass) { LogStash::Outputs::ElasticSearch::HttpClientBuilder }
9
+ let(:user) { "foo@bar"}
10
+ let(:password) {"baz@blah" }
11
+ let(:password_secured) do
12
+ secured = double("password")
13
+ allow(secured).to receive(:value).and_return(password)
14
+ secured
15
+ end
16
+ let(:options) { {"user" => user, "password" => password} }
17
+ let(:logger) { mock("logger") }
18
+ let(:auth_setup) { klass.setup_basic_auth(double("logger"), {"user" => user, "password" => password_secured}) }
19
+
20
+ it "should return the user escaped" do
21
+ expect(auth_setup[:user]).to eql(CGI.escape(user))
22
+ end
23
+
24
+ it "should return the password escaped" do
25
+ expect(auth_setup[:password]).to eql(CGI.escape(password))
26
+ end
27
+ end
28
+
29
+ describe "customizing action paths" do
30
+ let(:hosts) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200") ] }
31
+ let(:options) { {"hosts" => hosts } }
32
+ let(:logger) { double("logger") }
33
+ before :each do
34
+ [:debug, :debug?, :info?, :info, :warn].each do |level|
35
+ allow(logger).to receive(level)
36
+ end
37
+ end
38
+
39
+ describe "healthcheck_path" do
40
+
41
+ context "when setting bulk_path" do
42
+ let(:bulk_path) { "/meh" }
43
+ let(:options) { super.merge("bulk_path" => bulk_path) }
44
+
45
+ context "when using path" do
46
+ let(:options) { super.merge("path" => "/path") }
47
+ it "ignores the path setting" do
48
+ expect(described_class).to receive(:create_http_client) do |options|
49
+ expect(options[:bulk_path]).to eq(bulk_path)
50
+ end
51
+ described_class.build(logger, hosts, options)
52
+ end
53
+ end
54
+ context "when not using path" do
55
+
56
+ it "uses the bulk_path setting" do
57
+ expect(described_class).to receive(:create_http_client) do |options|
58
+ expect(options[:bulk_path]).to eq(bulk_path)
59
+ end
60
+ described_class.build(logger, hosts, options)
61
+ end
62
+ end
63
+ end
64
+
65
+ context "when not setting bulk_path" do
66
+
67
+ context "when using path" do
68
+ let(:path) { "/meh" }
69
+ let(:options) { super.merge("path" => path) }
70
+ it "sets bulk_path to path+_bulk" do
71
+ expect(described_class).to receive(:create_http_client) do |options|
72
+ expect(options[:bulk_path]).to eq("#{path}/_bulk")
73
+ end
74
+ described_class.build(logger, hosts, options)
75
+ end
76
+ end
77
+
78
+ context "when not using path" do
79
+ it "sets the bulk_path to _bulk" do
80
+ expect(described_class).to receive(:create_http_client) do |options|
81
+ expect(options[:bulk_path]).to eq("/_bulk")
82
+ end
83
+ described_class.build(logger, hosts, options)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ describe "healthcheck_path" do
89
+ context "when setting healthcheck_path" do
90
+ let(:healthcheck_path) { "/meh" }
91
+ let(:options) { super.merge("healthcheck_path" => healthcheck_path) }
92
+
93
+ context "when using path" do
94
+ let(:options) { super.merge("path" => "/path") }
95
+ it "ignores the path setting" do
96
+ expect(described_class).to receive(:create_http_client) do |options|
97
+ expect(options[:healthcheck_path]).to eq(healthcheck_path)
98
+ end
99
+ described_class.build(logger, hosts, options)
100
+ end
101
+ end
102
+ context "when not using path" do
103
+
104
+ it "uses the healthcheck_path setting" do
105
+ expect(described_class).to receive(:create_http_client) do |options|
106
+ expect(options[:healthcheck_path]).to eq(healthcheck_path)
107
+ end
108
+ described_class.build(logger, hosts, options)
109
+ end
110
+ end
111
+ end
112
+
113
+ context "when not setting healthcheck_path" do
114
+
115
+ context "when using path" do
116
+ let(:path) { "/meh" }
117
+ let(:options) { super.merge("path" => path) }
118
+ it "sets healthcheck_path to path" do
119
+ expect(described_class).to receive(:create_http_client) do |options|
120
+ expect(options[:healthcheck_path]).to eq(path)
121
+ end
122
+ described_class.build(logger, hosts, options)
123
+ end
124
+ end
125
+
126
+ context "when not using path" do
127
+ it "sets the healthcheck_path to root" do
128
+ expect(described_class).to receive(:create_http_client) do |options|
129
+ expect(options[:healthcheck_path]).to eq("/")
130
+ end
131
+ described_class.build(logger, hosts, options)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ describe "sniffing_path" do
137
+ context "when setting sniffing_path" do
138
+ let(:sniffing_path) { "/meh" }
139
+ let(:options) { super.merge("sniffing_path" => sniffing_path) }
140
+
141
+ context "when using path" do
142
+ let(:options) { super.merge("path" => "/path") }
143
+ it "ignores the path setting" do
144
+ expect(described_class).to receive(:create_http_client) do |options|
145
+ expect(options[:sniffing_path]).to eq(sniffing_path)
146
+ end
147
+ described_class.build(logger, hosts, options)
148
+ end
149
+ end
150
+ context "when not using path" do
151
+
152
+ it "uses the sniffing_path setting" do
153
+ expect(described_class).to receive(:create_http_client) do |options|
154
+ expect(options[:sniffing_path]).to eq(sniffing_path)
155
+ end
156
+ described_class.build(logger, hosts, options)
157
+ end
158
+ end
159
+ end
160
+
161
+ context "when not setting sniffing_path" do
162
+
163
+ context "when using path" do
164
+ let(:path) { "/meh" }
165
+ let(:options) { super.merge("path" => path) }
166
+ it "sets sniffing_path to path+_nodes/http" do
167
+ expect(described_class).to receive(:create_http_client) do |options|
168
+ expect(options[:sniffing_path]).to eq("#{path}/_nodes/http")
169
+ end
170
+ described_class.build(logger, hosts, options)
171
+ end
172
+ end
173
+
174
+ context "when not using path" do
175
+ it "sets the sniffing_path to _nodes/http" do
176
+ expect(described_class).to receive(:create_http_client) do |options|
177
+ expect(options[:sniffing_path]).to eq("/_nodes/http")
178
+ end
179
+ described_class.build(logger, hosts, options)
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,149 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/outputs/elasticsearch/http_client"
3
+
4
+ describe LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter do
5
+ let(:logger) { Cabin::Channel.get }
6
+ let(:options) { {} }
7
+
8
+ subject { described_class.new(logger, options) }
9
+
10
+ it "should raise an exception if requests are issued after close" do
11
+ subject.close
12
+ expect { subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, '/') }.to raise_error(::Manticore::ClientStoppedException)
13
+ end
14
+
15
+ it "should implement host unreachable exceptions" do
16
+ expect(subject.host_unreachable_exceptions).to be_a(Array)
17
+ end
18
+
19
+ describe "auth" do
20
+ let(:user) { "myuser" }
21
+ let(:password) { "mypassword" }
22
+ let(:noauth_uri) { clone = uri.clone; clone.user=nil; clone.password=nil; clone }
23
+ let(:uri) { ::LogStash::Util::SafeURI.new("http://#{user}:#{password}@localhost:9200") }
24
+
25
+ it "should convert the auth to params" do
26
+ resp = double("response")
27
+ allow(resp).to receive(:call)
28
+ allow(resp).to receive(:code).and_return(200)
29
+
30
+ expected_uri = noauth_uri.clone
31
+ expected_uri.path = "/"
32
+
33
+ expect(subject.manticore).to receive(:get).
34
+ with(expected_uri.to_s, {
35
+ :headers => {"Content-Type" => "application/json"},
36
+ :auth => {
37
+ :user => user,
38
+ :password => password,
39
+ :eager => true
40
+ }
41
+ }).and_return resp
42
+
43
+ subject.perform_request(uri, :get, "/")
44
+ end
45
+ end
46
+
47
+ describe "bad response codes" do
48
+ let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
49
+
50
+ it "should raise a bad response code error" do
51
+ resp = double("response")
52
+ allow(resp).to receive(:call)
53
+ allow(resp).to receive(:code).and_return(500)
54
+ allow(resp).to receive(:body).and_return("a body")
55
+
56
+ expect(subject.manticore).to receive(:get).
57
+ with(uri.to_s + "/", anything).
58
+ and_return(resp)
59
+
60
+ uri_with_path = uri.clone
61
+ uri_with_path.path = "/"
62
+
63
+ expect(::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError).to receive(:new).
64
+ with(resp.code, uri_with_path, nil, resp.body).and_call_original
65
+
66
+ expect do
67
+ subject.perform_request(uri, :get, "/")
68
+ end.to raise_error(::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError)
69
+ end
70
+ end
71
+
72
+ describe "format_url" do
73
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200/path/") }
74
+ let(:path) { "_bulk" }
75
+ subject { described_class.new(double("logger"), {}) }
76
+
77
+ it "should add the path argument to the uri's path" do
78
+ expect(subject.format_url(url, path).path).to eq("/path/_bulk")
79
+ end
80
+
81
+ context "when uri contains query parameters" do
82
+ let(:query_params) { "query=value&key=value2" }
83
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200/path/?#{query_params}") }
84
+ let(:formatted) { subject.format_url(url, path)}
85
+
86
+ it "should retain query_params after format" do
87
+ expect(formatted.query).to eq(query_params)
88
+ end
89
+
90
+ context "and the path contains query parameters" do
91
+ let(:path) { "/special_path?specialParam=123" }
92
+
93
+ it "should join the query correctly" do
94
+ expect(formatted.query).to eq(query_params + "&specialParam=123")
95
+ end
96
+ end
97
+ end
98
+
99
+ context "when the path contains query parameters" do
100
+ let(:path) { "/special_bulk?pathParam=1"}
101
+ let(:formatted) { subject.format_url(url, path) }
102
+
103
+ it "should add the path correctly" do
104
+ expect(formatted.path).to eq("#{url.path}special_bulk")
105
+ expect(subject.remove_double_escaping(formatted.path)).to eq("#{url.path}special_bulk")
106
+ end
107
+
108
+ it "should add the query parameters correctly" do
109
+ expect(formatted.query).to eq("pathParam=1")
110
+ end
111
+ end
112
+
113
+ context "when uri contains credentials" do
114
+ let(:url) { ::LogStash::Util::SafeURI.new("http://myuser:mypass@localhost:9200") }
115
+ let(:formatted) { subject.format_url(url, path) }
116
+
117
+ it "should remove credentials after format" do
118
+ expect(formatted.userinfo).to be_nil
119
+ end
120
+ end
121
+
122
+ context 'when uri contains date math' do
123
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
124
+ let(:path) { CGI.escape("<logstash-{now/d}-0001>") }
125
+ let(:formatted) { subject.format_url(url, path) }
126
+
127
+ it 'should escape the uri correctly' do
128
+ expect(subject.remove_double_escaping(formatted.path)).to eq("/%3Clogstash-%7Bnow%2Fd%7D-0001%3E")
129
+ end
130
+ end
131
+
132
+ context 'when uri does not contain date math' do
133
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
134
+ let(:path) { CGI.escape("logstash-0001") }
135
+ let(:formatted) { subject.format_url(url, path) }
136
+
137
+ it 'should escape the uri correctly' do
138
+ expect(subject.remove_double_escaping(formatted.path)).to eq("/logstash-0001")
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "integration specs", :integration => true do
144
+ it "should perform correct tests without error" do
145
+ resp = subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, "/")
146
+ expect(resp.code).to eql(200)
147
+ end
148
+ end
149
+ end