Browse Source

tstest: prepare for Clock API changes

This change introduces tstime.NewClock and tstime.ClockOpts as a new way
to construct tstime.Clock. This is a subset of #8464 as a stepping stone
so that we can update our internal code to use the new API before making
the second round of changes.

Updates #8463

Change-Id: Ib26edb60e5355802aeca83ed60e4fdf806c90e27
Signed-off-by: Adrian Dewhurst <[email protected]>
Adrian Dewhurst 2 years ago
parent
commit
cd4c71c122
4 changed files with 95 additions and 21 deletions
  1. 2 2
      net/dns/recursive/recursive_test.go
  2. 2 2
      net/dnscache/messagecache_test.go
  3. 74 0
      tstest/clock.go
  4. 17 17
      tsweb/tsweb_test.go

+ 2 - 2
net/dns/recursive/recursive_test.go

@@ -36,9 +36,9 @@ func init() {
 }
 
 func newResolver(tb testing.TB) *Resolver {
-	clock := &tstest.Clock{
+	clock := tstest.NewClock(tstest.ClockOpts{
 		Step: 50 * time.Millisecond,
-	}
+	})
 	return &Resolver{
 		Logf:    tb.Logf,
 		timeNow: clock.Now,

+ 2 - 2
net/dnscache/messagecache_test.go

@@ -18,9 +18,9 @@ import (
 )
 
 func TestMessageCache(t *testing.T) {
-	clock := &tstest.Clock{
+	clock := tstest.NewClock(tstest.ClockOpts{
 		Start: time.Date(1987, 11, 1, 0, 0, 0, 0, time.UTC),
-	}
+	})
 	mc := &MessageCache{Clock: clock.Now}
 	mc.SetMaxCacheSize(2)
 	clock.Advance(time.Second)

+ 74 - 0
tstest/clock.go

@@ -8,6 +8,56 @@ import (
 	"time"
 )
 
+// ClockOpts is used to configure the initial settings for a Clock. Once the
+// settings are configured as desired, call NewClock to get the resulting Clock.
+type ClockOpts struct {
+	// Start is the starting time for the Clock. When FollowRealTime is false,
+	// Start is also the value that will be returned by the first call
+	// to Clock.Now.
+	Start time.Time
+	// Step is the amount of time the Clock will advance whenever Clock.Now is
+	// called. If set to zero, the Clock will only advance when Clock.Advance is
+	// called and/or if FollowRealTime is true.
+	//
+	// FollowRealTime and Step cannot be enabled at the same time.
+	Step time.Duration
+
+	// TimerChannelSize configures the maximum buffered ticks that are
+	// permitted in the channel of any Timer and Ticker created by this Clock.
+	// The special value 0 means to use the default of 1. The buffer may need to
+	// be increased if time is advanced by more than a single tick and proper
+	// functioning of the test requires that the ticks are not lost.
+	TimerChannelSize int
+
+	// FollowRealTime makes the simulated time increment along with real time.
+	// It is a compromise between determinism and the difficulty of explicitly
+	// managing the simulated time via Step or Clock.Advance. When
+	// FollowRealTime is set, calls to Now() and PeekNow() will add the
+	// elapsed real-world time to the simulated time.
+	//
+	// FollowRealTime and Step cannot be enabled at the same time.
+	FollowRealTime bool
+}
+
+// NewClock creates a Clock with the specified settings. To create a
+// Clock with only the default settings, new(Clock) is equivalent, except that
+// the start time will not be computed until one of the receivers is called.
+func NewClock(co ClockOpts) *Clock {
+	if co.TimerChannelSize != 0 || co.FollowRealTime {
+		panic("TimerChannelSize and FollowRealTime are not implemented yet")
+	}
+
+	clock := &Clock{
+		Start: co.Start,
+		Step:  co.Step,
+	}
+	clock.Lock()
+	defer clock.Unlock()
+	clock.initLocked()
+
+	return clock
+}
+
 // Clock is a testing clock that advances every time its Now method is
 // called, beginning at Start.
 //
@@ -58,3 +108,27 @@ func (c *Clock) Reset() {
 	defer c.Unlock()
 	c.Present = c.Start
 }
+
+// GetStart returns the initial simulated time when this Clock was created.
+func (c *Clock) GetStart() time.Time {
+	c.Lock()
+	defer c.Unlock()
+	c.initLocked()
+	return c.Start
+}
+
+// GetStep returns the amount that simulated time advances on every call to Now.
+func (c *Clock) GetStep() time.Duration {
+	c.Lock()
+	defer c.Unlock()
+	c.initLocked()
+	return c.Step
+}
+
+// SetStep updates the amount that simulated time advances on every call to Now.
+func (c *Clock) SetStep(d time.Duration) {
+	c.Lock()
+	defer c.Unlock()
+	c.initLocked()
+	c.Step = d
+}

+ 17 - 17
tsweb/tsweb_test.go

@@ -65,10 +65,7 @@ func TestStdHandler(t *testing.T) {
 		testErr = errors.New("test error")
 		bgCtx   = context.Background()
 		// canceledCtx, cancel = context.WithCancel(bgCtx)
-		clock = tstest.Clock{
-			Start: time.Now(),
-			Step:  time.Second,
-		}
+		startTime = time.Unix(1687870000, 1234)
 	)
 	// cancel()
 
@@ -86,7 +83,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/"),
 			wantCode: 200,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				TLS:        false,
@@ -103,7 +100,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 404,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -119,7 +116,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 404,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -136,7 +133,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 404,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -153,7 +150,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 500,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -170,7 +167,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 500,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -187,7 +184,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 500,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -204,7 +201,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 200,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -221,7 +218,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 200,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -238,7 +235,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 200,
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				Host:       "example.com",
@@ -260,7 +257,7 @@ func TestStdHandler(t *testing.T) {
 			r:        req(bgCtx, "http://example.com/foo"),
 			wantCode: 200,
 			wantLog: AccessLogRecord{
-				When:    clock.Start,
+				When:    startTime,
 				Seconds: 1.0,
 
 				Proto:      "HTTP/1.1",
@@ -279,7 +276,7 @@ func TestStdHandler(t *testing.T) {
 				http.Error(w, e.Msg, 200)
 			},
 			wantLog: AccessLogRecord{
-				When:       clock.Start,
+				When:       startTime,
 				Seconds:    1.0,
 				Proto:      "HTTP/1.1",
 				TLS:        false,
@@ -302,7 +299,10 @@ func TestStdHandler(t *testing.T) {
 				t.Logf(fmt, args...)
 			}
 
-			clock.Reset()
+			clock := tstest.NewClock(tstest.ClockOpts{
+				Start: startTime,
+				Step:  time.Second,
+			})
 
 			rec := noopHijacker{httptest.NewRecorder(), false}
 			h := StdHandler(test.rh, HandlerOptions{Logf: logf, Now: clock.Now, OnError: test.errHandler})