Testing Clock Time Management Implementation in Fluentd
This test suite validates the Clock functionality in Fluentd, focusing on time manipulation and clock freezing capabilities. It ensures reliable time-based operations and clock state management across different scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
fluent/fluentd
test/test_clock.rb
require_relative 'helper'
require 'fluent/clock'
require 'timecop'
class ClockTest < ::Test::Unit::TestCase
teardown do
Fluent::Clock.return # call it always not to affect other tests
end
sub_test_case 'without any pre-operation' do
test 'clock can provides incremental floating point number based on second' do
c1 = Fluent::Clock.now
assert_kind_of Float, c1
sleep 1.1
c2 = Fluent::Clock.now
assert{ c2 >= c1 + 1.0 && c2 < c1 + 9.0 } # if clock returns deci-second (fantastic!), c2 should be larger than c1 + 10
end
test 'clock value will proceed even if timecop freezes Time' do
Timecop.freeze(Time.now) do
c1 = Fluent::Clock.now
assert_kind_of Float, c1
sleep 1.1
c2 = Fluent::Clock.now
assert{ c2 >= c1 + 1.0 && c2 < c1 + 9.0 }
end
end
end
sub_test_case 'using #freeze without any arguments' do
test 'Clock.freeze without arguments freezes clock with current clock value' do
c0 = Fluent::Clock.now
Fluent::Clock.freeze
c1 = Fluent::Clock.now
Fluent::Clock.return
c2 = Fluent::Clock.now
assert{ c0 <= c1 && c1 <= c2 }
end
test 'Clock.return raises an error if it is called in block' do
assert_raise RuntimeError.new("invalid return while running code in blocks") do
Fluent::Clock.freeze do
Fluent::Clock.return
end
end
end
end
sub_test_case 'using #freeze with clock value' do
test 'Clock.now always returns frozen time until #return called' do
c0 = Fluent::Clock.now
Fluent::Clock.freeze(c0)
assert_equal c0, Fluent::Clock.now
sleep 0.5
assert_equal c0, Fluent::Clock.now
sleep 0.6
assert_equal c0, Fluent::Clock.now
Fluent::Clock.return
c1 = Fluent::Clock.now
assert{ c1 >= c0 + 1.0 }
end
test 'Clock.now returns frozen time in the block argument of #freeze' do
c0 = Fluent::Clock.now
Fluent::Clock.freeze(c0) do
assert_equal c0, Fluent::Clock.now
sleep 0.5
assert_equal c0, Fluent::Clock.now
sleep 0.6
assert_equal c0, Fluent::Clock.now
end
c1 = Fluent::Clock.now
assert{ c1 >= c0 + 1.0 }
end
test 'Clock.now returns unfrozen value after jumping out from block by raising errors' do
c0 = Fluent::Clock.now
rescued_error = nil
begin
Fluent::Clock.freeze(c0) do
assert_equal c0, Fluent::Clock.now
sleep 0.5
assert_equal c0, Fluent::Clock.now
sleep 0.6
assert_equal c0, Fluent::Clock.now
raise "bye!"
end
rescue => e
rescued_error = e
end
assert rescued_error # ensure to rescue an error
c1 = Fluent::Clock.now
assert{ c1 >= c0 + 1.0 }
end
test 'Clock.return cancels all Clock.freeze effects by just once' do
c0 = Fluent::Clock.now
sleep 0.1
c1 = Fluent::Clock.now
sleep 0.1
c2 = Fluent::Clock.now
Fluent::Clock.freeze(c0)
sleep 0.1
assert_equal c0, Fluent::Clock.now
Fluent::Clock.freeze(c1)
sleep 0.1
assert_equal c1, Fluent::Clock.now
Fluent::Clock.freeze(c2)
sleep 0.1
assert_equal c2, Fluent::Clock.now
Fluent::Clock.return
assert{ Fluent::Clock.now > c2 }
end
test 'Clock.freeze allows nested blocks by itself' do
c0 = Fluent::Clock.now
sleep 0.1
c1 = Fluent::Clock.now
sleep 0.1
c2 = Fluent::Clock.now
Fluent::Clock.freeze(c0) do
sleep 0.1
assert_equal c0, Fluent::Clock.now
Fluent::Clock.freeze(c1) do
sleep 0.1
assert_equal c1, Fluent::Clock.now
Fluent::Clock.freeze(c2) do
sleep 0.1
assert_equal c2, Fluent::Clock.now
end
assert_equal c1, Fluent::Clock.now
end
assert_equal c0, Fluent::Clock.now
end
assert{ Fluent::Clock.now > c0 }
end
end
sub_test_case 'using #freeze with Time argument' do
test 'Clock.freeze returns the clock value which should be produced when the time is at the specified time' do
c0 = Fluent::Clock.now
t0 = Time.now
t1 = t0 - 30
assert_kind_of Time, t1
t2 = t0 + 30
assert_kind_of Time, t2
# 31 is for error of floating point value
Fluent::Clock.freeze(t1) do
c1 = Fluent::Clock.now
assert{ c1 >= c0 - 31 && c1 <= c0 - 31 + 10 } # +10 is for threading schedule error
end
# 29 is for error of floating point value
Fluent::Clock.freeze(t2) do
c2 = Fluent::Clock.now
assert{ c2 >= c0 + 29 && c2 <= c0 + 29 + 10 } # +10 is for threading schedule error
end
end
end
end