From fe9f6089afe4ce0d09433cb79130659d13a0a2ed Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 10 Sep 2021 10:42:15 -0700 Subject: [PATCH] Move controlledClock to ztest.MockClock We need to be able to use the controlled clock for some other tests so move it from clock_test to the ztest package and rename it to MockClock. To keep the interface for the MockClock clear, don't embed the benbjohnson/clock and instead, use it as an attribute. --- internal/ztest/clock.go | 50 +++++++++++++++++++++++ internal/ztest/clock_test.go | 57 +++++++++++++++++++++++++++ zapcore/buffered_write_syncer_test.go | 2 +- zapcore/clock.go | 4 +- zapcore/clock_test.go | 44 ++------------------- 5 files changed, 112 insertions(+), 45 deletions(-) create mode 100644 internal/ztest/clock.go create mode 100644 internal/ztest/clock_test.go diff --git a/internal/ztest/clock.go b/internal/ztest/clock.go new file mode 100644 index 000000000..fe8026d94 --- /dev/null +++ b/internal/ztest/clock.go @@ -0,0 +1,50 @@ +// 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 ztest + +import ( + "time" + + "github.com/benbjohnson/clock" +) + +// MockClock provides control over the time. +type MockClock struct{ m *clock.Mock } + +// NewMockClock builds a new mock clock that provides control of time. +func NewMockClock() *MockClock { + return &MockClock{clock.NewMock()} +} + +// Now reports the current time. +func (c *MockClock) Now() time.Time { + return c.m.Now() +} + +// NewTicker returns a time.Ticker that ticks at the specified frequency. +func (c *MockClock) NewTicker(d time.Duration) *time.Ticker { + return &time.Ticker{C: c.m.Ticker(d).C} +} + +// Add progresses time by the given duration. +func (c *MockClock) Add(d time.Duration) { + c.m.Add(d) +} diff --git a/internal/ztest/clock_test.go b/internal/ztest/clock_test.go new file mode 100644 index 000000000..377daf979 --- /dev/null +++ b/internal/ztest/clock_test.go @@ -0,0 +1,57 @@ +// 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 ztest + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.uber.org/atomic" +) + +func TestMockClock_NewTicker(t *testing.T) { + var n atomic.Int32 + clock := NewMockClock() + + done := make(chan struct{}) + defer func() { <-done }() // wait for end + + quit := make(chan struct{}) + // Create a channel to increment every microsecond. + go func(ticker *time.Ticker) { + defer close(done) + for { + select { + case <-quit: + ticker.Stop() + return + case <-ticker.C: + n.Inc() + } + } + }(clock.NewTicker(time.Microsecond)) + + // Move clock forward. + clock.Add(2 * time.Microsecond) + assert.Equal(t, int32(2), n.Load()) + close(quit) +} diff --git a/zapcore/buffered_write_syncer_test.go b/zapcore/buffered_write_syncer_test.go index 72d4d6f88..8a36ad69d 100644 --- a/zapcore/buffered_write_syncer_test.go +++ b/zapcore/buffered_write_syncer_test.go @@ -107,7 +107,7 @@ func TestBufferWriter(t *testing.T) { t.Run("flush timer", func(t *testing.T) { buf := &bytes.Buffer{} - clock := newControlledClock() + clock := ztest.NewMockClock() ws := &BufferedWriteSyncer{ WS: AddSync(buf), Size: 6, diff --git a/zapcore/clock.go b/zapcore/clock.go index d2ea95b39..422fd82a6 100644 --- a/zapcore/clock.go +++ b/zapcore/clock.go @@ -20,9 +20,7 @@ package zapcore -import ( - "time" -) +import "time" // DefaultClock is the default clock used by Zap in operations that require // time. This clock uses the system clock for all operations. diff --git a/zapcore/clock_test.go b/zapcore/clock_test.go index aab682fec..0dff34991 100644 --- a/zapcore/clock_test.go +++ b/zapcore/clock_test.go @@ -24,49 +24,11 @@ import ( "testing" "time" - "github.com/benbjohnson/clock" - "github.com/stretchr/testify/assert" - "go.uber.org/atomic" + "go.uber.org/zap/internal/ztest" ) -// controlledClock provides control over the time via a mock clock. -type controlledClock struct{ *clock.Mock } - -func newControlledClock() *controlledClock { - return &controlledClock{clock.NewMock()} -} - -func (c *controlledClock) NewTicker(d time.Duration) *time.Ticker { - return &time.Ticker{C: c.Ticker(d).C} -} - -func TestControlledClock_NewTicker(t *testing.T) { - var n atomic.Int32 - ctrlMock := newControlledClock() - - done := make(chan struct{}) - defer func() { <-done }() // wait for end - - quit := make(chan struct{}) - // Create a channel to increment every microsecond. - go func(ticker *time.Ticker) { - defer close(done) - for { - select { - case <-quit: - ticker.Stop() - return - case <-ticker.C: - n.Inc() - } - } - }(ctrlMock.NewTicker(time.Microsecond)) - - // Move clock forward. - ctrlMock.Add(2 * time.Microsecond) - assert.Equal(t, int32(2), n.Load()) - close(quit) -} +// Verify that the mock clock satisfies the Clock interface. +var _ Clock = (*ztest.MockClock)(nil) func TestSystemClock_NewTicker(t *testing.T) { want := 3