spec/integration/mongo_spec.rb (155 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 require 'integration_helper' require 'mongo' module ElasticAPM RSpec.describe 'Spy: MongoDB' do let(:url) do ENV.fetch('MONGODB_URL', '127.0.0.1:27017') end it 'instruments db admin commands', :intercept do with_agent do client = Mongo::Client.new( [url], database: 'elastic-apm-test', logger: Logger.new(nil), server_selection_timeout: 5 ) ElasticAPM.with_transaction 'Mongo test' do client.database.collections end client.close end span, = @intercepted.spans expect(span.name).to eq 'elastic-apm-test.listCollections' expect(span.type).to eq 'db' expect(span.subtype).to eq 'mongodb' expect(span.action).to eq 'query' expect(span.duration).to_not be_nil expect(span.outcome).to eq 'success' db = span.context.db expect(db.instance).to eq 'elastic-apm-test' expect(db.type).to eq 'mongodb' expect(db.statement).to include('{"listCollections"=>1, "cursor"=>{}, ' \ '"nameOnly"=>true') .or include('{"listCollections" => 1, "cursor" => {}, ' \ '"nameOnly" => true') expect(db.user).to be nil end it 'instruments commands on collections', :intercept do with_agent do client = Mongo::Client.new( [url], database: 'elastic-apm-test', logger: Logger.new(nil), server_selection_timeout: 5 ) client['testing'].drop client['testing'].create ElasticAPM.with_transaction 'Mongo test' do client['testing'].delete_many end client['testing'].drop client.close end span, = @intercepted.spans expect(span.name).to eq 'elastic-apm-test.testing.delete' expect(span.type).to eq 'db' expect(span.subtype).to eq 'mongodb' expect(span.action).to eq 'query' expect(span.duration).to_not be_nil db = span.context.db expect(db.instance).to eq 'elastic-apm-test' expect(db.type).to eq 'mongodb' expect(db.statement).to match('"delete"=>"testing"') .or match('"delete" => "testing"') expect(db.user).to be nil end it 'instruments commands with special BSON types', :intercept do with_agent do client = Mongo::Client.new( [url], database: 'elastic-apm-test', logger: Logger.new(nil), server_selection_timeout: 5 ) ElasticAPM.with_transaction 'Mongo test' do client['testing'].find(a: BSON::Decimal128.new('1')).to_a end client.close end span, = @intercepted.spans expect(span.name).to eq 'elastic-apm-test.testing.find' expect(span.type).to eq 'db' expect(span.subtype).to eq 'mongodb' expect(span.action).to eq 'query' expect(span.duration).to_not be_nil db = span.context.db expect(db.instance).to eq 'elastic-apm-test' expect(db.type).to eq 'mongodb' expect(db.statement).to include('{"a"=>BSON::Decimal128(\'1\')}') .or include('{"a" => BSON::Decimal128(\'1\')}') expect(db.user).to be nil end it 'instruments getMore comments', :intercept do with_agent do client = Mongo::Client.new( [url], database: 'elastic-apm-test', logger: Logger.new(nil), server_selection_timeout: 5 ) 3.times { |i| client['testing'].insert_one(a: i) } ElasticAPM.with_transaction 'Mongo test' do client['testing'].find({}, batch_size: 2).to_a end client.close end find_span, get_more_span = @intercepted.spans expect(find_span.name).to eq 'elastic-apm-test.testing.find' expect(find_span.type).to eq 'db' expect(find_span.subtype).to eq 'mongodb' expect(find_span.action).to eq 'query' expect(find_span.duration).to_not be_nil db = find_span.context.db expect(db.instance).to eq 'elastic-apm-test' expect(db.type).to eq 'mongodb' expect(db.statement).to include('{"find"=>"testing"') .or include('{"find" => "testing"') expect(db.user).to be nil expect(get_more_span.name).to eq 'elastic-apm-test.testing.getMore' expect(get_more_span.type).to eq 'db' expect(get_more_span.subtype).to eq 'mongodb' expect(get_more_span.action).to eq 'query' expect(get_more_span.duration).to_not be_nil db = get_more_span.context.db expect(db.instance).to eq 'elastic-apm-test' expect(db.type).to eq 'mongodb' expect(db.statement).to include('{"getMore"=>#<BSON::Int64') .or include('{"getMore" => #<BSON::Int64') expect(db.user).to be nil end it 'sets outcome to `failure` for failed operations', :intercept do with_agent do client = Mongo::Client.new( [url], database: 'elastic-apm-test', logger: Logger.new(nil), server_selection_timeout: 1 ) ElasticAPM.with_transaction 'Mongo test' do begin client['testing'].find('$or' => true).to_a rescue end end client.close end span, = @intercepted.spans expect(span.outcome).to eq 'failure' end end end