spec/outputs/newrelic_spec.rb in logstash-output-newrelic-1.0.2 vs spec/outputs/newrelic_spec.rb in logstash-output-newrelic-1.0.3

- old
+ new

@@ -22,10 +22,17 @@ "retry_seconds" => retry_seconds, "max_delay" => max_delay, } } + # An arbitrary time to use in these tests, with different representations + class FixedTime + MILLISECONDS = 1562888528123 + ISO_8601_STRING_TIME = '2019-07-11T23:42:08.123Z' + LOGSTASH_TIMESTAMP = LogStash::Timestamp.coerce(ISO_8601_STRING_TIME) + end + def gunzip(bytes) gz = Zlib::GzipReader.new(StringIO.new(bytes)) gz.read end @@ -37,10 +44,20 @@ def multiple_gzipped_messages(body) JSON.parse(gunzip(body)) end + def now_in_milliseconds() + (Time.now.to_f * 1000).to_i # to_f gives seconds with a fractional portion + end + + def within_five_seconds_of(time_in_millis, expected_in_millis) + five_seconds_in_millis = 5 * 1000 + (time_in_millis - expected_in_millis).abs < five_seconds_in_millis + end + + before(:each) do @newrelic_output = LogStash::Plugin.lookup("output", "newrelic").new(simple_config) @newrelic_output.register end @@ -59,21 +76,22 @@ context "request headers" do it "all present" do stub_request(:any, base_uri).to_return(status: 200) - event = LogStash::Event.new({ "message" => "Test message" }) + event = LogStash::Event.new({:message => "Test message" }) @newrelic_output.multi_receive([event]) wait_for(a_request(:post, base_uri) .with(headers: { "X-Insert-Key" => api_key, "X-Event-Source" => "logs", "Content-Encoding" => "gzip", })).to have_been_made end end + context "request body" do it "message contains plugin information" do stub_request(:any, base_uri).to_return(status: 200) @@ -86,20 +104,51 @@ data['common']['attributes']['plugin']['type'] == 'logstash' && data['common']['attributes']['plugin']['version'] == LogStash::Outputs::NewRelicVersion::VERSION }) .to have_been_made end - # TODO: why is this field always removed? - it "'@timestamp' field is removed" do - stub_request(:any, base_uri).to_return(status: 200) - event = LogStash::Event.new({ :message => "Test message", :@timestamp => '123' }) - @newrelic_output.multi_receive([event]) + context "@timestamp field" do - wait_for(a_request(:post, base_uri) - .with { |request| single_gzipped_message(request.body)['@timestamp'] == nil }) - .to have_been_made + def test_timestamp(timestamp, message_matcher) + stub_request(:any, base_uri).to_return(status: 200) + + event = LogStash::Event.new({ :message => "Test message", :@timestamp => timestamp }) + @newrelic_output.multi_receive([event]) + + wait_for(a_request(:post, base_uri) + .with { |request| + message = single_gzipped_message(request.body) + message_matcher.call(message) + }).to have_been_made + end + + it "LogStash::Timestamp '@timestamp' field is added as 'timestamp' as milliseconds since epoch" do + def message_matcher(message) + message['timestamp'] == FixedTime::MILLISECONDS + end + + test_timestamp(FixedTime::LOGSTASH_TIMESTAMP, method(:message_matcher)) + end + + it "String ISO 8601 '@timestamp' field is added as 'timestamp' as milliseconds since epoch" do + def message_matcher(message) + message['timestamp'] == FixedTime::MILLISECONDS + end + + test_timestamp(FixedTime::ISO_8601_STRING_TIME, method(:message_matcher)) + end + + # Ideally we might not even set a timestamp if parsing fails. However, the time parsing library doesn't tell us if + # parsing fails -- it just returns the current time. + it "Unparseable '@timestamp' field is parsed as current time and put into 'timestamp'" do + def message_matcher(message) + within_five_seconds_of(message['timestamp'], now_in_milliseconds) + end + + test_timestamp("Not an ISO 8601 string", method(:message_matcher)) + end end it "all other fields passed through as is" do stub_request(:any, base_uri).to_return(status: 200) @@ -107,10 +156,9 @@ @newrelic_output.multi_receive([event]) wait_for(a_request(:post, base_uri) .with { |request| message = single_gzipped_message(request.body) - puts message message['message'] == 'Test message' && message['attributes']['other'] == 'Other value' }) .to have_been_made end