Skip to content

Commit

Permalink
internal: Abstract time with fxclock
Browse files Browse the repository at this point in the history
Add an internal fxclock package that provides a minimal Clock interface.

We will use this to abstract away Fx's use of time operations to help
address test flakiness issues.
  • Loading branch information
abhinav committed Nov 19, 2021
1 parent dbe9bdb commit 2b4e675
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module go.uber.org/fx
go 1.13

require (
github.com/benbjohnson/clock v1.3.0
github.com/stretchr/testify v1.7.0
go.uber.org/dig v1.12.0
go.uber.org/goleak v1.1.11
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
58 changes: 58 additions & 0 deletions internal/fxclock/clock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package fxclock

import (
"context"
"time"
)

// Clock defines how Fx accesses time.
// The interface is pretty minimal but it matches github.com/benbjohnson/clock.
// We intentionally don't use that interface directly;
// this keeps it a test dependency for us.
type Clock interface {
Now() time.Time
Since(time.Time) time.Duration
Sleep(time.Duration)
WithTimeout(context.Context, time.Duration) (context.Context, context.CancelFunc)
}

// System is the default implementation of Clock based on real time.
var System Clock = systemClock{}

type systemClock struct{}

func (systemClock) Now() time.Time {
return time.Now()
}

func (systemClock) Since(t time.Time) time.Duration {
return time.Since(t)
}

func (systemClock) Sleep(d time.Duration) {
time.Sleep(d)
}

func (systemClock) WithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(ctx, d)
}
65 changes: 65 additions & 0 deletions internal/fxclock/clock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package fxclock

import (
"context"
"testing"
"time"

"github.com/benbjohnson/clock"
"github.com/stretchr/testify/assert"
)

var _ Clock = clock.Clock(nil)

// Just a basic sanity check that everything is in order.
func TestSystemClock(t *testing.T) {
t.Parallel()

clock := System

t.Run("Now and Since", func(t *testing.T) {
t.Parallel()

before := clock.Now()
assert.GreaterOrEqual(t, clock.Since(before), time.Duration(0))
})

t.Run("Sleep", func(t *testing.T) {
t.Parallel()

assert.NotPanics(t, func() {
clock.Sleep(time.Millisecond)
})
})

t.Run("WithTimeout", func(t *testing.T) {
t.Parallel()

ctx := context.Background()
ctx, cancel := clock.WithTimeout(ctx, time.Second)
defer cancel()

_, ok := ctx.Deadline()
assert.True(t, ok, "must have deadline")
})
}

0 comments on commit 2b4e675

Please sign in to comment.