Skip to content

Commit

Permalink
Merge pull request #3036 from DataDog/non-monitor-detection
Browse files Browse the repository at this point in the history
  • Loading branch information
marcotc authored Aug 10, 2023
2 parents 75cb379 + cd17e14 commit 5c390e1
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ target :ddtrace do
library 'sinatra'
library 'google-protobuf'
library 'protobuf-cucumber'
library 'minitest'
library 'mysql2'
library 'mysql2-aurora'
library 'opentracing'
Expand Down
55 changes: 55 additions & 0 deletions lib/datadog/core/environment/execution.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Datadog
module Core
module Environment
# Provides information about the execution environment on the current process.
module Execution
class << self
# Is this process running in a development environment?
# This can be used to make decisions about when to enable
# background systems like worker threads or telemetry.
def development?
!!(repl? || test?)
end

private

# Is this process running a test?
def test?
rspec? || minitest?
end

# Is this process running inside on a Read–eval–print loop?
# DEV: REPLs always set the program name to the exact REPL name.
def repl?
REPL_PROGRAM_NAMES.include?($PROGRAM_NAME)
end

REPL_PROGRAM_NAMES = %w[irb pry].freeze
private_constant :REPL_PROGRAM_NAMES

# RSpec always runs using the `rspec` file https://github.com/rspec/rspec-core/blob/main/exe/rspec
def rspec?
$PROGRAM_NAME.end_with?(RSPEC_PROGRAM_NAME)
end

RSPEC_PROGRAM_NAME = '/rspec'
private_constant :RSPEC_PROGRAM_NAME

# Check if Minitest is present and installed to run.
def minitest?
# Minitest >= 5
(defined?(::Minitest) &&
::Minitest.class_variable_defined?(:@@installed_at_exit) &&
::Minitest.class_variable_get(:@@installed_at_exit)) ||
# Minitest < 5
(defined?(::Minitest::Unit) &&
::Minitest::Unit.class_variable_defined?(:@@installed_at_exit) &&
::Minitest::Unit.class_variable_get(:@@installed_at_exit))
end
end
end
end
end
end
19 changes: 19 additions & 0 deletions sig/datadog/core/environment/execution.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Datadog
module Core
module Environment
module Execution
def self.development?: () -> bool

private
def self.test?: () -> bool
def self.repl?: () -> bool

REPL_PROGRAM_NAMES: ::Array[::String]
def self.rspec?: () -> bool

RSPEC_PROGRAM_NAME: ::String
def self.minitest?: () -> bool
end
end
end
end
87 changes: 87 additions & 0 deletions spec/datadog/core/environment/execution_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# frozen_string_literal: true

require 'spec_helper'

require 'datadog/core/environment/execution'

RSpec.describe Datadog::Core::Environment::Execution do
describe '#development?' do
subject(:development?) { described_class.development? }

context 'when in an RSpec test' do
it { is_expected.to eq(true) }
end

context 'when not in an RSpec test' do
# RSpec is detected through the $PROGRAM_NAME.
# Changing it will make RSpec detection to return false.
#
# We change the $PROGRAM_NAME instead of stubbing
# `Datadog::Core::Environment::Execution.rspec?` because
# otherwise we'll have no real test for non-RSpec cases.
around do |example|
begin
original = $PROGRAM_NAME
$PROGRAM_NAME = 'not-rspec'
example.run
ensure
$PROGRAM_NAME = original
end
end

let(:repl_script) do
<<-RUBY
# Load the working directory version of `ddtrace`
lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'datadog/core/environment/execution'
# Print actual value to STDERR, as STDOUT tends to have more noise in REPL sessions.
STDERR.print Datadog::Core::Environment::Execution.development?
RUBY
end

it 'ensure RSpec detection returns false' do
is_expected.to eq(false)
end

context 'when in an IRB session' do
it 'returns true' do
_, err = Bundler.with_clean_env do # Ruby 2.6 does not have irb by default in a bundle, but has it outside of it.
Open3.capture3('irb', '--noprompt', '--noverbose', stdin_data: repl_script)
end
expect(err).to end_with('true')
end
end

context 'when in a Pry session' do
it 'returns true' do
Tempfile.create('test') do |f|
f.write(repl_script)
f.close

out, = Open3.capture2e('pry', '-f', '--noprompt', f.path)
expect(out).to eq('true')
end
end
end

context 'when in a Minitest test' do
before { skip('Minitest not in bundle') unless Gem.loaded_specs['minitest'] }

it 'returns true' do
expect_in_fork do
# Minitest reads CLI arguments, but the current process has RSpec
# arguments that are not relevant (nor compatible) with Minitest.
# This happens inside a fork, thus we don't have to reset it.
Object.const_set('ARGV', [])

require 'minitest/autorun'

is_expected.to eq(true)
end
end
end
end
end
end

0 comments on commit 5c390e1

Please sign in to comment.