go.temporal.io/server@v1.23.0/common/timer/local_gate_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 timer 26 27 import ( 28 "testing" 29 "time" 30 31 "github.com/stretchr/testify/require" 32 "github.com/stretchr/testify/suite" 33 34 "go.temporal.io/server/common/clock" 35 ) 36 37 type ( 38 localGateSuite struct { 39 suite.Suite 40 *require.Assertions 41 42 localTimerGate LocalGate 43 } 44 ) 45 46 func BenchmarkLocalTimer(b *testing.B) { 47 lg := NewLocalGate(clock.NewRealTimeSource()) 48 49 for i := 0; i < b.N; i++ { 50 lg.Update(time.Now().UTC()) 51 } 52 } 53 54 func TestLocalTimerGateSuite(t *testing.T) { 55 s := new(localGateSuite) 56 suite.Run(t, s) 57 } 58 59 func (s *localGateSuite) SetupSuite() { 60 61 } 62 63 func (s *localGateSuite) TearDownSuite() { 64 65 } 66 67 func (s *localGateSuite) SetupTest() { 68 s.Assertions = require.New(s.T()) 69 70 s.localTimerGate = NewLocalGate(clock.NewRealTimeSource()) 71 } 72 73 func (s *localGateSuite) TearDownTest() { 74 s.localTimerGate.Close() 75 } 76 77 func (s *localGateSuite) TestTimerFire() { 78 now := time.Now().UTC() 79 newTimer := now.Add(1 * time.Second) 80 deadline := now.Add(2 * time.Second) 81 s.localTimerGate.Update(newTimer) 82 83 select { 84 case <-s.localTimerGate.FireCh(): 85 case <-time.NewTimer(deadline.Sub(now)).C: 86 s.Fail("timer should fire before test deadline") 87 } 88 } 89 90 func (s *localGateSuite) TestTimerFireAfterUpdate_Active_Updated_BeforeNow() { 91 now := time.Now().UTC() 92 newTimer := now.Add(9 * time.Second) 93 updatedNewTimer := now.Add(-1 * time.Second) 94 deadline := now.Add(3 * time.Second) 95 96 s.localTimerGate.Update(newTimer) 97 select { 98 case <-s.localTimerGate.FireCh(): 99 s.Fail("timer should not fire when current time not updated") 100 case <-time.NewTimer(deadline.Sub(now)).C: 101 } 102 103 s.True(s.localTimerGate.Update(updatedNewTimer)) 104 select { 105 case <-s.localTimerGate.FireCh(): 106 case <-time.NewTimer(deadline.Sub(now)).C: 107 s.Fail("timer should fire before test deadline") 108 } 109 } 110 111 func (s *localGateSuite) TestTimerFireAfterUpdate_Active_Updated() { 112 now := time.Now().UTC() 113 newTimer := now.Add(5 * time.Second) 114 updatedNewTimer := now.Add(1 * time.Second) 115 deadline := now.Add(3 * time.Second) 116 s.localTimerGate.Update(newTimer) 117 s.True(s.localTimerGate.Update(updatedNewTimer)) 118 119 select { 120 case <-s.localTimerGate.FireCh(): 121 case <-time.NewTimer(deadline.Sub(now)).C: 122 s.Fail("timer should fire before test deadline") 123 } 124 } 125 126 func (s *localGateSuite) TestTimerFireAfterUpdate_Active_NotUpdated() { 127 now := time.Now().UTC() 128 newTimer := now.Add(1 * time.Second) 129 updatedNewTimer := now.Add(3 * time.Second) 130 deadline := now.Add(2 * time.Second) 131 s.localTimerGate.Update(newTimer) 132 s.False(s.localTimerGate.Update(updatedNewTimer)) 133 134 select { 135 case <-s.localTimerGate.FireCh(): 136 case <-time.NewTimer(deadline.Sub(now)).C: 137 s.Fail("timer should fire before test deadline") 138 } 139 } 140 141 func (s *localGateSuite) TestTimerFireAfterUpdate_NotActive_Updated() { 142 now := time.Now().UTC() 143 newTimer := now.Add(-5 * time.Second) 144 updatedNewTimer := now.Add(1 * time.Second) 145 deadline := now.Add(3 * time.Second) 146 147 s.localTimerGate.Update(newTimer) 148 // this is to drain existing signal 149 <-s.localTimerGate.FireCh() 150 // test setup up complete 151 152 s.True(s.localTimerGate.Update(updatedNewTimer)) 153 select { 154 case <-s.localTimerGate.FireCh(): 155 case <-time.NewTimer(deadline.Sub(now)).C: 156 s.Fail("timer should fire before test deadline") 157 } 158 } 159 160 func (s *localGateSuite) TestTimerFireAfterUpdate_NotActive_NotUpdated() { 161 now := time.Now().UTC() 162 newTimer := now.Add(-5 * time.Second) 163 updatedNewTimer := now.Add(-1 * time.Second) 164 deadline := now.Add(1 * time.Second) 165 166 s.localTimerGate.Update(newTimer) 167 // this is to drain existing signal 168 <-s.localTimerGate.FireCh() 169 // test setup up complete 170 171 s.True(s.localTimerGate.Update(updatedNewTimer)) 172 select { 173 case <-s.localTimerGate.FireCh(): 174 case <-time.NewTimer(deadline.Sub(now)).C: 175 s.Fail("timer should fire before test deadline") 176 } 177 } 178 179 func (s *localGateSuite) TestTimerWillFire_Zero() { 180 // this test is to validate initial notification will trigger a scan of timer 181 s.localTimerGate.Update(time.Time{}) 182 s.False(s.localTimerGate.FireAfter(time.Now().UTC())) 183 184 select { // this is to drain existing signal 185 case <-s.localTimerGate.FireCh(): 186 case <-time.NewTimer(time.Second).C: 187 } 188 189 now := time.Now().UTC() 190 newTimer := now.Add(1 * time.Second) 191 deadline := now.Add(2 * time.Second) 192 s.localTimerGate.Update(newTimer) 193 select { 194 case <-s.localTimerGate.FireCh(): 195 case <-time.NewTimer(deadline.Sub(now)).C: 196 s.Fail("timer should fire") 197 } 198 s.localTimerGate.Update(time.Time{}) 199 select { // this is to drain existing signal 200 case <-s.localTimerGate.FireCh(): 201 case <-time.NewTimer(time.Second).C: 202 s.Fail("timer should fire") 203 } 204 205 now = time.Now().UTC() 206 newTimer = now.Add(1 * time.Second) 207 s.localTimerGate.Update(newTimer) 208 s.localTimerGate.Update(time.Time{}) 209 select { // this is to drain existing signal 210 case <-s.localTimerGate.FireCh(): 211 case <-time.NewTimer(time.Second).C: 212 s.Fail("timer should fire") 213 } 214 } 215 216 func (s *localGateSuite) TestTimerWillFire() { 217 now := time.Now().UTC() 218 newTimer := now.Add(2 * time.Second) 219 timeBeforeNewTimer := now.Add(1 * time.Second) 220 timeAfterNewTimer := now.Add(3 * time.Second) 221 s.localTimerGate.Update(newTimer) 222 s.True(s.localTimerGate.FireAfter(timeBeforeNewTimer)) 223 s.False(s.localTimerGate.FireAfter(timeAfterNewTimer)) 224 }