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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ADMINS.md +29 -0
  5. data/CODE_OF_CONDUCT.md +25 -0
  6. data/CONTRIBUTING.md +99 -0
  7. data/DEVELOPER_GUIDE.md +208 -0
  8. data/Gemfile +20 -0
  9. data/LICENSE +202 -0
  10. data/MAINTAINERS.md +71 -0
  11. data/NOTICE +2 -0
  12. data/README.md +37 -0
  13. data/RELEASING.md +36 -0
  14. data/SECURITY.md +3 -0
  15. data/lib/logstash/outputs/opensearch.rb +449 -0
  16. data/lib/logstash/outputs/opensearch/distribution_checker.rb +44 -0
  17. data/lib/logstash/outputs/opensearch/http_client.rb +465 -0
  18. data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +140 -0
  19. data/lib/logstash/outputs/opensearch/http_client/pool.rb +467 -0
  20. data/lib/logstash/outputs/opensearch/http_client_builder.rb +182 -0
  21. data/lib/logstash/outputs/opensearch/template_manager.rb +60 -0
  22. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x.json +44 -0
  23. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x.json +44 -0
  24. data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +168 -0
  25. data/lib/logstash/plugin_mixins/opensearch/common.rb +294 -0
  26. data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +18 -0
  27. data/logstash-output-opensearch.gemspec +40 -0
  28. data/spec/fixtures/_nodes/nodes.json +74 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  31. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  32. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  33. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  34. data/spec/integration/outputs/compressed_indexing_spec.rb +76 -0
  35. data/spec/integration/outputs/create_spec.rb +76 -0
  36. data/spec/integration/outputs/delete_spec.rb +72 -0
  37. data/spec/integration/outputs/index_spec.rb +164 -0
  38. data/spec/integration/outputs/index_version_spec.rb +110 -0
  39. data/spec/integration/outputs/ingest_pipeline_spec.rb +82 -0
  40. data/spec/integration/outputs/metrics_spec.rb +75 -0
  41. data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +67 -0
  42. data/spec/integration/outputs/painless_update_spec.rb +147 -0
  43. data/spec/integration/outputs/parent_spec.rb +103 -0
  44. data/spec/integration/outputs/retry_spec.rb +182 -0
  45. data/spec/integration/outputs/routing_spec.rb +70 -0
  46. data/spec/integration/outputs/sniffer_spec.rb +70 -0
  47. data/spec/integration/outputs/templates_spec.rb +105 -0
  48. data/spec/integration/outputs/update_spec.rb +123 -0
  49. data/spec/opensearch_spec_helper.rb +141 -0
  50. data/spec/spec_helper.rb +19 -0
  51. data/spec/unit/http_client_builder_spec.rb +194 -0
  52. data/spec/unit/outputs/error_whitelist_spec.rb +62 -0
  53. data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +159 -0
  54. data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +306 -0
  55. data/spec/unit/outputs/opensearch/http_client_spec.rb +292 -0
  56. data/spec/unit/outputs/opensearch/template_manager_spec.rb +36 -0
  57. data/spec/unit/outputs/opensearch_proxy_spec.rb +112 -0
  58. data/spec/unit/outputs/opensearch_spec.rb +800 -0
  59. data/spec/unit/outputs/opensearch_ssl_spec.rb +179 -0
  60. metadata +289 -0
  61. metadata.gz.sig +0 -0
@@ -0,0 +1,141 @@
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_helper'
11
+
12
+ require 'elasticsearch'
13
+
14
+ require 'json'
15
+ require 'cabin'
16
+
17
+ module OpenSearchHelper
18
+ def get_host_port
19
+ if ENV["INTEGRATION"] == "true"
20
+ "integration:9200"
21
+ else
22
+ "localhost:9200"
23
+ end
24
+ end
25
+
26
+ def get_client
27
+ Elasticsearch::Client.new(:hosts => [get_host_port])
28
+ end
29
+
30
+ def doc_type
31
+ "_doc"
32
+ end
33
+
34
+ def todays_date
35
+ Time.now.strftime("%Y.%m.%d")
36
+ end
37
+
38
+ def field_properties_from_template(template_name, field)
39
+ template = get_template(@client, template_name)
40
+ mappings = get_template_mappings(template)
41
+ mappings["properties"][field]["properties"]
42
+ end
43
+
44
+ def routing_field_name
45
+ :routing
46
+ end
47
+
48
+ def self.version
49
+ RSpec.configuration.filter[:version]
50
+ end
51
+
52
+ RSpec::Matchers.define :have_hits do |expected|
53
+ match do |actual|
54
+ expected == actual['hits']['total']['value']
55
+ end
56
+ end
57
+
58
+ RSpec::Matchers.define :have_index_pattern do |expected|
59
+ match do |actual|
60
+ test_against = Array(actual['index_patterns'].nil? ? actual['template'] : actual['index_patterns'])
61
+ test_against.include?(expected)
62
+ end
63
+ end
64
+
65
+ def clean(client)
66
+ client.indices.delete_template(:name => "*")
67
+ client.indices.delete_index_template(:name => "logstash*") rescue nil
68
+ # This can fail if there are no indexes, ignore failure.
69
+ client.indices.delete(:index => "*") rescue nil
70
+ end
71
+
72
+ def set_cluster_settings(client, cluster_settings)
73
+ client.cluster.put_settings(body: cluster_settings)
74
+ get_cluster_settings(client)
75
+ end
76
+
77
+ def get_cluster_settings(client)
78
+ client.cluster.get_settings
79
+ end
80
+
81
+ def put_alias(client, the_alias, index)
82
+ body = {
83
+ "aliases" => {
84
+ index => {
85
+ "is_write_index"=> true
86
+ }
87
+ }
88
+ }
89
+ client.put_alias({name: the_alias, body: body})
90
+ end
91
+
92
+ def max_docs_policy(max_docs)
93
+ {
94
+ "policy" => {
95
+ "phases"=> {
96
+ "hot" => {
97
+ "actions" => {
98
+ "rollover" => {
99
+ "max_docs" => max_docs
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ end
107
+
108
+ def max_age_policy(max_age)
109
+ {
110
+ "policy" => {
111
+ "phases"=> {
112
+ "hot" => {
113
+ "actions" => {
114
+ "rollover" => {
115
+ "max_age" => max_age
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ end
123
+
124
+ def get_template(client, name)
125
+ t = client.indices.get_template(name: name)
126
+ # TODO: use index template if version >= 7.8 & OpenSearch
127
+ t[name]
128
+ end
129
+
130
+ def get_template_settings(template)
131
+ template['template']
132
+ end
133
+
134
+ def get_template_mappings(template)
135
+ template['mappings']
136
+ end
137
+ end
138
+
139
+ RSpec.configure do |config|
140
+ config.include OpenSearchHelper
141
+ end
@@ -0,0 +1,19 @@
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
+
12
+ require "logstash/outputs/opensearch"
13
+
14
+ module LogStash::Outputs::OpenSearch::SpecHelper
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.include LogStash::Outputs::OpenSearch::SpecHelper
19
+ end
@@ -0,0 +1,194 @@
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"
12
+ require "logstash/outputs/opensearch/http_client"
13
+ require "logstash/outputs/opensearch/http_client_builder"
14
+
15
+ describe LogStash::Outputs::OpenSearch::HttpClientBuilder do
16
+ describe "auth setup with url encodable passwords" do
17
+ let(:klass) { LogStash::Outputs::OpenSearch::HttpClientBuilder }
18
+ let(:user) { "foo@bar"}
19
+ let(:password) {"baz@blah" }
20
+ let(:password_secured) do
21
+ secured = double("password")
22
+ allow(secured).to receive(:value).and_return(password)
23
+ secured
24
+ end
25
+ let(:options) { {"user" => user, "password" => password} }
26
+ let(:logger) { mock("logger") }
27
+ let(:auth_setup) { klass.setup_basic_auth(double("logger"), {"user" => user, "password" => password_secured}) }
28
+
29
+ it "should return the user escaped" do
30
+ expect(auth_setup[:user]).to eql(CGI.escape(user))
31
+ end
32
+
33
+ it "should return the password escaped" do
34
+ expect(auth_setup[:password]).to eql(CGI.escape(password))
35
+ end
36
+ end
37
+
38
+ describe "customizing action paths" do
39
+ let(:hosts) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200") ] }
40
+ let(:options) { {"hosts" => hosts } }
41
+ let(:logger) { double("logger") }
42
+ before :each do
43
+ [:debug, :debug?, :info?, :info, :warn].each do |level|
44
+ allow(logger).to receive(level)
45
+ end
46
+ end
47
+
48
+ describe "healthcheck_path" do
49
+
50
+ context "when setting bulk_path" do
51
+ let(:bulk_path) { "/meh" }
52
+ let(:options) { super().merge("bulk_path" => bulk_path) }
53
+
54
+ context "when using path" do
55
+ let(:options) { super().merge("path" => "/path") }
56
+ it "ignores the 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
+ context "when not using path" do
64
+
65
+ it "uses the bulk_path setting" do
66
+ expect(described_class).to receive(:create_http_client) do |options|
67
+ expect(options[:bulk_path]).to eq(bulk_path)
68
+ end
69
+ described_class.build(logger, hosts, options)
70
+ end
71
+ end
72
+ end
73
+
74
+ context "when not setting bulk_path" do
75
+
76
+ context "when using path" do
77
+ let(:path) { "/meh" }
78
+ let(:options) { super().merge("path" => path) }
79
+ it "sets bulk_path to path+_bulk" do
80
+ expect(described_class).to receive(:create_http_client) do |options|
81
+ expect(options[:bulk_path]).to eq("#{path}/_bulk")
82
+ end
83
+ described_class.build(logger, hosts, options)
84
+ end
85
+ end
86
+
87
+ context "when not using path" do
88
+ it "sets the bulk_path to _bulk" do
89
+ expect(described_class).to receive(:create_http_client) do |options|
90
+ expect(options[:bulk_path]).to eq("/_bulk")
91
+ end
92
+ described_class.build(logger, hosts, options)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ describe "healthcheck_path" do
98
+ context "when setting healthcheck_path" do
99
+ let(:healthcheck_path) { "/meh" }
100
+ let(:options) { super().merge("healthcheck_path" => healthcheck_path) }
101
+
102
+ context "when using path" do
103
+ let(:options) { super().merge("path" => "/path") }
104
+ it "ignores the 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
+ context "when not using path" do
112
+
113
+ it "uses the healthcheck_path setting" do
114
+ expect(described_class).to receive(:create_http_client) do |options|
115
+ expect(options[:healthcheck_path]).to eq(healthcheck_path)
116
+ end
117
+ described_class.build(logger, hosts, options)
118
+ end
119
+ end
120
+ end
121
+
122
+ context "when not setting healthcheck_path" do
123
+
124
+ context "when using path" do
125
+ let(:path) { "/meh" }
126
+ let(:options) { super().merge("path" => path) }
127
+ it "sets healthcheck_path to path" do
128
+ expect(described_class).to receive(:create_http_client) do |options|
129
+ expect(options[:healthcheck_path]).to eq(path)
130
+ end
131
+ described_class.build(logger, hosts, options)
132
+ end
133
+ end
134
+
135
+ context "when not using path" do
136
+ it "sets the healthcheck_path to root" do
137
+ expect(described_class).to receive(:create_http_client) do |options|
138
+ expect(options[:healthcheck_path]).to eq("/")
139
+ end
140
+ described_class.build(logger, hosts, options)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ describe "sniffing_path" do
146
+ context "when setting sniffing_path" do
147
+ let(:sniffing_path) { "/meh" }
148
+ let(:options) { super().merge("sniffing_path" => sniffing_path) }
149
+
150
+ context "when using path" do
151
+ let(:options) { super().merge("path" => "/path") }
152
+ it "ignores the 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
+ context "when not using path" do
160
+
161
+ it "uses the sniffing_path setting" do
162
+ expect(described_class).to receive(:create_http_client) do |options|
163
+ expect(options[:sniffing_path]).to eq(sniffing_path)
164
+ end
165
+ described_class.build(logger, hosts, options)
166
+ end
167
+ end
168
+ end
169
+
170
+ context "when not setting sniffing_path" do
171
+
172
+ context "when using path" do
173
+ let(:path) { "/meh" }
174
+ let(:options) { super().merge("path" => path) }
175
+ it "sets sniffing_path to path+_nodes/http" do
176
+ expect(described_class).to receive(:create_http_client) do |options|
177
+ expect(options[:sniffing_path]).to eq("#{path}/_nodes/http")
178
+ end
179
+ described_class.build(logger, hosts, options)
180
+ end
181
+ end
182
+
183
+ context "when not using path" do
184
+ it "sets the sniffing_path to _nodes/http" do
185
+ expect(described_class).to receive(:create_http_client) do |options|
186
+ expect(options[:sniffing_path]).to eq("/_nodes/http")
187
+ end
188
+ described_class.build(logger, hosts, options)
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,62 @@
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/outputs/opensearch"
11
+ require_relative "../../../spec/opensearch_spec_helper"
12
+
13
+ describe "whitelisting error types in expected behavior" do
14
+ let(:template) { '{"template" : "not important, will be updated by :index"}' }
15
+ let(:event1) { LogStash::Event.new("somevalue" => 100, "@timestamp" => "2014-11-17T20:37:17.223Z") }
16
+ let(:action1) { ["index", {:_id=>1, :routing=>nil, :_index=>"logstash-2014.11.17", :_type=> doc_type }, event1] }
17
+ let(:settings) { {"manage_template" => true, "index" => "logstash-2014.11.17", "template_overwrite" => true, "hosts" => get_host_port() } }
18
+
19
+ subject { LogStash::Outputs::OpenSearch.new(settings) }
20
+
21
+ before :each do
22
+ allow(subject.logger).to receive(:warn)
23
+ allow(subject).to receive(:maximum_seen_major_version).and_return(0)
24
+ allow(subject).to receive(:finish_register)
25
+
26
+ subject.register
27
+ allow(subject.client).to receive(:bulk).and_return(
28
+ {
29
+ "errors" => true,
30
+ "items" => [{
31
+ "create" => {
32
+ "status" => 409,
33
+ "error" => {
34
+ "type" => "document_already_exists_exception",
35
+ "reason" => "[shard] document already exists"
36
+ }
37
+ }
38
+ }]
39
+ })
40
+
41
+ subject.multi_receive([event1])
42
+ end
43
+
44
+ after :each do
45
+ subject.close
46
+ end
47
+
48
+ describe "when failure logging is enabled for everything" do
49
+ it "should log a failure on the action" do
50
+ expect(subject.logger).to have_received(:warn).with("Failed action", anything)
51
+ end
52
+ end
53
+
54
+ describe "when failure logging is disabled for docuemnt exists error" do
55
+ let(:settings) { super().merge("failure_type_logging_whitelist" => ["document_already_exists_exception"]) }
56
+
57
+ it "should log a failure on the action" do
58
+ expect(subject.logger).not_to have_received(:warn).with("Failed action", anything)
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,159 @@
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::ManticoreAdapter do
15
+ let(:logger) { Cabin::Channel.get }
16
+ let(:options) { {} }
17
+
18
+ subject { described_class.new(logger, options) }
19
+
20
+ it "should raise an exception if requests are issued after close" do
21
+ subject.close
22
+ expect { subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, '/') }.to raise_error(::Manticore::ClientStoppedException)
23
+ end
24
+
25
+ it "should implement host unreachable exceptions" do
26
+ expect(subject.host_unreachable_exceptions).to be_a(Array)
27
+ end
28
+
29
+ describe "auth" do
30
+ let(:user) { "myuser" }
31
+ let(:password) { "mypassword" }
32
+ let(:noauth_uri) { clone = uri.clone; clone.user=nil; clone.password=nil; clone }
33
+ let(:uri) { ::LogStash::Util::SafeURI.new("http://#{user}:#{password}@localhost:9200") }
34
+
35
+ it "should convert the auth to params" do
36
+ resp = double("response")
37
+ allow(resp).to receive(:call)
38
+ allow(resp).to receive(:code).and_return(200)
39
+
40
+ expected_uri = noauth_uri.clone
41
+ expected_uri.path = "/"
42
+
43
+ expect(subject.manticore).to receive(:get).
44
+ with(expected_uri.to_s, {
45
+ :headers => {"Content-Type" => "application/json"},
46
+ :auth => {
47
+ :user => user,
48
+ :password => password,
49
+ :eager => true
50
+ }
51
+ }).and_return resp
52
+
53
+ subject.perform_request(uri, :get, "/")
54
+ end
55
+ end
56
+
57
+ describe "bad response codes" do
58
+ let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
59
+
60
+ it "should raise a bad response code error" do
61
+ resp = double("response")
62
+ allow(resp).to receive(:call)
63
+ allow(resp).to receive(:code).and_return(500)
64
+ allow(resp).to receive(:body).and_return("a body")
65
+
66
+ expect(subject.manticore).to receive(:get).
67
+ with(uri.to_s + "/", anything).
68
+ and_return(resp)
69
+
70
+ uri_with_path = uri.clone
71
+ uri_with_path.path = "/"
72
+
73
+ expect(::LogStash::Outputs::OpenSearch::HttpClient::Pool::BadResponseCodeError).to receive(:new).
74
+ with(resp.code, uri_with_path, nil, resp.body).and_call_original
75
+
76
+ expect do
77
+ subject.perform_request(uri, :get, "/")
78
+ end.to raise_error(::LogStash::Outputs::OpenSearch::HttpClient::Pool::BadResponseCodeError)
79
+ end
80
+ end
81
+
82
+ describe "format_url" do
83
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200/path/") }
84
+ let(:path) { "_bulk" }
85
+ subject { described_class.new(double("logger"), {}) }
86
+
87
+ it "should add the path argument to the uri's path" do
88
+ expect(subject.format_url(url, path).path).to eq("/path/_bulk")
89
+ end
90
+
91
+ context "when uri contains query parameters" do
92
+ let(:query_params) { "query=value&key=value2" }
93
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200/path/?#{query_params}") }
94
+ let(:formatted) { subject.format_url(url, path)}
95
+
96
+ it "should retain query_params after format" do
97
+ expect(formatted.query).to eq(query_params)
98
+ end
99
+
100
+ context "and the path contains query parameters" do
101
+ let(:path) { "/special_path?specialParam=123" }
102
+
103
+ it "should join the query correctly" do
104
+ expect(formatted.query).to eq(query_params + "&specialParam=123")
105
+ end
106
+ end
107
+ end
108
+
109
+ context "when the path contains query parameters" do
110
+ let(:path) { "/special_bulk?pathParam=1"}
111
+ let(:formatted) { subject.format_url(url, path) }
112
+
113
+ it "should add the path correctly" do
114
+ expect(formatted.path).to eq("#{url.path}special_bulk")
115
+ expect(subject.remove_double_escaping(formatted.path)).to eq("#{url.path}special_bulk")
116
+ end
117
+
118
+ it "should add the query parameters correctly" do
119
+ expect(formatted.query).to eq("pathParam=1")
120
+ end
121
+ end
122
+
123
+ context "when uri contains credentials" do
124
+ let(:url) { ::LogStash::Util::SafeURI.new("http://myuser:mypass@localhost:9200") }
125
+ let(:formatted) { subject.format_url(url, path) }
126
+
127
+ it "should remove credentials after format" do
128
+ expect(formatted.userinfo).to be_nil
129
+ end
130
+ end
131
+
132
+ context 'when uri contains date math' do
133
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
134
+ let(:path) { CGI.escape("<logstash-{now/d}-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("/%3Clogstash-%7Bnow%2Fd%7D-0001%3E")
139
+ end
140
+ end
141
+
142
+ context 'when uri does not contain date math' do
143
+ let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
144
+ let(:path) { CGI.escape("logstash-0001") }
145
+ let(:formatted) { subject.format_url(url, path) }
146
+
147
+ it 'should escape the uri correctly' do
148
+ expect(subject.remove_double_escaping(formatted.path)).to eq("/logstash-0001")
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "integration specs", :integration => true do
154
+ it "should perform correct tests without error" do
155
+ resp = subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, "/")
156
+ expect(resp.code).to eql(200)
157
+ end
158
+ end
159
+ end