elasticsearch/spec/integration/helpers/esql_helper_spec.rb (103 lines of code) (raw):
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
require_relative File.expand_path('../../spec_helper', __dir__)
require 'elasticsearch/helpers/esql_helper'
require 'ipaddr'
context 'Elasticsearch client helpers' do
let(:index) { 'esql_helper_test' }
let(:body) { { size: 12, query: { match_all: {} } } }
let(:esql_helper) { Elasticsearch::Helpers::ESQLHelper }
let(:query) do
<<~ESQL
FROM #{index}
| EVAL duration_ms = ROUND(event.duration / 1000000.0, 1)
ESQL
end
before do
CLIENT.indices.create(
index: index,
body: {
mappings: {
properties: { 'client.ip' => { type: 'ip' }, message: { type: 'keyword' } }
}
}
)
CLIENT.bulk(
index: index,
body: [
{ 'index': {} },
{ '@timestamp' => '2023-10-23T12:15:03.360Z', 'client.ip' => '172.21.2.162', message: 'Connected to 10.1.0.3',
'event.duration' => 3_450_233 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T12:27:28.948Z', 'client.ip' => '172.21.2.113', message: 'Connected to 10.1.0.2',
'event.duration' => 2_764_889 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T13:33:34.937Z', 'client.ip' => '172.21.0.5', message: 'Disconnected',
'event.duration' => 1_232_382 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T13:51:54.732Z', 'client.ip' => '172.21.3.15', message: 'Connection error',
'event.duration' => 725_448 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T13:52:55.015Z', 'client.ip' => '172.21.3.15', message: 'Connection error',
'event.duration' => 8_268_153 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T13:53:55.832Z', 'client.ip' => '172.21.3.15', message: 'Connection error',
'event.duration' => 5_033_755 },
{ 'index': {} },
{ '@timestamp' => '2023-10-23T13:55:01.543Z', 'client.ip' => '172.21.3.15', message: 'Connected to 10.1.0.1',
'event.duration' => 1_756_467 }
],
refresh: true
)
end
after do
CLIENT.indices.delete(index: index)
end
it 'returns an ESQL response as a relational key/value object' do
response = esql_helper.query(CLIENT, query)
expect(response.count).to eq 7
expect(response.first.keys).to eq ['duration_ms', 'message', 'event.duration', 'client.ip', '@timestamp']
response.each do |r|
expect(r['@timestamp']).to be_a String
expect(r['client.ip']).to be_a String
expect(r['message']).to be_a String
expect(r['event.duration']).to be_a Integer
end
end
it 'parses iterated objects when procs are passed in' do
parser = {
'@timestamp' => Proc.new { |t| DateTime.parse(t) },
'client.ip' => Proc.new { |i| IPAddr.new(i) },
'event.duration' => Proc.new { |d| d.to_s }
}
response = esql_helper.query(CLIENT, query, parser: parser)
response.each do |r|
expect(r['@timestamp']).to be_a DateTime
expect(r['client.ip']).to be_a IPAddr
expect(r['message']).to be_a String
expect(r['event.duration']).to be_a String
end
end
it 'parser does not error when value is nil, leaves nil' do
CLIENT.index(
index: index,
body: {
'@timestamp' => nil,
'client.ip' => nil,
message: 'Connected to 10.1.0.1',
'event.duration' => 1756465
},
refresh: true
)
parser = {
'@timestamp' => Proc.new { |t| DateTime.parse(t) },
'client.ip' => Proc.new { |i| IPAddr.new(i) },
'event.duration' => Proc.new { |d| d.to_s }
}
response = esql_helper.query(CLIENT, query, parser: parser)
response.each do |r|
expect [DateTime, NilClass].include?(r['@timestamp'].class)
expect [IPAddr, NilClass].include?(r['client.ip'].class)
expect(r['message']).to be_a String
expect(r['event.duration']).to be_a String
end
end
end