spec/support/event_collector.rb (146 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. # frozen_string_literal: true class EventCollector class TestAdapter < ElasticAPM::Transport::Connection def write(payload) EventCollector.catalog(JSON.parse(@metadata)) EventCollector.catalog JSON.parse(payload) end end class << self def method_missing(name, *args, **kw_args, &block) if instance.respond_to?(name) instance.send(name, *args, **kw_args, &block) else super end end def instance @instance ||= new end end attr_reader( :errors, :metadatas, :metricsets, :requests, :spans, :transactions ) def initialize @mutex = Mutex.new clear! end def catalog(json) @mutex.synchronize do case json.keys.first when 'transaction' then transactions << json.values.first when 'span' then spans << json.values.first when 'error' then errors << json.values.first when 'metricset' then metricsets << json.values.first when 'metadata' then metadatas << json.values.first end end end def clear! @requests = [] @errors = [] @metadatas = [] @metricsets = [] @spans = [] @transactions = [] end def transaction_metrics metrics = metricsets.select do |set| set && set['transaction'] && !set['span'] end if metrics.empty? puts metricsets end metrics end def span_metrics metrics = metricsets.select do |set| set && set['transaction'] && set['span'] end if metrics.empty? puts metricsets end metrics end # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def wait_for(timeout: 5, **expected) if expected.empty? && !block_given? raise ArgumentError, 'Either args or block required' end Timeout.timeout(timeout) do loop do sleep 0.01 missing = expected.reduce(0) do |total, (kind, count)| total + (count - send(kind).length) end next if missing > 0 unless missing == 0 if missing < 0 puts format( 'Expected %s. Got %s', expected, "#{missing.abs} extra" ) else puts format( 'Expected %s. Got %s', expected, "missing #{missing}" ) print_received end end if block_given? next unless yield(self) end break true end end rescue Timeout::Error puts format('Died waiting for %s', block_given? ? 'block' : expected) puts '--- Received: ---' print_received raise end # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def metricsets_summary metricsets.each_with_object( Hash.new { 0 } ) do |set, totals| next unless set['transaction'] count = set['samples']['span.self_time.count'] case set.dig('span', 'type') when 'app' subtype = set.dig('span', 'subtype') key = :"app_span_self_times__#{subtype || 'nil'}" next totals && totals[key] += count['value'] when 'template' totals && totals[:template_span_self_times] += count['value'] next else pp set raise 'Unmatched metric type' end end end # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity private def print_received pp( transactions: transactions.map { |o| o['name'] }, spans: spans.map { |o| o['name'] }, errors: errors.map { |o| o['culprit'] }, metricsets: metricsets, metadatas: metadatas.count ) end end RSpec.shared_context 'event_collector' do before do EventCollector.clear! end after do EventCollector.clear! end end