From f0bda0cd88c6f1f9dc243cf02a3d9e4a5220c908 Mon Sep 17 00:00:00 2001 From: Roger Peppe Date: Tue, 14 May 2019 20:34:43 +0100 Subject: [PATCH] slim dependencies; add go.mod People don't like large dependencies and Go modules includes test dependencies too, so it's nice to trim down a bit and be a little less opinonated in the API (making the loggo dependency optional if you wish to plug it in). --- .travis.yml | 10 +++++ dependencies.tsv | 11 ----- go.mod | 5 +++ go.sum | 9 +++++ monotonic/monotonic_test.go | 15 +------ testclock/clock.go | 14 +++++-- testclock/clock_test.go | 80 +++++++++++++++++++------------------ 7 files changed, 77 insertions(+), 67 deletions(-) create mode 100644 .travis.yml delete mode 100644 dependencies.tsv create mode 100644 go.mod create mode 100644 go.sum diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fa122d2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: go +go_import_path: github.com/juju/clock +go: + - "1.11.x" + - "1.12.x" +env: + global: + - GO111MODULE=on +install: "echo no install step required" +script: go test ./... diff --git a/dependencies.tsv b/dependencies.tsv deleted file mode 100644 index d5fe896..0000000 --- a/dependencies.tsv +++ /dev/null @@ -1,11 +0,0 @@ -github.com/juju/errors git 1b5e39b83d1835fa480e0c2ddefb040ee82d58b3 2015-09-16T12:56:42Z -github.com/juju/loggo git 8232ab8918d91c72af1a9fb94d3edbe31d88b790 2017-06-05T01:46:07Z -github.com/juju/retry git 62c62032529169c7ec02fa48f93349604c345e1f 2015-10-29T02:48:21Z -github.com/juju/testing git c84dd6ba038a9012fb7830d206a006915b6e7937 2018-08-07T04:45:55Z -github.com/juju/utils git 2000ea4ff0431598aec2b7e1d11d5d49b5384d63 2018-04-24T09:41:59Z -github.com/juju/version git 1f41e27e54f21acccf9b2dddae063a782a8a7ceb 2016-10-31T05:19:06Z -golang.org/x/crypto git 650f4a345ab4e5b245a3034b110ebc7299e68186 2018-02-14T00:00:28Z -golang.org/x/net git 61147c48b25b599e5b561d2e9c4f3e1ef489ca41 2018-04-06T21:48:16Z -gopkg.in/check.v1 git 4f90aeace3a26ad7021961c297b22c42160c7b25 2016-01-05T16:49:36Z -gopkg.in/mgo.v2 git f2b6f6c918c452ad107eec89615f074e3bd80e33 2016-08-18T01:52:18Z -gopkg.in/yaml.v2 git 1be3d31502d6eabc0dd7ce5b0daab022e14a5538 2017-07-12T05:45:46Z diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c93dee9 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/juju/clock + +go 1.13 + +require github.com/frankban/quicktest v1.2.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6c29888 --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42 h1:q3pnF5JFBNRz8sRD+IRj7Y6DMyYGTNqnZ9axTbSfoNI= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= diff --git a/monotonic/monotonic_test.go b/monotonic/monotonic_test.go index b57fe42..8289487 100644 --- a/monotonic/monotonic_test.go +++ b/monotonic/monotonic_test.go @@ -7,26 +7,15 @@ import ( "testing" "time" - gc "gopkg.in/check.v1" - "github.com/juju/clock/monotonic" ) -func TestPackage(t *testing.T) { - gc.TestingT(t) -} - -type MonotonicSuite struct { -} - -var _ = gc.Suite(&MonotonicSuite{}) - -func (s *MonotonicSuite) TestNow(c *gc.C) { +func TestNow(t *testing.T) { var prev time.Duration for i := 0; i < 1000; i++ { val := monotonic.Now() if val < prev { - c.Fatal("now is less than previous value") + t.Fatal("now is less than previous value") } prev = val } diff --git a/testclock/clock.go b/testclock/clock.go index 9a2d710..7aef820 100644 --- a/testclock/clock.go +++ b/testclock/clock.go @@ -11,8 +11,6 @@ import ( "time" "github.com/juju/clock" - "github.com/juju/errors" - "github.com/juju/loggo" ) // timer implements a mock clock.Timer for testing purposes. @@ -44,6 +42,7 @@ func (t *timer) Chan() <-chan time.Time { // Clock implements a mock clock.Clock for testing purposes. type Clock struct { mu sync.Mutex + log func(string) now time.Time waiting []*timer // timers waiting to fire, sorted by deadline. notifyAlarms chan struct{} @@ -55,11 +54,18 @@ type Clock struct { // Alarms chan to keep the buffer clear. func NewClock(now time.Time) *Clock { return &Clock{ + log: func(string) {}, now: now, notifyAlarms: make(chan struct{}, 10000), } } +// SetLog sets the log function that's called if something that probably +// shouldn't happen occurs. +func (clock *Clock) SetLog(log func(msg string)) { + clock.log = log +} + // Now is part of the clock.Clock interface. func (clock *Clock) Now() time.Time { clock.mu.Lock() @@ -109,7 +115,7 @@ func (clock *Clock) Advance(d time.Duration) { defer clock.mu.Unlock() clock.now = clock.now.Add(d) if len(clock.waiting) == 0 { - loggo.GetLogger("juju.clock").Debugf("advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures") + clock.log("advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures") } clock.triggerAll() } @@ -141,7 +147,7 @@ func (clock *Clock) WaitAdvance(d, w time.Duration, n int) error { stacks += fmt.Sprintf("timer deadline: %v\n%s", t.deadline, string(t.stack)) } clock.mu.Unlock() - return errors.Errorf( + return fmt.Errorf( "got %d timers added after waiting %s: wanted %d, stacks:\n%s", got, w.String(), n, stacks) case <-next: diff --git a/testclock/clock_test.go b/testclock/clock_test.go index c3ff4c8..7222d4a 100644 --- a/testclock/clock_test.go +++ b/testclock/clock_test.go @@ -4,32 +4,22 @@ package testclock_test import ( + "bytes" + "fmt" "sync" - gotesting "testing" + "testing" "time" - "github.com/juju/loggo" - "github.com/juju/testing" - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" + qt "github.com/frankban/quicktest" "github.com/juju/clock/testclock" ) -type clockSuite struct { - testing.LoggingSuite -} - -func TestAll(t *gotesting.T) { - gc.TestingT(t) -} - -var _ = gc.Suite(&clockSuite{}) - -func (*clockSuite) TestNow(c *gc.C) { +func TestNow(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) - c.Assert(cl.Now(), gc.Equals, t0) + c.Assert(cl.Now(), qt.Equals, t0) } var ( @@ -37,41 +27,47 @@ var ( longWait = time.Second ) -func (*clockSuite) TestAdvanceLogs(c *gc.C) { - loggo.GetLogger("juju.clock").SetLogLevel(loggo.DEBUG) +func TestAdvanceLogs(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) + var logBuf bytes.Buffer + cl.SetLog(func(msg string) { + fmt.Fprintln(&logBuf, msg) + }) // Shouldn't log anything. - t := cl.After(time.Second) + tc := cl.After(time.Second) cl.Advance(time.Minute) - <-t - c.Check(c.GetTestLog(), jc.DeepEquals, "") + <-tc + c.Check(logBuf.Bytes(), qt.HasLen, 0) // Should log since nothing's waiting. cl.Advance(time.Hour) - c.Check(c.GetTestLog(), jc.Contains, "advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures") + c.Check(logBuf.String(), qt.Equals, "advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures\n") } -func (*clockSuite) TestWaitAdvance(c *gc.C) { +func TestWaitAdvance(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) // It is legal to just say 'nothing is waiting' err := cl.WaitAdvance(0, 0, 0) - c.Check(err, jc.ErrorIsNil) + c.Check(err, qt.Equals, nil) // Test that no timers errors out. err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1) - c.Check(err, gc.ErrorMatches, "got 0 timers added after waiting 10ms: wanted 1, stacks:\n") + c.Check(err, qt.ErrorMatches, "got 0 timers added after waiting 10ms: wanted 1, stacks:\n") // Test that a timer doesn't error. _ = cl.After(time.Nanosecond) err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1) - c.Check(err, jc.ErrorIsNil) + c.Check(err, qt.Equals, nil) } -func (*clockSuite) TestAdvanceWithAfter(c *gc.C) { +func TestAdvanceWithAfter(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) ch := cl.After(time.Second) @@ -112,10 +108,11 @@ func (*clockSuite) TestAdvanceWithAfter(c *gc.C) { case <-time.After(longWait): c.Fatalf("expected event to be triggered") } - c.Assert(cl.Now().UTC(), gc.Equals, t0.Add(4*time.Second).UTC()) + c.Assert(cl.Now().UTC(), qt.Equals, t0.Add(4*time.Second).UTC()) } -func (*clockSuite) TestAdvanceWithAfterFunc(c *gc.C) { +func TestAdvanceWithAfterFunc(t *testing.T) { + c := qt.New(t) // Most of the details have been checked in TestAdvanceWithAfter, // so just check that AfterFunc is wired up correctly. t0 := time.Now() @@ -132,7 +129,8 @@ func (*clockSuite) TestAdvanceWithAfterFunc(c *gc.C) { } } -func (*clockSuite) TestAfterFuncStop(c *gc.C) { +func TestAfterFuncStop(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) fired := make(chan struct{}) @@ -148,14 +146,15 @@ func (*clockSuite) TestAfterFuncStop(c *gc.C) { } } -func (*clockSuite) TestNewTimerReset(c *gc.C) { +func TestNewTimerReset(t *testing.T) { + c := qt.New(t) t0 := time.Now() cl := testclock.NewClock(t0) timer := cl.NewTimer(time.Second) cl.Advance(time.Second) select { case t := <-timer.Chan(): - c.Assert(t.UTC(), gc.Equals, t0.Add(time.Second).UTC()) + c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second).UTC()) case <-time.After(longWait): c.Fatalf("expected event to be triggered") } @@ -164,13 +163,14 @@ func (*clockSuite) TestNewTimerReset(c *gc.C) { cl.Advance(100 * time.Millisecond) select { case t := <-timer.Chan(): - c.Assert(t.UTC(), gc.Equals, t0.Add(time.Second+100*time.Millisecond).UTC()) + c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second+100*time.Millisecond).UTC()) case <-time.After(longWait): c.Fatalf("expected event to be triggered") } } -func (*clockSuite) TestNewTimerAsyncReset(c *gc.C) { +func TestNewTimerAsyncReset(t *testing.T) { + c := qt.New(t) t0 := time.Now() clock := testclock.NewClock(t0) timer := clock.NewTimer(time.Hour) @@ -219,7 +219,8 @@ func (*clockSuite) TestNewTimerAsyncReset(c *gc.C) { wg.Wait() } -func (*clockSuite) TestNewTimerResetCausesWakeup(c *gc.C) { +func TestNewTimerResetCausesWakeup(t *testing.T) { + c := qt.New(t) t0 := time.Now() clock := testclock.NewClock(t0) timer1 := clock.NewTimer(time.Hour) @@ -231,7 +232,7 @@ func (*clockSuite) TestNewTimerResetCausesWakeup(c *gc.C) { defer wg.Done() select { case t := <-timer1.Chan(): - c.Check(t0, gc.Equals, t) + c.Check(t0, qt.Equals, t) case <-time.After(longWait): c.Errorf("timer1 took too long to wake up") } @@ -252,7 +253,7 @@ func (*clockSuite) TestNewTimerResetCausesWakeup(c *gc.C) { select { case t := <-timer3.Chan(): // Even though the reset was negative, it triggers at 'now' - c.Check(t0, gc.Equals, t) + c.Check(t0, qt.Equals, t) case <-time.After(longWait): c.Errorf("timer3 took too long to wake up") } @@ -264,7 +265,8 @@ func (*clockSuite) TestNewTimerResetCausesWakeup(c *gc.C) { wg.Wait() } -func (*clockSuite) TestMultipleWaiters(c *gc.C) { +func TestMultipleWaiters(t *testing.T) { + c := qt.New(t) var wg sync.WaitGroup t0 := time.Date(2000, 01, 01, 01, 0, 0, 0, time.UTC) cl := testclock.NewClock(t0)