pax_global_header00006660000000000000000000000064127003073420014510gustar00rootroot0000000000000052 comment=783ffacd5f6c1829c88caf121026fb8d57637cbb clock-1.0/000077500000000000000000000000001270030734200124435ustar00rootroot00000000000000clock-1.0/.travis.yml000066400000000000000000000000661270030734200145560ustar00rootroot00000000000000language: go go: - 1.3 - 1.4 - 1.5 sudo: falseclock-1.0/LICENSE000066400000000000000000000021271270030734200134520ustar00rootroot00000000000000The MIT License (MIT) Copyright © 2014 Jeff Hodges 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.clock-1.0/README.md000066400000000000000000000017711270030734200137300ustar00rootroot00000000000000clock ==== [![Build Status](https://travis-ci.org/jmhodges/clock.png?branch=master)](https://travis-ci.org/jmhodges/clock) Package clock provides an abstraction for system time that enables testing of time-sensitive code. Where you'd use time.Now, instead use clk.Now where clk is an instance of Clock. When running your code in production, pass it a Clock given by Default() and when you're running it in your tests, pass it an instance of Clock from NewFake(). When you do that, you can use FakeClock's Add and Set methods to control how time behaves in your code making them more reliable while also expanding the space of problems you can test. This code intentionally does not attempt to provide an abstraction over time.Ticker and time.Timer because Go does not have the runtime or API hooks available to do reliably. See https://github.com/golang/go/issues/8869 Be sure to test Time equality with time.Time#Equal, not ==. For documentation, see the [godoc](http://godoc.org/github.com/jmhodges/clock). clock-1.0/clock.go000066400000000000000000000130301270030734200140620ustar00rootroot00000000000000// Package clock provides an abstraction for system time that enables // testing of time-sensitive code. // // Where you'd use time.Now, instead use clk.Now where clk is an // instance of Clock. // // When running your code in production, pass it a Clock given by // Default() and when you're running it in your tests, pass it an // instance of Clock from NewFake(). // // When you do that, you can use FakeClock's Add and Set methods to // control how time behaves in your code making them more reliable // while also expanding the space of problems you can test. // // This code intentionally does not attempt to provide an abstraction // over time.Ticker and time.Timer because Go does not have the // runtime or API hooks available to do reliably. See // https://github.com/golang/go/issues/8869 // // Be sure to test Time equality with time.Time#Equal, not ==. package clock import ( "sort" "sync" "time" ) var systemClock Clock = sysClock{} // Default returns a Clock that matches the actual system time. func Default() Clock { // This is a method instead of a public var to prevent folks from // "making things work" by writing to the var instead of passing // in a Clock. return systemClock } // Clock is an abstraction over system time. New instances of it can // be made with Default and NewFake. type Clock interface { // Now returns the Clock's current view of the time. Mutating the // returned Time will not mutate the clock's time. Now() time.Time // Sleep causes the current goroutine to sleep for the given duration. Sleep(time.Duration) // After returns a channel that fires after the given duration. After(time.Duration) <-chan time.Time // NewTimer makes a Timer based on this clock's time. Using Timers and // negative durations in the Clock or Timer API is undefined behavior and // may be changed. NewTimer(time.Duration) *Timer } type sysClock struct{} func (s sysClock) Now() time.Time { return time.Now() } func (s sysClock) Sleep(d time.Duration) { time.Sleep(d) } func (s sysClock) After(d time.Duration) <-chan time.Time { return time.After(d) } func (s sysClock) NewTimer(d time.Duration) *Timer { tt := time.NewTimer(d) return &Timer{C: tt.C, timer: tt} } // NewFake returns a FakeClock to be used in tests that need to // manipulate time. Its initial value is always the unix epoch in the // UTC timezone. The FakeClock returned is thread-safe. func NewFake() FakeClock { // We're explicit about this time construction to avoid early user // questions about why the time object doesn't have a Location by // default. return &fake{t: time.Unix(0, 0).UTC()} } // FakeClock is a Clock with additional controls. The return value of // Now return can be modified with Add. Use NewFake to get a // thread-safe FakeClock implementation. type FakeClock interface { Clock // Adjust the time that will be returned by Now. Add(d time.Duration) // Set the Clock's time to exactly the time given. Set(t time.Time) } // To prevent mistakes with the API, we hide this behind NewFake. It's // easy forget to create a pointer to a fake since time.Time (and // sync.Mutex) are also simple values. The code will appear to work // but the clock's time will never be adjusted. type fake struct { sync.RWMutex t time.Time sends sortedSends } func (f *fake) Now() time.Time { f.RLock() defer f.RUnlock() return f.t } func (f *fake) Sleep(d time.Duration) { if d < 0 { // time.Sleep just returns immediately. Do the same. return } f.Add(d) } func (f *fake) After(d time.Duration) <-chan time.Time { return f.NewTimer(d).C } func (f *fake) NewTimer(d time.Duration) *Timer { f.Lock() defer f.Unlock() ch := make(chan time.Time, 1) tt := f.t.Add(d) ft := &fakeTimer{c: ch, clk: f, active: true} t := &Timer{ C: ch, fakeTimer: ft, } s := f.addSend(tt, ft) ft.sends = []*send{s} return t } func (f *fake) Add(d time.Duration) { f.Lock() defer f.Unlock() f.t = f.t.Add(d) f.sendTimes() } func (f *fake) Set(t time.Time) { f.Lock() defer f.Unlock() f.t = t f.sendTimes() } // Only to be called while the fake's lock is held func (f *fake) sendTimes() { newSends := make(sortedSends, 0) for _, s := range f.sends { if !s.active || !s.ft.active { continue } if s.target.Equal(f.t) || s.target.Before(f.t) { s.ft.active = false s.active = false // The select is to drop second sends from resets without a user // receiving from ft.c. select { case s.ft.c <- s.target: default: } } if s.active { newSends = append(newSends, s) } } f.sends = newSends } // Only to be called while the fake's lock is held func (f *fake) addSend(target time.Time, ft *fakeTimer) *send { s := &send{target: target, ft: ft, active: true} f.sends = append(f.sends, s) // This will be a small enough slice to be fast. Can be replaced with a more // complicated container if someone is making many timers. sort.Sort(f.sends) return s } // send is a struct that represents a scheduled send of a time.Time to its // fakeTimer's channel. They are actually sent when the relevant fake's time // goes equal or past their target time, as long as the relevant fakeTimer has // not been Reset or Stop'ed. When a Timer is Reset, the old sends are // deactivated and will be removed from the clocks list on the next attempt to // send. type send struct { target time.Time active bool ft *fakeTimer } type sortedSends []*send func (s sortedSends) Len() int { return len(s) } func (s sortedSends) Less(i, j int) bool { return s[i].target.Before(s[j].target) } func (s sortedSends) Swap(i, j int) { s[i], s[j] = s[j], s[i] } clock-1.0/clock_test.go000066400000000000000000000200251270030734200151230ustar00rootroot00000000000000package clock import ( "fmt" "testing" "time" ) func TestFakeClockGoldenPath(t *testing.T) { clk := NewFake() second := NewFake() oldT := clk.Now() if !clk.Now().Equal(second.Now()) { t.Errorf("clocks must start out at the same time but didn't: %#v vs %#v", clk.Now(), second.Now()) } clk.Add(3 * time.Second) if clk.Now().Equal(second.Now()) { t.Errorf("clocks different must differ: %#v vs %#v", clk.Now(), second.Now()) } clk.Set(oldT) if !clk.Now().Equal(second.Now()) { t.Errorf("clk should have been been set backwards: %#v vs %#v", clk.Now(), second.Now()) } clk.Sleep(time.Second) if clk.Now().Equal(second.Now()) { t.Errorf("clk should have been set forwards (by sleeping): %#v vs %#v", clk.Now(), second.Now()) } } func TestNegativeSleep(t *testing.T) { clk := NewFake() clk.Add(1 * time.Hour) first := clk.Now() clk.Sleep(-10 * time.Second) if !clk.Now().Equal(first) { t.Errorf("clk should not move in time on a negative sleep") } } func TestFakeTimer(t *testing.T) { clk := NewFake() setTo := clk.Now().Add(3 * time.Hour) tests := []struct { f func(clk FakeClock) recvVal time.Time nowVal time.Time }{ { func(fc FakeClock) { fc.Add(2 * time.Hour) }, clk.Now().Add(1 * time.Hour), clk.Now().Add(2 * time.Hour), }, { func(fc FakeClock) { fc.Set(setTo) }, clk.Now().Add(1 * time.Hour), clk.Now().Add(3 * time.Hour), }, { func(fc FakeClock) { fc.Sleep(2 * time.Hour) }, clk.Now().Add(1 * time.Hour), clk.Now().Add(2 * time.Hour), }, } for i, tc := range tests { clk := NewFake() timer := clk.NewTimer(1 * time.Hour) go tc.f(clk) recvVal := waitFor(timer.C) if recvVal == nil { t.Errorf("didn't receive time notification") continue } if !recvVal.Equal(tc.recvVal) { t.Errorf("#%d, <-timer.C: want %s, got %s", i, tc.recvVal, recvVal) } if !clk.Now().Equal(tc.nowVal) { t.Errorf("#%d, clk.Now: want %s, got %s", i, tc.nowVal, clk.Now()) } } } func TestFakeTimerStop(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Second) if !tt.Stop() { t.Errorf("Stop: thought it was stopped or expired already") } if tt.Stop() { t.Errorf("Stop, again: thought it wasn't stopped or expired already") } } func TestFakeTimerReset(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Second) before := clk.Now() if !tt.Reset(1 * time.Second) { t.Errorf("Reset: was already expired and shouldn't be") } clk.Add(1 * time.Second) if tt.Reset(1 * time.Hour) { t.Errorf("should have already been expired") } clk.Add(1 * time.Hour) t1 := waitFor(tt.C) if t1 == nil { t.Fatal("timeout") } oneSec := before.Add(1 * time.Second) if *t1 != oneSec { t.Errorf("first: want %s, got %s", oneSec, t1) } if immediatelyRecv(tt.C) != nil { t.Fatal("second reset should never fire") } } func TestFakeTimerResetAgain(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Second) before := clk.Now() if !tt.Reset(1 * time.Second) { t.Errorf("Reset: was already expired and shouldn't be") } clk.Add(1 * time.Second) t1 := waitFor(tt.C) if t1 == nil { t.Fatal("timeout") } if tt.Reset(1 * time.Hour) { t.Errorf("should have already been expired") } clk.Add(1 * time.Hour) oneSec := before.Add(1 * time.Second) if *t1 != oneSec { t.Errorf("first: want %s, got %s", t1, oneSec) } t2 := waitFor(tt.C) if t2 == nil { t.Fatal("second reset should have already fired") } } func TestFakeTimerResetAgainWithSleep(t *testing.T) { clk := NewFake() tt := clk.NewTimer(4 * time.Second) if !tt.Reset(4 * time.Second) { t.Errorf("Reset: was already expired and shouldn't be") } clk.Sleep(5 * time.Second) t1 := waitFor(tt.C) if t1 == nil { t.Fatal("timeout") } if tt.Reset(10 * time.Second) { t.Errorf("should have already been expired") } clk.Sleep(12 * time.Second) t2 := waitFor(tt.C) if t2 == nil { t.Fatal("second reset should have already fired") } } func TestFakeTimerOrderOfTimers(t *testing.T) { clk := NewFake() t2 := clk.NewTimer(2 * time.Hour) t3 := clk.NewTimer(3 * time.Hour) t1 := clk.NewTimer(1 * time.Hour) before := clk.Now() clk.Add(3 * time.Hour) expected1 := before.Add(1 * time.Hour) expected2 := before.Add(2 * time.Hour) expected3 := before.Add(3 * time.Hour) actual1 := waitFor(t1.C) if actual1 == nil { t.Errorf("expected t1 to fire, but did not") } if !actual1.Equal(expected1) { t.Errorf("t1: want %s, got %s", expected1, actual1) } actual2 := waitFor(t2.C) if actual2 == nil { t.Fatalf("expected t2 to fire first, but did not") } if !actual2.Equal(expected2) { t.Errorf("t2: want %s, got %s", expected2, actual2) } actual3 := waitFor(t3.C) if actual3 == nil { t.Fatalf("expected t3 to fire first, but did not") } if !actual3.Equal(expected3) { t.Errorf("t3: want %s, got %s", expected3, actual3) } } func TestTimerOrderOfTimers(t *testing.T) { clk := NewFake() t2 := clk.NewTimer(2 * time.Hour) t3 := clk.NewTimer(3 * time.Hour) t1 := clk.NewTimer(1 * time.Hour) before := clk.Now() clk.Add(3 * time.Hour) expected1 := before.Add(1 * time.Hour) expected2 := before.Add(2 * time.Hour) expected3 := before.Add(3 * time.Hour) actual1 := waitFor(t1.C) if actual1 == nil { t.Errorf("expected t1 to fire, but did not") } if !actual1.Equal(expected1) { t.Errorf("t1: want %s, got %s", expected1, actual1) } actual2 := waitFor(t2.C) if actual2 == nil { t.Fatalf("expected t2 to fire first, but did not") } if !actual2.Equal(expected2) { t.Errorf("t2: want %s, got %s", expected2, actual2) } actual3 := waitFor(t3.C) if actual3 == nil { t.Fatalf("expected t3 to fire first, but did not") } if !actual3.Equal(expected3) { t.Errorf("t3: want %s, got %s", expected3, actual3) } } func TestFakeTimerExpiresAfterFiring(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Hour) go func() { clk.Add(1 * time.Hour) }() t1 := waitFor(tt.C) if t1 == nil { t.Fatal("timeout") } if tt.fakeTimer.active { t.Errorf("did not expire after firing") } if tt.Stop() { t.Errorf("Stop: was not already expired after firing") } } func TestFakeAfter(t *testing.T) { clk := NewFake() ch := clk.After(1 * time.Hour) go func() { clk.Add(1 * time.Hour) }() t1 := waitFor(ch) if t1 == nil { t.Fatal("timeout") } if !t1.Equal(clk.Now()) { t.Errorf("After: want %s, got %s", clk.Now(), t1) } } func TestFakeTimerStopStopsOldSends(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Second) tt.Stop() clk.Add(1 * time.Second) t1 := immediatelyRecv(tt.C) if t1 != nil { t.Errorf("expected no send, got %s", *t1) } } func TestFakeTimerResetStopsOldSends(t *testing.T) { clk := NewFake() tt := clk.NewTimer(1 * time.Second) tt.Reset(2 * time.Second) clk.Add(1 * time.Second) t1 := immediatelyRecv(tt.C) if t1 != nil { t.Errorf("expected no send, got %s", *t1) } clk.Add(1 * time.Second) t2 := waitFor(tt.C) if t2 == nil { t.Errorf("expected a send, got nothing") } } func TestRealClock(t *testing.T) { clk := Default() clk.Now() clk.Sleep(1 * time.Nanosecond) clk.After(1 * time.Nanosecond) tt := clk.NewTimer(1 * time.Nanosecond) tt.Stop() tt.Reset(1 * time.Nanosecond) } func waitFor(c <-chan time.Time) *time.Time { select { case ti := <-c: return &ti case <-time.After(2 * time.Second): return nil } } func immediatelyRecv(c <-chan time.Time) *time.Time { select { case ti := <-c: return &ti default: return nil } } func ExampleClock() { c := Default() now := c.Now() fmt.Println(now.UTC().Zone()) // Output: // UTC 0 } func ExampleFakeClock() { c := Default() fc := NewFake() fc.Add(20 * time.Hour) fc.Add(-5 * time.Minute) // negatives work, as well if fc.Now().Equal(fc.Now()) { fmt.Println("FakeClocks' Times always equal themselves.") } if !c.Now().Equal(fc.Now()) { fmt.Println("Clock and FakeClock can be set to different times.") } if !fc.Now().Equal(NewFake().Now()) { fmt.Println("FakeClocks work independently, too.") } // Output: // FakeClocks' Times always equal themselves. // Clock and FakeClock can be set to different times. // FakeClocks work independently, too. } clock-1.0/timer.go000066400000000000000000000025461270030734200141210ustar00rootroot00000000000000package clock import "time" type Timer struct { C <-chan time.Time timer *time.Timer fakeTimer *fakeTimer } func (t *Timer) Reset(d time.Duration) bool { if t.timer != nil { return t.timer.Reset(d) } return t.fakeTimer.Reset(d) } func (t *Timer) Stop() bool { if t.timer != nil { return t.timer.Stop() } return t.fakeTimer.Stop() } type fakeTimer struct { // c is the same chan as C in the Timer that contains this fakeTimer c chan<- time.Time // clk is kept so we can maintain just one lock and to add and attempt to // send the times made by this timer during Resets and Stops clk *fake // active is true until the fakeTimer's send is attempted or it has been // stopped active bool // sends is where we store all the sends made by this timer so we can // deactivate the old ones when Reset or Stop is called. sends []*send } func (ft *fakeTimer) Reset(d time.Duration) bool { ft.clk.Lock() defer ft.clk.Unlock() target := ft.clk.t.Add(d) active := ft.active ft.active = true for _, s := range ft.sends { s.active = false } s := ft.clk.addSend(target, ft) ft.sends = []*send{s} ft.clk.sendTimes() return active } func (ft *fakeTimer) Stop() bool { ft.clk.Lock() defer ft.clk.Unlock() active := ft.active ft.active = false for _, s := range ft.sends { s.active = false } ft.sends = nil ft.clk.sendTimes() return active }