github.com/kubernetes/utils@v0.0.0-20190308190857-21c4ce38f2a7/clock/testing/fake_clock_test.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package testing
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  func TestFakeClock(t *testing.T) {
    25  	startTime := time.Now()
    26  	tc := NewFakeClock(startTime)
    27  	tc.Step(time.Second)
    28  	now := tc.Now()
    29  	if now.Sub(startTime) != time.Second {
    30  		t.Errorf("input: %s now=%s gap=%s expected=%s", startTime, now, now.Sub(startTime), time.Second)
    31  	}
    32  
    33  	tt := tc.Now()
    34  	tc.SetTime(tt.Add(time.Hour))
    35  	if tc.Now().Sub(tt) != time.Hour {
    36  		t.Errorf("input: %s now=%s gap=%s expected=%s", tt, tc.Now(), tc.Now().Sub(tt), time.Hour)
    37  	}
    38  }
    39  
    40  func TestFakeClockSleep(t *testing.T) {
    41  	startTime := time.Now()
    42  	tc := NewFakeClock(startTime)
    43  	tc.Sleep(time.Duration(1) * time.Hour)
    44  	now := tc.Now()
    45  	if now.Sub(startTime) != time.Hour {
    46  		t.Errorf("Fake sleep failed, expected time to advance by one hour, instead, its %v", now.Sub(startTime))
    47  	}
    48  }
    49  
    50  func TestFakeAfter(t *testing.T) {
    51  	tc := NewFakeClock(time.Now())
    52  	if tc.HasWaiters() {
    53  		t.Errorf("unexpected waiter?")
    54  	}
    55  	oneSec := tc.After(time.Second)
    56  	if !tc.HasWaiters() {
    57  		t.Errorf("unexpected lack of waiter?")
    58  	}
    59  
    60  	oneOhOneSec := tc.After(time.Second + time.Millisecond)
    61  	twoSec := tc.After(2 * time.Second)
    62  	select {
    63  	case <-oneSec:
    64  		t.Errorf("unexpected channel read")
    65  	case <-oneOhOneSec:
    66  		t.Errorf("unexpected channel read")
    67  	case <-twoSec:
    68  		t.Errorf("unexpected channel read")
    69  	default:
    70  	}
    71  
    72  	tc.Step(999 * time.Millisecond)
    73  	select {
    74  	case <-oneSec:
    75  		t.Errorf("unexpected channel read")
    76  	case <-oneOhOneSec:
    77  		t.Errorf("unexpected channel read")
    78  	case <-twoSec:
    79  		t.Errorf("unexpected channel read")
    80  	default:
    81  	}
    82  
    83  	tc.Step(time.Millisecond)
    84  	select {
    85  	case <-oneSec:
    86  		// Expected!
    87  	case <-oneOhOneSec:
    88  		t.Errorf("unexpected channel read")
    89  	case <-twoSec:
    90  		t.Errorf("unexpected channel read")
    91  	default:
    92  		t.Errorf("unexpected non-channel read")
    93  	}
    94  	tc.Step(time.Millisecond)
    95  	select {
    96  	case <-oneSec:
    97  		// should not double-trigger!
    98  		t.Errorf("unexpected channel read")
    99  	case <-oneOhOneSec:
   100  		// Expected!
   101  	case <-twoSec:
   102  		t.Errorf("unexpected channel read")
   103  	default:
   104  		t.Errorf("unexpected non-channel read")
   105  	}
   106  }
   107  
   108  func TestFakeTick(t *testing.T) {
   109  	tc := NewFakeClock(time.Now())
   110  	if tc.HasWaiters() {
   111  		t.Errorf("unexpected waiter?")
   112  	}
   113  	oneSec := tc.Tick(time.Second)
   114  	if !tc.HasWaiters() {
   115  		t.Errorf("unexpected lack of waiter?")
   116  	}
   117  
   118  	oneOhOneSec := tc.Tick(time.Second + time.Millisecond)
   119  	twoSec := tc.Tick(2 * time.Second)
   120  	select {
   121  	case <-oneSec:
   122  		t.Errorf("unexpected channel read")
   123  	case <-oneOhOneSec:
   124  		t.Errorf("unexpected channel read")
   125  	case <-twoSec:
   126  		t.Errorf("unexpected channel read")
   127  	default:
   128  	}
   129  
   130  	tc.Step(999 * time.Millisecond) // t=.999
   131  	select {
   132  	case <-oneSec:
   133  		t.Errorf("unexpected channel read")
   134  	case <-oneOhOneSec:
   135  		t.Errorf("unexpected channel read")
   136  	case <-twoSec:
   137  		t.Errorf("unexpected channel read")
   138  	default:
   139  	}
   140  
   141  	tc.Step(time.Millisecond) // t=1.000
   142  	select {
   143  	case <-oneSec:
   144  		// Expected!
   145  	case <-oneOhOneSec:
   146  		t.Errorf("unexpected channel read")
   147  	case <-twoSec:
   148  		t.Errorf("unexpected channel read")
   149  	default:
   150  		t.Errorf("unexpected non-channel read")
   151  	}
   152  	tc.Step(time.Millisecond) // t=1.001
   153  	select {
   154  	case <-oneSec:
   155  		// should not double-trigger!
   156  		t.Errorf("unexpected channel read")
   157  	case <-oneOhOneSec:
   158  		// Expected!
   159  	case <-twoSec:
   160  		t.Errorf("unexpected channel read")
   161  	default:
   162  		t.Errorf("unexpected non-channel read")
   163  	}
   164  
   165  	tc.Step(time.Second) // t=2.001
   166  	tc.Step(time.Second) // t=3.001
   167  	tc.Step(time.Second) // t=4.001
   168  	tc.Step(time.Second) // t=5.001
   169  
   170  	// The one second ticker should not accumulate ticks
   171  	accumulatedTicks := 0
   172  	drained := false
   173  	for !drained {
   174  		select {
   175  		case <-oneSec:
   176  			accumulatedTicks++
   177  		default:
   178  			drained = true
   179  		}
   180  	}
   181  	if accumulatedTicks != 1 {
   182  		t.Errorf("unexpected number of accumulated ticks: %d", accumulatedTicks)
   183  	}
   184  }
   185  
   186  func TestFakeStop(t *testing.T) {
   187  	tc := NewFakeClock(time.Now())
   188  	timer := tc.NewTimer(time.Second)
   189  	if !tc.HasWaiters() {
   190  		t.Errorf("expected a waiter to be present, but it is not")
   191  	}
   192  	timer.Stop()
   193  	if tc.HasWaiters() {
   194  		t.Errorf("expected existing waiter to be cleaned up, but it is still present")
   195  	}
   196  }
   197  
   198  // This tests the pattern documented in the go docs here: https://golang.org/pkg/time/#Timer.Stop
   199  // This pattern is required to safely reset a timer, so should be common.
   200  // This also tests resetting the timer
   201  func TestFakeStopDrain(t *testing.T) {
   202  	start := time.Time{}
   203  	tc := NewFakeClock(start)
   204  	timer := tc.NewTimer(time.Second)
   205  	tc.Step(1 * time.Second)
   206  	// Effectively `if !timer.Stop { <-t.C }` but with more asserts
   207  	if timer.Stop() {
   208  		t.Errorf("stop should report the timer had triggered")
   209  	}
   210  	if readTime := assertReadTime(t, timer.C()); !readTime.Equal(start.Add(1 * time.Second)) {
   211  		t.Errorf("timer should have ticked after 1 second, got %v", readTime)
   212  	}
   213  
   214  	timer.Reset(time.Second)
   215  	if !tc.HasWaiters() {
   216  		t.Errorf("expected a waiter to be present, but it is not")
   217  	}
   218  	select {
   219  	case <-timer.C():
   220  		t.Fatal("got time early on clock; haven't stepped yet")
   221  	default:
   222  	}
   223  	tc.Step(1 * time.Second)
   224  	if readTime := assertReadTime(t, timer.C()); !readTime.Equal(start.Add(2 * time.Second)) {
   225  		t.Errorf("timer should have ticked again after reset + 1 more second, got %v", readTime)
   226  	}
   227  }
   228  
   229  func TestTimerNegative(t *testing.T) {
   230  	tc := NewFakeClock(time.Now())
   231  	timer := tc.NewTimer(-1 * time.Second)
   232  	if !tc.HasWaiters() {
   233  		t.Errorf("expected a waiter to be present, but it is not")
   234  	}
   235  	// force waiters to be called
   236  	tc.Step(0)
   237  	tick := assertReadTime(t, timer.C())
   238  	if tick != tc.Now() {
   239  		t.Errorf("expected -1s to turn into now: %v != %v", tick, tc.Now())
   240  	}
   241  }
   242  
   243  func TestTickNegative(t *testing.T) {
   244  	// The stdlib 'Tick' returns nil for negative and zero values, so our fake
   245  	// should too.
   246  	tc := NewFakeClock(time.Now())
   247  	if tick := tc.Tick(-1 * time.Second); tick != nil {
   248  		t.Errorf("expected negative tick to be nil: %v", tick)
   249  	}
   250  	if tick := tc.Tick(0); tick != nil {
   251  		t.Errorf("expected negative tick to be nil: %v", tick)
   252  	}
   253  }
   254  
   255  // assertReadTime asserts that the channel can be read and returns the time it
   256  // reads from the channel.
   257  func assertReadTime(t testing.TB, c <-chan time.Time) time.Time {
   258  	type helper interface {
   259  		Helper()
   260  	}
   261  	if h, ok := t.(helper); ok {
   262  		h.Helper()
   263  	}
   264  	select {
   265  	case ti, ok := <-c:
   266  		if !ok {
   267  			t.Fatalf("expected to read time from channel, but it was closed")
   268  		}
   269  		return ti
   270  	default:
   271  		t.Fatalf("expected to read time from channel, but couldn't")
   272  	}
   273  	panic("unreachable")
   274  }