Skip to content

Commit 9ec713d

Browse files
authored
Merge pull request #242 from DataDog/anmarchenko/timecop_mock_process_clock_issue
[SDTEST-482] Use correct monotonic clock time if Timecop.mock_process_clock is set
2 parents fc40f77 + 1ef2028 commit 9ec713d

File tree

4 files changed

+35
-11
lines changed

4 files changed

+35
-11
lines changed

lib/datadog/ci/configuration/components.rb

+25-11
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,8 @@ def activate_ci!(settings)
8080
# startup logs are useless for test visibility and create noise
8181
settings.diagnostics.startup_logs.enabled = false
8282

83-
# When timecop is present, Time.now is mocked and .now_without_mock_time is added on Time to
84-
# get the current time without the mock.
85-
if timecop?
86-
settings.time_now_provider = -> do
87-
Time.now_without_mock_time
88-
rescue NoMethodError
89-
# fallback to normal Time.now if Time.now_without_mock_time is not defined for any reason
90-
Time.now
91-
end
92-
end
83+
# timecop configuration
84+
configure_time_providers(settings)
9385

9486
# Configure Datadog::Tracing module
9587

@@ -182,7 +174,6 @@ def build_test_visibility_api(settings)
182174
# Tests are running without CI visibility enabled
183175
settings.ci.enabled = false
184176
end
185-
186177
else
187178
Datadog.logger.debug("CI visibility configured to use agent transport via EVP proxy")
188179

@@ -299,6 +290,29 @@ def configure_telemetry(settings)
299290
end
300291
end
301292

293+
# When timecop is present:
294+
# - Time.now is mocked and .now_without_mock_time is added on Time to get the current time without the mock.
295+
# - Process.clock_gettime is mocked and .clock_gettime_without_mock is added on Process to get the monotonic time without the mock.
296+
def configure_time_providers(settings)
297+
return unless timecop?
298+
299+
settings.time_now_provider = -> do
300+
Time.now_without_mock_time
301+
rescue NoMethodError
302+
# fallback to normal Time.now if Time.now_without_mock_time is not defined for any reason
303+
Time.now
304+
end
305+
306+
if defined?(Process.clock_gettime_without_mock)
307+
settings.get_time_provider = ->(unit = :float_second) do
308+
::Process.clock_gettime_without_mock(::Process::CLOCK_MONOTONIC, unit)
309+
rescue NoMethodError
310+
# fallback to normal Process.clock_gettime if Process.clock_gettime_without_mock is not defined for any reason
311+
Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit)
312+
end
313+
end
314+
end
315+
302316
def timecop?
303317
Gem.loaded_specs.key?("timecop") || !!defined?(Timecop)
304318
end

sig/datadog/ci/configuration/components.rbs

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ module Datadog
4040

4141
def configure_telemetry: (untyped settings) -> void
4242

43+
def configure_time_providers: (untyped settings) -> void
44+
4345
def timecop?: () -> bool
4446
end
4547
end

spec/datadog/ci/contrib/timecop/instrumentation_spec.rb

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
Minitest::Runnable.reset
1414

1515
Timecop.freeze(time_1990)
16+
Timecop.mock_process_clock = true
1617

1718
class SomeTest < Minitest::Test
1819
def test_pass
@@ -25,6 +26,9 @@ def test_pass
2526

2627
it "does not set frozen time when setting start time for traces" do
2728
expect(first_test_span.start_time).not_to eq(time_1990)
29+
expect(first_test_span.duration).not_to eq(0)
30+
2831
expect(test_session_span.start_time).not_to eq(time_1990)
32+
expect(test_session_span.duration).not_to eq(0)
2933
end
3034
end

vendor/rbs/timecop/0/timecop.rbs

+4
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@ class Time
22
def self.now_without_mock_time: () -> Time
33
end
44

5+
module Process
6+
def self.clock_gettime_without_mock: (untyped clock, untyped unit) -> Numeric
7+
end
8+
59
class Timecop
610
end

0 commit comments

Comments
 (0)