mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
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 <adrian@tailscale.com>
This commit is contained in:
parent
fd8c8a3700
commit
cd4c71c122
@ -36,9 +36,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newResolver(tb testing.TB) *Resolver {
|
func newResolver(tb testing.TB) *Resolver {
|
||||||
clock := &tstest.Clock{
|
clock := tstest.NewClock(tstest.ClockOpts{
|
||||||
Step: 50 * time.Millisecond,
|
Step: 50 * time.Millisecond,
|
||||||
}
|
})
|
||||||
return &Resolver{
|
return &Resolver{
|
||||||
Logf: tb.Logf,
|
Logf: tb.Logf,
|
||||||
timeNow: clock.Now,
|
timeNow: clock.Now,
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMessageCache(t *testing.T) {
|
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),
|
Start: time.Date(1987, 11, 1, 0, 0, 0, 0, time.UTC),
|
||||||
}
|
})
|
||||||
mc := &MessageCache{Clock: clock.Now}
|
mc := &MessageCache{Clock: clock.Now}
|
||||||
mc.SetMaxCacheSize(2)
|
mc.SetMaxCacheSize(2)
|
||||||
clock.Advance(time.Second)
|
clock.Advance(time.Second)
|
||||||
|
@ -8,6 +8,56 @@
|
|||||||
"time"
|
"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
|
// Clock is a testing clock that advances every time its Now method is
|
||||||
// called, beginning at Start.
|
// called, beginning at Start.
|
||||||
//
|
//
|
||||||
@ -58,3 +108,27 @@ func (c *Clock) Reset() {
|
|||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
c.Present = c.Start
|
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
|
||||||
|
}
|
||||||
|
@ -65,10 +65,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
testErr = errors.New("test error")
|
testErr = errors.New("test error")
|
||||||
bgCtx = context.Background()
|
bgCtx = context.Background()
|
||||||
// canceledCtx, cancel = context.WithCancel(bgCtx)
|
// canceledCtx, cancel = context.WithCancel(bgCtx)
|
||||||
clock = tstest.Clock{
|
startTime = time.Unix(1687870000, 1234)
|
||||||
Start: time.Now(),
|
|
||||||
Step: time.Second,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
// cancel()
|
// cancel()
|
||||||
|
|
||||||
@ -86,7 +83,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/"),
|
r: req(bgCtx, "http://example.com/"),
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
TLS: false,
|
TLS: false,
|
||||||
@ -103,7 +100,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 404,
|
wantCode: 404,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -119,7 +116,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 404,
|
wantCode: 404,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -136,7 +133,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 404,
|
wantCode: 404,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -153,7 +150,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 500,
|
wantCode: 500,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -170,7 +167,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 500,
|
wantCode: 500,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -187,7 +184,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 500,
|
wantCode: 500,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -204,7 +201,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -221,7 +218,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -238,7 +235,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Host: "example.com",
|
Host: "example.com",
|
||||||
@ -260,7 +257,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
r: req(bgCtx, "http://example.com/foo"),
|
r: req(bgCtx, "http://example.com/foo"),
|
||||||
wantCode: 200,
|
wantCode: 200,
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
|
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
@ -279,7 +276,7 @@ func TestStdHandler(t *testing.T) {
|
|||||||
http.Error(w, e.Msg, 200)
|
http.Error(w, e.Msg, 200)
|
||||||
},
|
},
|
||||||
wantLog: AccessLogRecord{
|
wantLog: AccessLogRecord{
|
||||||
When: clock.Start,
|
When: startTime,
|
||||||
Seconds: 1.0,
|
Seconds: 1.0,
|
||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
TLS: false,
|
TLS: false,
|
||||||
@ -302,7 +299,10 @@ func TestStdHandler(t *testing.T) {
|
|||||||
t.Logf(fmt, args...)
|
t.Logf(fmt, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
clock.Reset()
|
clock := tstest.NewClock(tstest.ClockOpts{
|
||||||
|
Start: startTime,
|
||||||
|
Step: time.Second,
|
||||||
|
})
|
||||||
|
|
||||||
rec := noopHijacker{httptest.NewRecorder(), false}
|
rec := noopHijacker{httptest.NewRecorder(), false}
|
||||||
h := StdHandler(test.rh, HandlerOptions{Logf: logf, Now: clock.Now, OnError: test.errHandler})
|
h := StdHandler(test.rh, HandlerOptions{Logf: logf, Now: clock.Now, OnError: test.errHandler})
|
||||||
|
Loading…
Reference in New Issue
Block a user