logstash-input-beats 3.1.0.beta1-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
- data/CHANGELOG.md +131 -0
- data/CONTRIBUTORS +17 -0
- data/Gemfile +4 -0
- data/LICENSE +14 -0
- data/NOTICE.TXT +5 -0
- data/PROTOCOL.md +127 -0
- data/README.md +98 -0
- data/VERSION +1 -0
- data/lib/logstash-input-beats_jars.rb +17 -0
- data/lib/logstash/inputs/beats.rb +184 -0
- data/lib/logstash/inputs/beats/codec_callback_listener.rb +26 -0
- data/lib/logstash/inputs/beats/decoded_event_transform.rb +34 -0
- data/lib/logstash/inputs/beats/event_transform_common.rb +48 -0
- data/lib/logstash/inputs/beats/message_listener.rb +96 -0
- data/lib/logstash/inputs/beats/raw_event_transform.rb +18 -0
- data/lib/logstash/inputs/beats/tls.rb +40 -0
- data/lib/tasks/build.rake +15 -0
- data/lib/tasks/test.rake +65 -0
- data/logstash-input-beats.gemspec +41 -0
- data/spec/inputs/beats/codec_callback_listener_spec.rb +33 -0
- data/spec/inputs/beats/decoded_event_transform_spec.rb +74 -0
- data/spec/inputs/beats/event_transform_common_spec.rb +11 -0
- data/spec/inputs/beats/message_listener_spec.rb +108 -0
- data/spec/inputs/beats/raw_event_transform_spec.rb +26 -0
- data/spec/inputs/beats/tls_spec.rb +39 -0
- data/spec/inputs/beats_spec.rb +99 -0
- data/spec/integration/filebeat_spec.rb +234 -0
- data/spec/integration/logstash_forwarder_spec.rb +104 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/client_process_helpers.rb +28 -0
- data/spec/support/file_helpers.rb +61 -0
- data/spec/support/flores_extensions.rb +82 -0
- data/spec/support/integration_shared_context.rb +73 -0
- data/spec/support/logstash_test.rb +66 -0
- data/spec/support/shared_examples.rb +56 -0
- data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.7.5/jackson-annotations-2.7.5.jar +0 -0
- data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.7.5/jackson-core-2.7.5.jar +0 -0
- data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-databind/2.7.5/jackson-databind-2.7.5.jar +0 -0
- data/vendor/jar-dependencies/com/fasterxml/jackson/module/jackson-module-afterburner/2.7.5/jackson-module-afterburner-2.7.5.jar +0 -0
- data/vendor/jar-dependencies/io/netty/netty-all/4.1.1.Final/netty-all-4.1.1.Final.jar +0 -0
- data/vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/1.1.33.Fork17/netty-tcnative-boringssl-static-1.1.33.Fork17.jar +0 -0
- data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-1.2-api/2.6.1/log4j-1.2-api-2.6.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar +0 -0
- data/vendor/jar-dependencies/org/bouncycastle/bcpkix-jdk15on/1.54/bcpkix-jdk15on-1.54.jar +0 -0
- data/vendor/jar-dependencies/org/bouncycastle/bcprov-jdk15on/1.54/bcprov-jdk15on-1.54.jar +0 -0
- data/vendor/jar-dependencies/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar +0 -0
- data/vendor/jar-dependencies/org/logstash/beats/logstash-input-beats/3.1.0.beta1/logstash-input-beats-3.1.0.beta1.jar +0 -0
- metadata +313 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/inputs/beats"
|
3
|
+
require "logstash/json"
|
4
|
+
require "fileutils"
|
5
|
+
require_relative "../support/flores_extensions"
|
6
|
+
require_relative "../support/file_helpers"
|
7
|
+
require_relative "../support/integration_shared_context"
|
8
|
+
require_relative "../support/client_process_helpers"
|
9
|
+
require "spec_helper"
|
10
|
+
|
11
|
+
LSF_BINARY = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "vendor", "logstash-forwarder", "logstash-forwarder"))
|
12
|
+
|
13
|
+
describe "Logstash-Forwarder", :integration => true do
|
14
|
+
include ClientProcessHelpers
|
15
|
+
|
16
|
+
before :all do
|
17
|
+
unless File.exist?(LSF_BINARY)
|
18
|
+
raise "Cannot find `logstash-forwarder` binary in `vendor/logstash-forwarder` Did you run `bundle exec rake test:integration:setup` before running the integration suite?"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
include FileHelpers
|
23
|
+
include_context "beats configuration"
|
24
|
+
|
25
|
+
let(:client_wait_time) { 5 }
|
26
|
+
|
27
|
+
# Filebeat related variables
|
28
|
+
let(:cmd) { [lsf_exec, "-config", lsf_config_path] }
|
29
|
+
|
30
|
+
let(:lsf_exec) { LSF_BINARY }
|
31
|
+
let(:registry_file) { File.expand_path(File.join(File.dirname(__FILE__), "..", "..", ".logstash-forwarder")) }
|
32
|
+
let_tmp_file(:lsf_config_path) { lsf_config }
|
33
|
+
let(:log_file) { f = Stud::Temporary.file; f.close; f.path }
|
34
|
+
let(:lsf_config) do
|
35
|
+
<<-CONFIG
|
36
|
+
{
|
37
|
+
"network": {
|
38
|
+
"servers": [ "#{host}:#{port}" ],
|
39
|
+
"ssl ca": "#{certificate_authorities}"
|
40
|
+
},
|
41
|
+
"files": [
|
42
|
+
{ "paths": [ "#{log_file}" ] }
|
43
|
+
]
|
44
|
+
}
|
45
|
+
CONFIG
|
46
|
+
end
|
47
|
+
#
|
48
|
+
|
49
|
+
before :each do
|
50
|
+
FileUtils.rm_rf(registry_file) # ensure clean state between runs
|
51
|
+
start_client
|
52
|
+
sleep(1)
|
53
|
+
# let LSF start and than write the logs
|
54
|
+
File.open(log_file, "a") do |f|
|
55
|
+
f.write(events.join("\n") + "\n")
|
56
|
+
end
|
57
|
+
sleep(1) # give some time to the clients to pick up the changes
|
58
|
+
stop_client
|
59
|
+
end
|
60
|
+
|
61
|
+
after :each do
|
62
|
+
stop_client
|
63
|
+
end
|
64
|
+
|
65
|
+
xcontext "Plain TCP" do
|
66
|
+
include ClientProcessHelpers
|
67
|
+
|
68
|
+
let(:certificate_authorities) { "" }
|
69
|
+
|
70
|
+
it "should not send any events" do
|
71
|
+
expect(queue.size).to eq(0), @execution_output
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "TLS" do
|
76
|
+
context "Server Verification" do
|
77
|
+
let(:input_config) do
|
78
|
+
super.merge({
|
79
|
+
"ssl" => true,
|
80
|
+
"ssl_certificate" => certificate_file,
|
81
|
+
"ssl_key" => certificate_key_file,
|
82
|
+
})
|
83
|
+
end
|
84
|
+
|
85
|
+
let(:certificate_data) { Flores::PKI.generate }
|
86
|
+
let_tmp_file(:certificate_file) { certificate_data.first }
|
87
|
+
let_tmp_file(:certificate_key_file) { certificate_data.last }
|
88
|
+
let(:certificate_authorities) { certificate_file }
|
89
|
+
|
90
|
+
context "self signed certificate" do
|
91
|
+
include_examples "send events"
|
92
|
+
end
|
93
|
+
|
94
|
+
context "invalid CA on the client" do
|
95
|
+
let(:invalid_data) { Flores::PKI.generate }
|
96
|
+
let(:certificate_authorities) { f = Stud::Temporary.file; f.close; f.path }
|
97
|
+
|
98
|
+
it "should not send any events" do
|
99
|
+
expect(queue.size).to eq(0), @execution_output
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/mocks'
|
4
|
+
require 'rspec/wait'
|
5
|
+
require "logstash/devutils/rspec/spec_helper"
|
6
|
+
require "logstash/codecs/plain"
|
7
|
+
require_relative "support/logstash_test"
|
8
|
+
|
9
|
+
$: << File.realpath(File.join(File.dirname(__FILE__), "..", "lib"))
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.order = :rand
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "childprocess"
|
3
|
+
module ClientProcessHelpers
|
4
|
+
def start_client(timeout = 1)
|
5
|
+
@client_out = Stud::Temporary.file
|
6
|
+
@client_out.sync
|
7
|
+
|
8
|
+
@process = ChildProcess.build(*cmd)
|
9
|
+
@process.duplex = true
|
10
|
+
@process.io.stdout = @process.io.stderr = @client_out
|
11
|
+
ChildProcess.posix_spawn = true
|
12
|
+
@process.start
|
13
|
+
|
14
|
+
sleep(0.1)
|
15
|
+
@client_out.rewind
|
16
|
+
|
17
|
+
# can be used to helper debugging when a test fails
|
18
|
+
@execution_output = @client_out.read
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop_client
|
22
|
+
begin
|
23
|
+
@process.poll_for_exit(5)
|
24
|
+
rescue ChildProcess::TimeoutError
|
25
|
+
Process.kill("KILL", @process.pid)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Add an helper method named `let_tmp_file` to spec example, this
|
4
|
+
# helper will create a temporary file with the content from the block,
|
5
|
+
# it behave like a normal `let` statement. Also to make things easier temporary
|
6
|
+
# debug it will create another `let` statement with the actual content of the block.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
# ```
|
10
|
+
# let_tmp_file(:hello_world_file) { "Hello world" } # return a path to a tmp file containing "Hello World"
|
11
|
+
# and will create this debug `let`, the value of the file will be the same.
|
12
|
+
# let(:hello_world_file_content) # return "Hello world"
|
13
|
+
#
|
14
|
+
module FileHelpers
|
15
|
+
AUTO_CLEAN = true
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_to_tmp_file(content)
|
22
|
+
file = Stud::Temporary.file
|
23
|
+
file.write(content.to_s)
|
24
|
+
file.close
|
25
|
+
file.path
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
def let_empty_tmp_file(name, &block)
|
30
|
+
let(name) do
|
31
|
+
path = nil
|
32
|
+
f = Stud::Temporary.file
|
33
|
+
f.close
|
34
|
+
path = f.path
|
35
|
+
@__let_tmp_files = [] unless @__let_tmp_files
|
36
|
+
@__let_tmp_files << path
|
37
|
+
path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def let_tmp_file(name, &block)
|
42
|
+
after :each do
|
43
|
+
if @__let_tmp_files && FileHelpers::AUTO_CLEAN
|
44
|
+
@__let_tmp_files.each do |f|
|
45
|
+
FileUtils.rm_f(f)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
name_content = "#{name}_content"
|
51
|
+
let(name_content, &block)
|
52
|
+
let(name) do
|
53
|
+
content = __send__(name_content)
|
54
|
+
path = write_to_tmp_file(content)
|
55
|
+
@__let_tmp_files = [] unless @__let_tmp_files
|
56
|
+
@__let_tmp_files << path
|
57
|
+
path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "flores/pki"
|
3
|
+
require "flores/random"
|
4
|
+
|
5
|
+
module Flores
|
6
|
+
module Random
|
7
|
+
DEFAULT_PORT_RANGE = 1024..65535
|
8
|
+
DEFAULT_PORT_CHECK_TIMEOUT = 1
|
9
|
+
DEFAULT_MAXIMUM_PORT_FIND_TRY = 15
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def port(range = DEFAULT_PORT_RANGE)
|
13
|
+
try = 0
|
14
|
+
while try < DEFAULT_MAXIMUM_PORT_FIND_TRY
|
15
|
+
candidate = integer(range)
|
16
|
+
|
17
|
+
if port_available?(candidate)
|
18
|
+
break
|
19
|
+
else
|
20
|
+
try += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
raise "Flores.random_port: Cannot find an available port, tried #{DEFAULT_MAXIMUM_PORT_FIND_TRY} times, range was: #{range}" if try == DEFAULT_MAXIMUM_PORT_FIND_TRY
|
25
|
+
|
26
|
+
candidate
|
27
|
+
end
|
28
|
+
|
29
|
+
def port_available?(port)
|
30
|
+
begin
|
31
|
+
server = TCPServer.new(port)
|
32
|
+
available = true
|
33
|
+
rescue # Assume that any errors can do this
|
34
|
+
available = false
|
35
|
+
ensure
|
36
|
+
server.close if server
|
37
|
+
end
|
38
|
+
|
39
|
+
return available
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module PKI
|
45
|
+
DEFAULT_CERTIFICATE_OPTIONS = {
|
46
|
+
:duration => Flores::Random.number(100..2000),
|
47
|
+
:key_size => GENERATE_DEFAULT_KEY_SIZE,
|
48
|
+
:exponent => GENERATE_DEFAULT_EXPONENT,
|
49
|
+
:want_signature_ability => false
|
50
|
+
}
|
51
|
+
|
52
|
+
def self.chain_certificates(*certificates)
|
53
|
+
certificates.join("\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.create_intermediate_certificate(subject, signing_certificate, signing_private_key, options = {})
|
57
|
+
create_a_signed_certificate(subject, signing_certificate, signing_private_key, options.merge({ :want_signature_ability => true }))
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.create_client_certicate(subject, signing_certificate, signing_private_key, options = {})
|
61
|
+
create_a_signed_certificate(subject, signing_certificate, signing_private_key, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def self.create_a_signed_certificate(subject, signing_certificate, signing_private_key, options = {})
|
66
|
+
options = DEFAULT_CERTIFICATE_OPTIONS.merge(options)
|
67
|
+
|
68
|
+
client_key = OpenSSL::PKey::RSA.new(options[:key_size], options[:exponent])
|
69
|
+
|
70
|
+
csr = Flores::PKI::CertificateSigningRequest.new
|
71
|
+
csr.start_time = Time.now
|
72
|
+
csr.expire_time = csr.start_time + options[:duration]
|
73
|
+
csr.public_key = client_key.public_key
|
74
|
+
csr.subject = subject
|
75
|
+
csr.signing_key = signing_private_key
|
76
|
+
csr.signing_certificate = signing_certificate
|
77
|
+
csr.want_signature_ability = options[:want_signature_ability]
|
78
|
+
|
79
|
+
[csr.create, client_key]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "flores/random"
|
3
|
+
|
4
|
+
shared_examples "send events" do
|
5
|
+
it "successfully send the events" do
|
6
|
+
wait(20).for { queue.size }.to eq(number_of_events), "Expected: #{number_of_events} got: #{queue.size}, execution output:\n #{@execution_output}"
|
7
|
+
expect(queue.collect { |e| e.get("message") }).to eq(events)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples "doesn't send events" do
|
12
|
+
it "doesn't send any events" do
|
13
|
+
expect(queue.size).to eq(0), "Expected: #{number_of_events} got: #{queue.size}, execution output:\n #{@execution_output}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
shared_context "beats configuration" do
|
18
|
+
# common
|
19
|
+
let(:port) { Flores::Random.port }
|
20
|
+
let(:host) { "localhost" }
|
21
|
+
|
22
|
+
let(:queue) { [] }
|
23
|
+
let_tmp_file(:log_file) { events.join("\n") + "\n" } # make sure we end of line
|
24
|
+
let(:number_of_events) { 5 }
|
25
|
+
let(:event) { "Hello world" }
|
26
|
+
let(:events) do
|
27
|
+
events = []
|
28
|
+
number_of_events.times { |n| events << "#{event} #{n}" }
|
29
|
+
events
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:input_config) do
|
33
|
+
{
|
34
|
+
"host" => host,
|
35
|
+
"port" => port
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:beats) do
|
40
|
+
LogStash::Inputs::Beats.new(input_config)
|
41
|
+
end
|
42
|
+
|
43
|
+
before :each do
|
44
|
+
beats.register
|
45
|
+
|
46
|
+
@abort_on_exception = Thread.abort_on_exception
|
47
|
+
Thread.abort_on_exception = true
|
48
|
+
|
49
|
+
@server = Thread.new do
|
50
|
+
begin
|
51
|
+
# use to know what lumberjack is actually doing
|
52
|
+
if ENV["DEBUG"]
|
53
|
+
logger = Logger.new(STDOUT)
|
54
|
+
beats.logger = Cabin::Channel.new
|
55
|
+
beats.logger.subscribe(logger)
|
56
|
+
beats.logger.level = :debug
|
57
|
+
end
|
58
|
+
|
59
|
+
beats.run(queue)
|
60
|
+
rescue => e
|
61
|
+
retry unless beats.stop?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@server.abort_on_exception = true
|
65
|
+
|
66
|
+
sleep(1) while @server.status != "run"
|
67
|
+
end
|
68
|
+
|
69
|
+
after(:each) do
|
70
|
+
beats.stop
|
71
|
+
Thread.abort_on_exception = @abort_on_exception
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "stud/temporary"
|
2
|
+
|
3
|
+
|
4
|
+
# namespace the Dummy* classes, they are reused names
|
5
|
+
# use a more specific module name to prevent clashes
|
6
|
+
module BeatsInputTest
|
7
|
+
class Certicate
|
8
|
+
attr_reader :ssl_key, :ssl_cert
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@ssl_cert = Stud::Temporary.pathname("ssl_certificate")
|
12
|
+
@ssl_key = Stud::Temporary.pathname("ssl_key")
|
13
|
+
|
14
|
+
system("openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout #{ssl_key} -out #{ssl_cert} -subj /CN=localhost > /dev/null 2>&1")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def certificate
|
20
|
+
Certicate.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def random_port
|
24
|
+
rand(2000..10000)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DummyNeverBlockedQueue < Array
|
29
|
+
def offer(element, timeout = nil)
|
30
|
+
push(element)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :take, :shift
|
34
|
+
end
|
35
|
+
|
36
|
+
class DummyConnection
|
37
|
+
def initialize(events)
|
38
|
+
@events = events
|
39
|
+
end
|
40
|
+
|
41
|
+
def run
|
42
|
+
@events.each do |element|
|
43
|
+
yield element[:map], element[:identity_stream]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def peer
|
48
|
+
"localhost:5555"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class DummyCodec
|
53
|
+
def register() end
|
54
|
+
def decode(*) end
|
55
|
+
def clone() self; end
|
56
|
+
def base_codec
|
57
|
+
self
|
58
|
+
end
|
59
|
+
def self.config_name
|
60
|
+
"dummy"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
shared_examples "Common Event Transformation" do
|
3
|
+
let(:tag) { "140-rpm-beats" }
|
4
|
+
let(:config) do
|
5
|
+
{
|
6
|
+
"port" => 0,
|
7
|
+
"type" => "example",
|
8
|
+
"tags" => tag
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:input) do
|
13
|
+
LogStash::Inputs::Beats.new(config).tap do |i|
|
14
|
+
i.register
|
15
|
+
end
|
16
|
+
end
|
17
|
+
let(:event) { LogStash::Event.new(event_map) }
|
18
|
+
let(:event_map) do
|
19
|
+
{
|
20
|
+
"message" => "Hello world",
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "adds configured tags to the event" do
|
25
|
+
expect(subject.get("tags")).to include(tag)
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when the `beast.hotname` doesnt exist on the event" do
|
29
|
+
let(:already_exist) { "already_exist" }
|
30
|
+
let(:event_map) { super.merge({ "host" => already_exist }) }
|
31
|
+
|
32
|
+
it "doesnt change the value" do
|
33
|
+
expect(subject.get("host")).to eq(already_exist)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when the `beat.hostname` exist in the event" do
|
38
|
+
let(:producer_host) { "newhost01" }
|
39
|
+
let(:event_map) { super.merge({ "beat" => { "hostname" => producer_host }}) }
|
40
|
+
|
41
|
+
context "when `host` key doesn't exist on the event" do
|
42
|
+
it "copy the `beat.hostname` to `host` or backward compatibility" do
|
43
|
+
expect(subject.get("host")).to eq(producer_host)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when `host` key exists on the event" do
|
48
|
+
let(:already_exist) { "already_exist" }
|
49
|
+
let(:event_map) { super.merge({ "host" => already_exist }) }
|
50
|
+
|
51
|
+
it "doesn't override it" do
|
52
|
+
expect(subject.get("host")).to eq(already_exist)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|