feat: support injected clock in ConditionSet for testability#204
Merged
DerekFrank merged 1 commit intoawslabs:mainfrom Apr 9, 2026
Merged
feat: support injected clock in ConditionSet for testability#204DerekFrank merged 1 commit intoawslabs:mainfrom
DerekFrank merged 1 commit intoawslabs:mainfrom
Conversation
ConditionSet.Set() used metav1.Now() (real clock) for LastTransitionTime.
Controllers that use a fake clock for time-dependent logic (e.g.,
checking elapsed time since a condition was set) get incorrect results
because the condition timestamp and the controller clock diverge.
Add a WithClock option to ConditionTypes.For() that injects a
clock.Clock into the ConditionSet. Defaults to clock.RealClock{}, so
existing callers are unaffected. Tests can pass a fake clock to get
deterministic LastTransitionTime values.
This fixes a class of test flakes in downstream projects (e.g.,
kubernetes-sigs/karpenter#2951) where controllers compare
clock.Since(condition.LastTransitionTime) using a fake clock but the
condition was stamped with real time.
2 tasks
jamesmt-aws
added a commit
to jamesmt-aws/karpenter
that referenced
this pull request
Apr 9, 2026
operatorpkg now supports an injected clock for ConditionSet (awslabs/operatorpkg#204), so LastTransitionTime can be stamped with a fake clock in tests. Use it. Replace the drainStartTimes sync.Map workaround with reading LastTransitionTime directly off the Drained condition. The termination controller now sets the Drained condition via StatusConditionsWithClock, which threads its injected clock through to operatorpkg's status.WithClock, so LastTransitionTime is stamped with the same clock the controller reads back. Add NodeClaim.StatusConditionsWithClock as a sibling to StatusConditions(). The variadic shape we'd normally use can't go on StatusConditions() itself because operatorpkg's status.Object interface requires a non-variadic signature.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ConditionSet.Set()usesmetav1.Now()forLastTransitionTime, which returns real wall clock time. Controllers that check elapsed time since a condition was set using an injected fake clock get incorrect results because the condition timestamp and the controller clock diverge.Add a
WithClockoption toConditionTypes.For():Defaults to
clock.RealClock{}, so existing callers are unaffected.Motivation
This fixes a class of test flakes in downstream projects. In kubernetes-sigs/karpenter, the termination controller checks
c.clock.Since(condition.LastTransitionTime)using a fake clock, butLastTransitionTimewas stamped withmetav1.Now(). The test "should not finish draining until minDrainTime has passed" fails deterministically because the fake clock and real clock diverge (kubernetes-sigs/karpenter#2951).The downstream workaround is to track timestamps separately using the injected clock, duplicating what
LastTransitionTimealready provides. This PR fixes the root cause.Changes
condition_set.go: Addclockfield toConditionSet,ForOptions/ForOption/WithClocktypes,now()helper. Replace twometav1.Now()calls withc.now().condition_set_test.go: Test thatWithClockcontrolsLastTransitionTimeon set, transition, and same-status update.Test plan
WithClock)LastTransitionTime