Skip to content

Commit

Permalink
Provide testing implementation of time.Now()
Browse files Browse the repository at this point in the history
Prior to this commit, the TaskRun and PipelineRun reconciler tests implicitly depended on the value of time.Now.
This commit allows tests to use a specific time as Now when reconciling TaskRuns and PipelineRuns.
No functional changes.
  • Loading branch information
lbernick committed Jan 14, 2022
1 parent b12b237 commit 64d9902
Show file tree
Hide file tree
Showing 20 changed files with 194 additions and 117 deletions.
5 changes: 3 additions & 2 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/clock"
"github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun"
"github.com/tektoncd/pipeline/pkg/reconciler/taskrun"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -100,8 +101,8 @@ func main() {

ctx = filteredinformerfactory.WithSelectors(ctx, v1beta1.ManagedByLabelKey)
sharedmain.MainWithConfig(ctx, ControllerLogKey, cfg,
taskrun.NewController(opts),
pipelinerun.NewController(opts),
taskrun.NewController(opts, clock.RealClock{}),
pipelinerun.NewController(opts, clock.RealClock{}),
)
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ package v1alpha1

import (
"fmt"
"time"

"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/clock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
Expand Down Expand Up @@ -161,7 +161,7 @@ func (pr *PipelineRun) GetRunKey() string {
}

// IsTimedOut returns true if a pipelinerun has exceeded its spec.Timeout based on its status.Timeout
func (pr *PipelineRun) IsTimedOut() bool {
func (pr *PipelineRun) IsTimedOut(c clock.Clock) bool {
pipelineTimeout := pr.Spec.Timeout
startTime := pr.Status.StartTime

Expand All @@ -170,7 +170,7 @@ func (pr *PipelineRun) IsTimedOut() bool {
if timeout == config.NoTimeoutDuration {
return false
}
runtime := time.Since(startTime.Time)
runtime := c.Since(startTime.Time)
if runtime > timeout {
return true
}
Expand Down
19 changes: 13 additions & 6 deletions pkg/apis/pipeline/v1alpha1/pipelinerun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ import (
"knative.dev/pkg/apis"
)

var now = time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)

type testClock struct{}

func (tc testClock) Now() time.Time { return now }
func (tc testClock) Since(t time.Time) time.Duration { return now.Sub(t) }

func TestPipelineRunStatusConditions(t *testing.T) {
p := &v1alpha1.PipelineRun{}
foo := &apis.Condition{
Expand Down Expand Up @@ -69,7 +76,7 @@ func TestInitializeConditions(t *testing.T) {
Namespace: "test-ns",
},
}
p.Status.InitializeConditions()
p.Status.InitializeConditions(testClock{})

if p.Status.TaskRuns == nil {
t.Fatalf("PipelineRun status not initialized correctly")
Expand All @@ -81,7 +88,7 @@ func TestInitializeConditions(t *testing.T) {

p.Status.TaskRuns["fooTask"] = &v1alpha1.PipelineRunTaskRunStatus{}

p.Status.InitializeConditions()
p.Status.InitializeConditions(testClock{})
if len(p.Status.TaskRuns) != 1 {
t.Fatalf("PipelineRun status getting reset")
}
Expand Down Expand Up @@ -192,17 +199,17 @@ func TestPipelineRunHasTimedOut(t *testing.T) {
}{{
name: "timedout",
timeout: 1 * time.Second,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: true,
}, {
name: "nottimedout",
timeout: 25 * time.Hour,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: false,
}, {
name: "notimeoutspecified",
timeout: 0 * time.Second,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: false,
},
}
Expand All @@ -226,7 +233,7 @@ func TestPipelineRunHasTimedOut(t *testing.T) {
},
}

if pr.IsTimedOut() != tc.expected {
if pr.IsTimedOut(testClock{}) != tc.expected {
t.Fatalf("Expected isTimedOut to be %t", tc.expected)
}
})
Expand Down
5 changes: 3 additions & 2 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
apisconfig "github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/clock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
Expand Down Expand Up @@ -211,7 +212,7 @@ func (tr *TaskRun) IsCancelled() bool {
}

// HasTimedOut returns true if the TaskRun runtime is beyond the allowed timeout
func (tr *TaskRun) HasTimedOut() bool {
func (tr *TaskRun) HasTimedOut(c clock.Clock) bool {
if tr.Status.StartTime.IsZero() {
return false
}
Expand All @@ -220,7 +221,7 @@ func (tr *TaskRun) HasTimedOut() bool {
if timeout == apisconfig.NoTimeoutDuration {
return false
}
runtime := time.Since(tr.Status.StartTime.Time)
runtime := c.Since(tr.Status.StartTime.Time)
return runtime > timeout
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/pipeline/v1alpha1/taskrun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func TestTaskRunHasStarted(t *testing.T) {
name: "trWithStartTime",
trStatus: v1alpha1.TaskRunStatus{
TaskRunStatusFields: v1alpha1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
StartTime: &metav1.Time{Time: now},
},
},
expectedValue: true,
Expand Down Expand Up @@ -312,7 +312,7 @@ func TestHasTimedOut(t *testing.T) {
},
},
TaskRunStatusFields: v1alpha1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Hour)},
StartTime: &metav1.Time{Time: now.Add(-15 * time.Hour)},
},
},
},
Expand All @@ -336,7 +336,7 @@ func TestHasTimedOut(t *testing.T) {
},
},
TaskRunStatusFields: v1alpha1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Second)},
StartTime: &metav1.Time{Time: now.Add(-15 * time.Second)},
},
},
},
Expand All @@ -345,7 +345,7 @@ func TestHasTimedOut(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := tc.taskRun.HasTimedOut()
result := tc.taskRun.HasTimedOut(testClock{})
if d := cmp.Diff(result, tc.expectedStatus); d != "" {
t.Fatalf(diff.PrintWantGot(d))
}
Expand Down
9 changes: 5 additions & 4 deletions pkg/apis/pipeline/v1beta1/pipelinerun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
apisconfig "github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
runv1alpha1 "github.com/tektoncd/pipeline/pkg/apis/run/v1alpha1"
"github.com/tektoncd/pipeline/pkg/clock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -153,15 +154,15 @@ func (pr *PipelineRun) GetNamespacedName() types.NamespacedName {
}

// HasTimedOut returns true if a pipelinerun has exceeded its spec.Timeout based on its status.Timeout
func (pr *PipelineRun) HasTimedOut(ctx context.Context) bool {
func (pr *PipelineRun) HasTimedOut(ctx context.Context, c clock.Clock) bool {
timeout := pr.PipelineTimeout(ctx)
startTime := pr.Status.StartTime

if !startTime.IsZero() {
if timeout == config.NoTimeoutDuration {
return false
}
runtime := time.Since(startTime.Time)
runtime := c.Since(startTime.Time)
if runtime > timeout {
return true
}
Expand Down Expand Up @@ -340,7 +341,7 @@ func (pr *PipelineRunStatus) GetCondition(t apis.ConditionType) *apis.Condition

// InitializeConditions will set all conditions in pipelineRunCondSet to unknown for the PipelineRun
// and set the started time to the current time
func (pr *PipelineRunStatus) InitializeConditions() {
func (pr *PipelineRunStatus) InitializeConditions(c clock.Clock) {
started := false
if pr.TaskRuns == nil {
pr.TaskRuns = make(map[string]*PipelineRunTaskRunStatus)
Expand All @@ -349,7 +350,7 @@ func (pr *PipelineRunStatus) InitializeConditions() {
pr.Runs = make(map[string]*PipelineRunRunStatus)
}
if pr.StartTime.IsZero() {
pr.StartTime = &metav1.Time{Time: time.Now()}
pr.StartTime = &metav1.Time{Time: c.Now()}
started = true
}
conditionManager := pipelineRunCondSet.Manage(pr)
Expand Down
23 changes: 15 additions & 8 deletions pkg/apis/pipeline/v1beta1/pipelinerun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ import (
"knative.dev/pkg/apis"
)

var now = time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)

type testClock struct{}

func (tc testClock) Now() time.Time { return now }
func (tc testClock) Since(t time.Time) time.Duration { return now.Sub(t) }

func TestPipelineRunStatusConditions(t *testing.T) {
p := &v1beta1.PipelineRun{}
foo := &apis.Condition{
Expand Down Expand Up @@ -70,7 +77,7 @@ func TestInitializePipelineRunConditions(t *testing.T) {
Namespace: "test-ns",
},
}
p.Status.InitializeConditions()
p.Status.InitializeConditions(testClock{})

if p.Status.TaskRuns == nil {
t.Fatalf("PipelineRun TaskRun status not initialized correctly")
Expand Down Expand Up @@ -99,7 +106,7 @@ func TestInitializePipelineRunConditions(t *testing.T) {
Message: "hello",
})

p.Status.InitializeConditions()
p.Status.InitializeConditions(testClock{})
if len(p.Status.TaskRuns) != 1 {
t.Fatalf("PipelineRun TaskRun status getting reset")
}
Expand Down Expand Up @@ -199,7 +206,7 @@ func TestPipelineRunHasStarted(t *testing.T) {
name: "prWithStartTime",
prStatus: v1beta1.PipelineRunStatus{
PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
StartTime: &metav1.Time{Time: now},
},
},
expectedValue: true,
Expand Down Expand Up @@ -237,17 +244,17 @@ func TestPipelineRunHasTimedOut(t *testing.T) {
}{{
name: "timedout",
timeout: 1 * time.Second,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: true,
}, {
name: "nottimedout",
timeout: 25 * time.Hour,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: false,
}, {
name: "notimeoutspecified",
timeout: 0 * time.Second,
starttime: time.Now().AddDate(0, 0, -1),
starttime: now.AddDate(0, 0, -1),
expected: false,
},
}
Expand All @@ -263,7 +270,7 @@ func TestPipelineRunHasTimedOut(t *testing.T) {
StartTime: &metav1.Time{Time: tc.starttime},
}},
}
if pr.HasTimedOut(context.Background()) != tc.expected {
if pr.HasTimedOut(context.Background(), testClock{}) != tc.expected {
t.Errorf("Expected HasTimedOut to be %t when using pipeline.timeout", tc.expected)
}
})
Expand All @@ -278,7 +285,7 @@ func TestPipelineRunHasTimedOut(t *testing.T) {
}},
}

if pr.HasTimedOut(context.Background()) != tc.expected {
if pr.HasTimedOut(context.Background(), testClock{}) != tc.expected {
t.Errorf("Expected HasTimedOut to be %t when using pipeline.timeouts.pipeline", tc.expected)
}
})
Expand Down
5 changes: 3 additions & 2 deletions pkg/apis/pipeline/v1beta1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/tektoncd/pipeline/pkg/apis/config"
apisconfig "github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/clock"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -384,7 +385,7 @@ func (tr *TaskRun) IsCancelled() bool {
}

// HasTimedOut returns true if the TaskRun runtime is beyond the allowed timeout
func (tr *TaskRun) HasTimedOut(ctx context.Context) bool {
func (tr *TaskRun) HasTimedOut(ctx context.Context, c clock.Clock) bool {
if tr.Status.StartTime.IsZero() {
return false
}
Expand All @@ -393,7 +394,7 @@ func (tr *TaskRun) HasTimedOut(ctx context.Context) bool {
if timeout == apisconfig.NoTimeoutDuration {
return false
}
runtime := time.Since(tr.Status.StartTime.Time)
runtime := c.Since(tr.Status.StartTime.Time)
return runtime > timeout
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/pipeline/v1beta1/taskrun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func TestTaskRunHasStarted(t *testing.T) {
name: "trWithStartTime",
trStatus: v1beta1.TaskRunStatus{
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now()},
StartTime: &metav1.Time{Time: now},
},
},
expectedValue: true,
Expand Down Expand Up @@ -283,7 +283,7 @@ func TestHasTimedOut(t *testing.T) {
}},
},
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Hour)},
StartTime: &metav1.Time{Time: now.Add(-15 * time.Hour)},
},
},
},
Expand All @@ -304,7 +304,7 @@ func TestHasTimedOut(t *testing.T) {
}},
},
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Second)},
StartTime: &metav1.Time{Time: now.Add(-15 * time.Second)},
},
},
},
Expand All @@ -313,7 +313,7 @@ func TestHasTimedOut(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := tc.taskRun.HasTimedOut(context.Background())
result := tc.taskRun.HasTimedOut(context.Background(), testClock{})
if d := cmp.Diff(result, tc.expectedStatus); d != "" {
t.Fatalf(diff.PrintWantGot(d))
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/clock/clock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package clock

import "time"

// Clock provides functions to get the current time and the duration of time elapsed since the current time
type Clock interface {
Now() time.Time
Since(t time.Time) time.Duration
}

// RealClock implements Clock based on the actual time
type RealClock struct{}

// Now returns the current time
func (RealClock) Now() time.Time { return time.Now() }

// Since returns the duration of time elapsed since the current time
func (RealClock) Since(t time.Time) time.Duration { return time.Since(t) }
Loading

0 comments on commit 64d9902

Please sign in to comment.