go.temporal.io/server@v1.23.0/common/clock/event_time_source_test.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package clock_test 26 27 import ( 28 "fmt" 29 "testing" 30 "time" 31 32 "github.com/stretchr/testify/assert" 33 "go.temporal.io/server/common/clock" 34 ) 35 36 // event is a helper to verify how many times a callback was triggered. Because callbacks are triggered synchronously 37 // with calls to EventTimeSource.Advance, we don't need any further synchronization. 38 type event struct { 39 t *testing.T 40 count int 41 } 42 43 // Fire is the callback to be triggered. 44 func (e *event) Fire() { 45 e.count++ 46 } 47 48 // AssertFiredOnce asserts that the callback was triggered exactly once. 49 func (e *event) AssertFiredOnce(msg string) { 50 e.t.Helper() 51 assert.Equal(e.t, 1, e.count, msg) 52 } 53 54 // AssertNotFired asserts that the callback was not triggered. 55 func (e *event) AssertNotFired(msg string) { 56 e.t.Helper() 57 assert.Zero(e.t, e.count, msg) 58 } 59 60 func ExampleEventTimeSource() { 61 // Create a new fake timeSource. 62 source := clock.NewEventTimeSource() 63 64 // Create a timer which fires after 1 second. 65 source.AfterFunc(time.Second, func() { 66 fmt.Println("timer fired") 67 }) 68 69 // Advance the time source by 1 second. 70 fmt.Println("advancing time source by 1 second") 71 source.Advance(time.Second) 72 fmt.Println("time source advanced") 73 74 // Output: 75 // advancing time source by 1 second 76 // timer fired 77 // time source advanced 78 } 79 80 func TestEventTimeSource_AfterFunc(t *testing.T) { 81 t.Parallel() 82 83 // Create a new fake time source and an event to fire. 84 source := clock.NewEventTimeSource() 85 ev := event{t: t} 86 87 // Create a timer which fires after 2ns. 88 source.AfterFunc(2, ev.Fire) 89 90 // Advance the time source by 1ns. 91 source.Advance(1) 92 ev.AssertNotFired( 93 "Advancing the time source should not fire the timer if its deadline still has not been reached", 94 ) 95 96 // Advance the time source by 1ns more. 97 source.Advance(1) 98 ev.AssertFiredOnce("Advancing a time source past a timer's deadline should fire the timer") 99 } 100 101 func TestEventTimeSource_AfterFunc_Reset(t *testing.T) { 102 t.Parallel() 103 104 // Create a new fake time source and two events to fire. 105 source := clock.NewEventTimeSource() 106 ev1 := event{t: t} 107 ev2 := event{t: t} 108 109 // Create a timer for each event which fires after 2ns. 110 timer := source.AfterFunc(2, ev1.Fire) 111 source.AfterFunc(2, ev2.Fire) 112 113 // Advance the time source by 1ns and verify that neither timer has fired. 114 source.Advance(1) 115 ev1.AssertNotFired("Timer should not fire before deadline") 116 ev2.AssertNotFired("Timer should not fire before deadline") 117 118 // Reset the first timer to fire after an additional 2ns. 119 assert.True(t, timer.Reset(2), "`Reset` should return true if the timer was not already stopped") 120 121 // Advance the time source by 1ns and verify that the first timer has not fired but the second timer has. 122 source.Advance(1) 123 ev1.AssertNotFired("Timer which was reset should not fire after original deadline but before new deadline") 124 ev2.AssertFiredOnce("Timer which was not reset should fire after deadline") 125 126 // Advance the time source by 1ns more and verify that the reset timer has fired. 127 source.Advance(1) 128 ev1.AssertFiredOnce("The reset timer should fire after its new deadline") 129 130 // Reset the first timer and advance the time source past the new deadline to verify that the timer does not fire 131 // again. 132 assert.False(t, timer.Reset(1), "`Reset` should return false if the timer was already stopped") 133 source.Advance(1) 134 ev1.AssertFiredOnce("The timer should never fire twice, even if it was reset") 135 } 136 137 func TestEventTimeSource_AfterFunc_Stop(t *testing.T) { 138 t.Parallel() 139 140 // Create a new fake time source and two events to fire. 141 source := clock.NewEventTimeSource() 142 ev1 := event{t: t} 143 ev2 := event{t: t} 144 145 // Create a timer for each event which fires after 1ns. 146 timer := source.AfterFunc(1, ev1.Fire) 147 source.AfterFunc(1, ev2.Fire) 148 149 // Stop the first timer. 150 assert.True(t, timer.Stop(), "`Stop` should return true if the timer was not already stopped") 151 152 // Advance the time source by 1ns and verify that the first timer has not fired and the second timer has. 153 source.Advance(1) 154 ev1.AssertNotFired("A timer should not fire if it was already stopped") 155 ev2.AssertFiredOnce("A timer which was not stopped should fire after its deadline") 156 157 // Verify that subsequent calls to `Stop` return false. 158 assert.False(t, timer.Stop(), "`Stop` return false if the timer was already stopped") 159 } 160 161 func TestEventTimeSource_AfterFunc_NegativeDelay(t *testing.T) { 162 t.Parallel() 163 164 // Create a new fake time source and one event to fire. 165 source := clock.NewEventTimeSource() 166 ev1 := event{t: t} 167 168 // Create a timer which fires after -1ns. This should fire immediately. 169 timer := source.AfterFunc(-1, ev1.Fire) 170 171 // Verify that the timer has fired. 172 ev1.AssertFiredOnce("A timer with a negative delay should fire immediately") 173 174 // Verify that the timer is stopped. 175 assert.False(t, timer.Stop(), "`Stop` should return false if the timer was already stopped") 176 } 177 178 func TestEventTimeSource_Update(t *testing.T) { 179 t.Parallel() 180 181 // Create a new fake time source and two events to fire. 182 source := clock.NewEventTimeSource() 183 ev1 := event{t: t} 184 ev2 := event{t: t} 185 186 // Create a timer for each event which fires after 1ns. 187 source.AfterFunc(1, ev1.Fire) 188 source.AfterFunc(1, ev2.Fire) 189 190 // Verify that the time source starts at Unix epoch. 191 assert.Equal( 192 t, time.Unix(0, 0), source.Now(), "The fake time source should start at the unix epoch", 193 ) 194 195 // Update to move the time source forward by 1ns. 196 source.Update(time.Unix(0, 1)) 197 assert.Equal(t, time.Unix(0, 1), source.Now()) 198 ev1.AssertFiredOnce("Timer should fire after deadline") 199 ev2.AssertFiredOnce("Timer should fire after deadline") 200 }