logstash-filter-elasticsearch 3.17.1 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,7 +61,7 @@ describe LogStash::Filters::Elasticsearch do
61
61
  allow(filter_client).to receive(:serverless?).and_return(true)
62
62
  allow(filter_client).to receive(:client).and_return(es_client)
63
63
 
64
- if elastic_ruby_v8_client_available?
64
+ if defined?(Elastic::Transport)
65
65
  allow(es_client).to receive(:info)
66
66
  .with(a_hash_including(
67
67
  :headers => LogStash::Filters::ElasticsearchClient::DEFAULT_EAV_HEADER))
@@ -93,306 +93,6 @@ describe LogStash::Filters::Elasticsearch do
93
93
  end
94
94
  end
95
95
 
96
- describe "data fetch" do
97
- let(:config) do
98
- {
99
- "hosts" => ["localhost:9200"],
100
- "query" => "response: 404",
101
- "fields" => { "response" => "code" },
102
- "docinfo_fields" => { "_index" => "es_index" },
103
- "aggregation_fields" => { "bytes_avg" => "bytes_avg_ls_field" }
104
- }
105
- end
106
-
107
- let(:response) do
108
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_x_1.json")))
109
- end
110
-
111
- let(:client) { double(:client) }
112
-
113
- before(:each) do
114
- allow(LogStash::Filters::ElasticsearchClient).to receive(:new).and_return(client)
115
- if elastic_ruby_v8_client_available?
116
- allow(client).to receive(:es_transport_client_type).and_return('elastic_transport')
117
- else
118
- allow(client).to receive(:es_transport_client_type).and_return('elasticsearch_transport')
119
- end
120
- allow(client).to receive(:search).and_return(response)
121
- allow(plugin).to receive(:test_connection!)
122
- allow(plugin).to receive(:setup_serverless)
123
- plugin.register
124
- end
125
-
126
- after(:each) do
127
- Thread.current[:filter_elasticsearch_client] = nil
128
- end
129
-
130
- it "should enhance the current event with new data" do
131
- plugin.filter(event)
132
- expect(event.get("code")).to eq(404)
133
- expect(event.get("es_index")).to eq("logstash-2014.08.26")
134
- expect(event.get("bytes_avg_ls_field")["value"]).to eq(294)
135
- end
136
-
137
- it "should receive all necessary params to perform the search" do
138
- expect(client).to receive(:search).with({:q=>"response: 404", :size=>1, :index=>"", :sort=>"@timestamp:desc"})
139
- plugin.filter(event)
140
- end
141
-
142
- context "when asking to hit specific index" do
143
-
144
- let(:config) do
145
- {
146
- "index" => "foo*",
147
- "hosts" => ["localhost:9200"],
148
- "query" => "response: 404",
149
- "fields" => { "response" => "code" }
150
- }
151
- end
152
-
153
- it "should receive all necessary params to perform the search" do
154
- expect(client).to receive(:search).with({:q=>"response: 404", :size=>1, :index=>"foo*", :sort=>"@timestamp:desc"})
155
- plugin.filter(event)
156
- end
157
- end
158
-
159
- context "when asking for more than one result" do
160
-
161
- let(:config) do
162
- {
163
- "hosts" => ["localhost:9200"],
164
- "query" => "response: 404",
165
- "fields" => { "response" => "code" },
166
- "result_size" => 10
167
- }
168
- end
169
-
170
- let(:response) do
171
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_x_10.json")))
172
- end
173
-
174
- it "should enhance the current event with new data" do
175
- plugin.filter(event)
176
- expect(event.get("code")).to eq([404]*10)
177
- end
178
- end
179
-
180
- context 'when Elasticsearch 7.x gives us a totals object instead of an integer' do
181
- let(:config) do
182
- {
183
- "hosts" => ["localhost:9200"],
184
- "query" => "response: 404",
185
- "fields" => { "response" => "code" },
186
- "result_size" => 10
187
- }
188
- end
189
-
190
- let(:response) do
191
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "elasticsearch_7.x_hits_total_as_object.json")))
192
- end
193
-
194
- it "should enhance the current event with new data" do
195
- plugin.filter(event)
196
- expect(event.get("[@metadata][total_hits]")).to eq(13476)
197
- end
198
- end
199
-
200
- context "if something wrong happen during connection" do
201
-
202
- before(:each) do
203
- allow(LogStash::Filters::ElasticsearchClient).to receive(:new).and_return(client)
204
- allow(client).to receive(:search).and_raise("connection exception")
205
- plugin.register
206
- end
207
-
208
- it "tag the event as something happened, but still deliver it" do
209
- expect(plugin.logger).to receive(:warn)
210
- plugin.filter(event)
211
- expect(event.to_hash["tags"]).to include("_elasticsearch_lookup_failure")
212
- end
213
- end
214
-
215
- # Tagging test for positive results
216
- context "Tagging should occur if query returns results" do
217
- let(:config) do
218
- {
219
- "index" => "foo*",
220
- "hosts" => ["localhost:9200"],
221
- "query" => "response: 404",
222
- "add_tag" => ["tagged"]
223
- }
224
- end
225
-
226
- let(:response) do
227
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_x_10.json")))
228
- end
229
-
230
- it "should tag the current event if results returned" do
231
- plugin.filter(event)
232
- expect(event.to_hash["tags"]).to include("tagged")
233
- end
234
- end
235
-
236
- context "an aggregation search with size 0 that matches" do
237
- let(:config) do
238
- {
239
- "index" => "foo*",
240
- "hosts" => ["localhost:9200"],
241
- "query" => "response: 404",
242
- "add_tag" => ["tagged"],
243
- "result_size" => 0,
244
- "aggregation_fields" => { "bytes_avg" => "bytes_avg_ls_field" }
245
- }
246
- end
247
-
248
- let(:response) do
249
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_size0_agg.json")))
250
- end
251
-
252
- it "should tag the current event" do
253
- plugin.filter(event)
254
- expect(event.get("tags")).to include("tagged")
255
- expect(event.get("bytes_avg_ls_field")["value"]).to eq(294)
256
- end
257
- end
258
-
259
- # Tagging test for negative results
260
- context "Tagging should not occur if query has no results" do
261
- let(:config) do
262
- {
263
- "index" => "foo*",
264
- "hosts" => ["localhost:9200"],
265
- "query" => "response: 404",
266
- "add_tag" => ["tagged"]
267
- }
268
- end
269
-
270
- let(:response) do
271
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_error.json")))
272
- end
273
-
274
- it "should not tag the current event" do
275
- plugin.filter(event)
276
- expect(event.to_hash["tags"]).to_not include("tagged")
277
- end
278
- end
279
- context "testing a simple query template" do
280
- let(:config) do
281
- {
282
- "hosts" => ["localhost:9200"],
283
- "query_template" => File.join(File.dirname(__FILE__), "fixtures", "query_template.json"),
284
- "fields" => { "response" => "code" },
285
- "result_size" => 1
286
- }
287
- end
288
-
289
- let(:response) do
290
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_x_1.json")))
291
- end
292
-
293
- it "should enhance the current event with new data" do
294
- plugin.filter(event)
295
- expect(event.get("code")).to eq(404)
296
- end
297
-
298
- end
299
-
300
- context "testing a simple index substitution" do
301
- let(:event) {
302
- LogStash::Event.new(
303
- {
304
- "subst_field" => "subst_value"
305
- }
306
- )
307
- }
308
- let(:config) do
309
- {
310
- "index" => "foo_%{subst_field}*",
311
- "hosts" => ["localhost:9200"],
312
- "query" => "response: 404",
313
- "fields" => { "response" => "code" }
314
- }
315
- end
316
-
317
- it "should receive substituted index name" do
318
- expect(client).to receive(:search).with({:q => "response: 404", :size => 1, :index => "foo_subst_value*", :sort => "@timestamp:desc"})
319
- plugin.filter(event)
320
- end
321
- end
322
-
323
- context "if query result errored but no exception is thrown" do
324
- let(:response) do
325
- LogStash::Json.load(File.read(File.join(File.dirname(__FILE__), "fixtures", "request_error.json")))
326
- end
327
-
328
- before(:each) do
329
- allow(LogStash::Filters::ElasticsearchClient).to receive(:new).and_return(client)
330
- allow(client).to receive(:search).and_return(response)
331
- plugin.register
332
- end
333
-
334
- it "tag the event as something happened, but still deliver it" do
335
- expect(plugin.logger).to receive(:warn)
336
- plugin.filter(event)
337
- expect(event.to_hash["tags"]).to include("_elasticsearch_lookup_failure")
338
- end
339
- end
340
-
341
- context 'with client-level retries' do
342
- let(:config) do
343
- super().merge(
344
- "retry_on_failure" => 3,
345
- "retry_on_status" => [500]
346
- )
347
- end
348
- end
349
-
350
- context "with custom headers" do
351
- let(:config) do
352
- {
353
- "query" => "*",
354
- "custom_headers" => { "Custom-Header-1" => "Custom Value 1", "Custom-Header-2" => "Custom Value 2" }
355
- }
356
- end
357
-
358
- let(:plugin) { LogStash::Filters::Elasticsearch.new(config) }
359
- let(:client_double) { double("client") }
360
- let(:transport_double) { double("transport", options: { transport_options: { headers: config["custom_headers"] } }) }
361
-
362
- before do
363
- allow(plugin).to receive(:get_client).and_return(client_double)
364
- if elastic_ruby_v8_client_available?
365
- allow(client_double).to receive(:es_transport_client_type).and_return('elastic_transport')
366
- else
367
- allow(client_double).to receive(:es_transport_client_type).and_return('elasticsearch_transport')
368
- end
369
- allow(client_double).to receive(:client).and_return(transport_double)
370
- end
371
-
372
- it "sets custom headers" do
373
- plugin.register
374
- client = plugin.send(:get_client).client
375
- expect(client.options[:transport_options][:headers]).to match(hash_including(config["custom_headers"]))
376
- end
377
- end
378
-
379
- context "if query is on nested field" do
380
- let(:config) do
381
- {
382
- "hosts" => ["localhost:9200"],
383
- "query" => "response: 404",
384
- "fields" => [ ["[geoip][ip]", "ip_address"] ]
385
- }
386
- end
387
-
388
- it "should enhance the current event with new data" do
389
- plugin.filter(event)
390
- expect(event.get("ip_address")).to eq("66.249.73.185")
391
- end
392
-
393
- end
394
- end
395
-
396
96
  class StoppableServer
397
97
 
398
98
  attr_reader :port
@@ -525,7 +225,7 @@ describe LogStash::Filters::Elasticsearch do
525
225
  # this spec is a safeguard to trigger an assessment of thread-safety should
526
226
  # we choose a different transport adapter in the future.
527
227
  transport_class = extract_transport(client).options.fetch(:transport_class)
528
- if elastic_ruby_v8_client_available?
228
+ if defined?(Elastic::Transport)
529
229
  allow(client).to receive(:es_transport_client_type).and_return("elastic_transport")
530
230
  expect(transport_class).to equal ::Elastic::Transport::Transport::HTTP::Manticore
531
231
  else
@@ -845,7 +545,7 @@ describe LogStash::Filters::Elasticsearch do
845
545
 
846
546
  before(:each) do
847
547
  allow(LogStash::Filters::ElasticsearchClient).to receive(:new).and_return(client)
848
- if elastic_ruby_v8_client_available?
548
+ if defined?(Elastic::Transport)
849
549
  allow(client).to receive(:es_transport_client_type).and_return('elastic_transport')
850
550
  else
851
551
  allow(client).to receive(:es_transport_client_type).and_return('elasticsearch_transport')
@@ -864,19 +564,149 @@ describe LogStash::Filters::Elasticsearch do
864
564
  end
865
565
  end
866
566
 
567
+ describe "ES|QL" do
568
+
569
+ describe "compatibility" do
570
+ let(:config) {{ "hosts" => ["localhost:9200"], "query_type" => "esql", "query" => "FROM my-index" }}
571
+
572
+ context "when LS doesn't support ES|QL" do
573
+ let(:ls_version) { LogStash::Filters::Elasticsearch::LS_ESQL_SUPPORT_VERSION }
574
+ before(:each) do
575
+ stub_const("LOGSTASH_VERSION", "8.17.0")
576
+ end
577
+
578
+ it "raises a runtime error" do
579
+ expect { plugin.send(:validate_ls_version_for_esql_support!) }
580
+ .to raise_error(RuntimeError, /Current version of Logstash does not include Elasticsearch client which supports ES|QL. Please upgrade Logstash to at least #{ls_version}/)
581
+ end
582
+ end
583
+
584
+ context "when ES doesn't support ES|QL" do
585
+ let(:es_version) { LogStash::Filters::Elasticsearch::ES_ESQL_SUPPORT_VERSION }
586
+ let(:client) { double(:client) }
587
+
588
+ it "raises a runtime error" do
589
+ allow(plugin).to receive(:get_client).twice.and_return(client)
590
+ allow(client).to receive(:es_version).and_return("8.8.0")
591
+
592
+ expect { plugin.send(:validate_es_for_esql_support!) }
593
+ .to raise_error(RuntimeError, /Connected Elasticsearch 8.8.0 version does not supports ES|QL. ES|QL feature requires at least Elasticsearch #{es_version} version./)
594
+ end
595
+ end
596
+ end
597
+
598
+ context "when non-ES|QL params applied" do
599
+ let(:config) do
600
+ {
601
+ "hosts" => ["localhost:9200"],
602
+ "query_type" => "esql",
603
+ "query" => "FROM my-index",
604
+ "index" => "some-index",
605
+ "docinfo_fields" => { "_index" => "es_index" },
606
+ "sort" => "@timestamp:desc",
607
+ "enable_sort" => true,
608
+ "aggregation_fields" => { "bytes_avg" => "bytes_avg_ls_field" }
609
+ }
610
+ end
611
+ it "raises a config error" do
612
+ invalid_params_with_esql = %w(index docinfo_fields sort enable_sort aggregation_fields)
613
+ error_text = /Configured #{invalid_params_with_esql} params cannot be used with ES|QL query/i
614
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, error_text
615
+ end
616
+ end
617
+
618
+ describe "#query placeholder" do
619
+ let(:config) do
620
+ {
621
+ "hosts" => ["localhost:9200"],
622
+ "query_type" => "esql"
623
+ }
624
+ end
625
+
626
+ context "when query placeholder doesn't exist in the query" do
627
+ let(:config) {
628
+ super()
629
+ .merge(
630
+ {
631
+ "query" => "FROM my-index",
632
+ "query_params" => { "a" => "b" },
633
+ })
634
+ }
635
+
636
+ it "doesn't complain since not used" do
637
+ expect { plugin.send(:validate_esql_query_and_params!) }.not_to raise_error
638
+ end
639
+ end
640
+
641
+ context "when illegal placeholders appear" do
642
+ let(:config) {
643
+ super()
644
+ .merge(
645
+ {
646
+ "query" => "FROM my-index | WHERE type = ?type",
647
+ "query_params" => { "1abcd_efg1" => "1", "$abcd_efg1" => 2, "type" => 3 },
648
+ })
649
+ }
650
+ it "raises a config error" do
651
+ message = 'Illegal ["1abcd_efg1", "$abcd_efg1"] placeholder names in `query_params`. A valid parameter name starts with a letter and contains letters, digits and underscores only;'
652
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, message
653
+ end
654
+ end
655
+
656
+ context "when query placeholders and `query_params` do not match" do
657
+ let(:config) {
658
+ super()
659
+ .merge(
660
+ {
661
+ "query" => "FROM my-index | WHERE type = ?type",
662
+ "query_params" => {"b" => "c"},
663
+ })
664
+ }
665
+ it "raises a config error" do
666
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, /Placeholder type not found in query/
667
+ end
668
+ end
669
+
670
+ context "when `query_params` is an Array contains {key => val} entries" do
671
+ let(:config) {
672
+ super()
673
+ .merge(
674
+ {
675
+ "query" => "FROM my-index",
676
+ "query_params" => [{ "a" => "b" }, { "c" => "[b]" }, { "e" => 1 }, { "f" => "[g]" }],
677
+ })
678
+ }
679
+
680
+ it "doesn't complain since not used" do
681
+ expect { plugin.send(:validate_esql_query_and_params!) }.not_to raise_error
682
+ expect(plugin.query_params).to eq({ "a" => "b", "c" => "[b]", "e" => 1, "f" => "[g]" })
683
+ end
684
+ end
685
+
686
+ context "when `query_params` is a Hash" do
687
+ let(:config) {
688
+ super()
689
+ .merge(
690
+ {
691
+ "query" => "FROM my-index",
692
+ "query_params" => { "a" => "b", "c" => "[b]", "e" => 1, "f" => "[g]" },
693
+ })
694
+ }
695
+
696
+ it "doesn't complain since not used" do
697
+ expect { plugin.send(:validate_esql_query_and_params!) }.not_to raise_error
698
+ expect(plugin.query_params).to eq({ "a" => "b", "c" => "[b]", "e" => 1, "f" => "[g]" })
699
+ end
700
+ end
701
+ end if LOGSTASH_VERSION >= '8.17.4'
702
+ end
703
+
867
704
  def extract_transport(client)
868
705
  # on 7x: client.transport.transport
869
706
  # on >=8.x: client.transport
870
707
  client.transport.respond_to?(:transport) ? client.transport.transport : client.transport
871
708
  end
872
709
 
873
- def elastic_ruby_v8_client_available?
874
- Elasticsearch::Transport
875
- false
876
- rescue NameError # NameError: uninitialized constant Elasticsearch::Transport if Elastic Ruby client is not available
877
- true
878
- end
879
-
880
710
  class MockResponse
881
711
  attr_reader :code, :headers
882
712
 
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "logstash/filters/elasticsearch"
4
+ require "elasticsearch"
5
+ require_relative "../../../spec/es_helper"
6
+
7
+ describe LogStash::Filters::Elasticsearch, integration: true do
8
+
9
+ ELASTIC_SECURITY_ENABLED = ENV['ELASTIC_SECURITY_ENABLED'].eql? 'true'
10
+ SECURE_INTEGRATION = ENV['SECURE_INTEGRATION'].eql? 'true'
11
+ ES_HOSTS = ["http#{SECURE_INTEGRATION ? 's' : nil}://#{ESHelper.get_host_port}"]
12
+ CA_PATH = File.expand_path('../fixtures/test_certs/ca.crt', File.dirname(__FILE__))
13
+
14
+ let(:plugin) { described_class.new(config) }
15
+ let(:es_index) { "es-filter-plugin-esql-integration-#{rand(1000)}" }
16
+ let(:test_documents) do
17
+ [
18
+ { "message" => "test message 1", "type" => "a", "count" => 1 },
19
+ { "message" => "test message 2", "type" => "a", "count" => 2 },
20
+ { "message" => "test message 3", "type" => "b", "count" => 3 },
21
+ { "message" => "test message 4", "type" => "b", "count" => 4 },
22
+ { "message" => "test message 5", "type" => "c", "count" => 5 },
23
+ { "message" => "odd test message", "type" => "t" }
24
+ ]
25
+ end
26
+
27
+ let(:base_config) do
28
+ {
29
+ "query_type" => "esql",
30
+ "hosts" => ES_HOSTS,
31
+ "ssl_enabled" => SECURE_INTEGRATION
32
+ }
33
+ end
34
+
35
+ let(:credentials) do
36
+ if SECURE_INTEGRATION
37
+ { 'user' => 'tests', 'password' => 'Tests123' }
38
+ else
39
+ { 'user' => 'elastic', 'password' => ENV['ELASTIC_PASSWORD'] }
40
+ end
41
+ end
42
+
43
+ let(:config) do
44
+ config = ELASTIC_SECURITY_ENABLED ? base_config.merge(credentials) : base_config
45
+ config = { 'ssl_certificate_authorities' => CA_PATH }.merge(config) if SECURE_INTEGRATION
46
+ config
47
+ end
48
+
49
+ let(:event) { LogStash::Event.new({}) }
50
+
51
+ def es_client
52
+ @es_client ||= begin
53
+ user = SECURE_INTEGRATION ? 'tests' : 'elastic'
54
+ password = SECURE_INTEGRATION ? 'Tests123' : ENV['ELASTIC_PASSWORD']
55
+
56
+ es_client_config = { hosts: ES_HOSTS }
57
+ es_client_config = es_client_config.merge({ user: user, password: password }) if ELASTIC_SECURITY_ENABLED || SECURE_INTEGRATION
58
+ es_client_config = es_client_config.merge({ transport_options: { ssl: { ca_path: CA_PATH, verify: false }}}) if SECURE_INTEGRATION
59
+
60
+ Elasticsearch::Client.new(es_client_config)
61
+ end
62
+ end
63
+
64
+ before(:all) do
65
+ is_ls_with_esql_supported_client = Gem::Version.create(LOGSTASH_VERSION) >= Gem::Version.create(LogStash::Filters::Elasticsearch::LS_ESQL_SUPPORT_VERSION)
66
+ # Skip tests if an ES version doesn't support ES|QL
67
+ skip "LS version does not have ES client which supports ES|QL" unless is_ls_with_esql_supported_client
68
+
69
+ es_version_info = es_client.info["version"]
70
+ es_gem_version = Gem::Version.create(es_version_info["number"])
71
+ skip "ES version does not support ES|QL" if es_gem_version.nil? || es_gem_version < Gem::Version.create(LogStash::Filters::Elasticsearch::ES_ESQL_SUPPORT_VERSION)
72
+ end
73
+
74
+ before(:each) do
75
+ # Create index with test documents
76
+ es_client.indices.create(index: es_index, body: {}) unless es_client.indices.exists?(index: es_index)
77
+
78
+ test_documents.each do |doc|
79
+ es_client.index(index: es_index, body: doc, refresh: true)
80
+ end
81
+ end
82
+
83
+ after(:each) do
84
+ es_client.indices.delete(index: es_index) if es_client.indices.exists?(index: es_index)
85
+ end
86
+
87
+ describe "run ES|QL queries" do
88
+
89
+ before do
90
+ stub_const("LOGSTASH_VERSION", LogStash::Filters::Elasticsearch::LS_ESQL_SUPPORT_VERSION)
91
+ end
92
+
93
+ before(:each) do
94
+ plugin.register
95
+ end
96
+
97
+ shared_examples "ESQL query execution" do |expected_count, fields|
98
+ it "processes the event" do
99
+ plugin.filter(event)
100
+ expect(event.get("[@metadata][total_values]")).to eq(expected_count)
101
+ fields&.each do | field |
102
+ expect(event.get(field)).not_to be(nil)
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "with simple FROM query with LIMIT" do
108
+ let(:config) do
109
+ super().merge("query" => "FROM #{es_index} | LIMIT 99")
110
+ end
111
+
112
+ include_examples "ESQL query execution", 6
113
+ end
114
+
115
+ describe "with simple FROM and WHERE query combinations" do
116
+ let(:config) do
117
+ super().merge("query" => "FROM #{es_index} | WHERE type==\"b\" | LIMIT 99")
118
+ end
119
+
120
+ include_examples "ESQL query execution", 2
121
+ end
122
+
123
+ describe "with query params" do
124
+ let(:config) do
125
+ super().merge("query" => "FROM #{es_index} | WHERE type==?type", "query_params" => { "type" => "b" })
126
+ end
127
+
128
+ include_examples "ESQL query execution", 2
129
+ end
130
+
131
+ describe "when invalid query used" do
132
+ let(:config) do
133
+ super().merge("query" => "FROM undefined index | LIMIT 1")
134
+ end
135
+
136
+ it "tags on failure" do
137
+ plugin.filter(event)
138
+ expect(event.to_hash["tags"]).to include("_elasticsearch_lookup_failure")
139
+ end
140
+ end
141
+
142
+ describe "when field enrichment requested" do
143
+ let(:config) do
144
+ super().merge("query" => "FROM #{es_index} | WHERE type==\"b\" | LIMIT 99")
145
+ end
146
+
147
+ include_examples "ESQL query execution", 2, %w[message count]
148
+ end
149
+
150
+ describe "when non-exist field value appear" do
151
+ let(:config) do
152
+ super().merge("query" => "FROM #{es_index}", "target" => "target_field")
153
+ end
154
+
155
+ it "processes the event" do
156
+ plugin.filter(event)
157
+ expect(event.get("[@metadata][total_values]")).to eq(6)
158
+ expect(event.get("target_field").size).to eq(6)
159
+ values = event.get("target_field")
160
+ counts = values.count { |entry| entry.key?("count") }
161
+ messages = values.count { |entry| entry.key?("message") }
162
+ expect(counts).to eq(5)
163
+ expect(messages).to eq(6)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -84,7 +84,9 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
84
84
  end
85
85
 
86
86
  it "fails to register plugin" do
87
- expect { plugin.register }.to raise_error Elasticsearch::Transport::Transport::Errors::Unauthorized
87
+ expect { plugin.register }.to raise_error elastic_ruby_v8_client_available? ?
88
+ Elastic::Transport::Transport::Errors::Unauthorized :
89
+ Elasticsearch::Transport::Transport::Errors::Unauthorized
88
90
  end
89
91
 
90
92
  end if ELASTIC_SECURITY_ENABLED
@@ -150,5 +152,10 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
150
152
  end
151
153
  end
152
154
  end
153
-
155
+ def elastic_ruby_v8_client_available?
156
+ Elasticsearch::Transport
157
+ false
158
+ rescue NameError # NameError: uninitialized constant Elasticsearch::Transport if Elastic Ruby client is not available
159
+ true
160
+ end
154
161
  end