go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/tests/history_timer_task.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 tests 26 27 import ( 28 "math/rand" 29 "testing" 30 "time" 31 32 "github.com/stretchr/testify/require" 33 "github.com/stretchr/testify/suite" 34 35 "go.temporal.io/server/common/persistence" 36 "go.temporal.io/server/common/persistence/sql/sqlplugin" 37 "go.temporal.io/server/common/shuffle" 38 ) 39 40 type ( 41 historyHistoryTimerTaskSuite struct { 42 suite.Suite 43 *require.Assertions 44 45 store sqlplugin.HistoryTimerTask 46 } 47 ) 48 49 const ( 50 testHistoryTimerTaskEncoding = "random encoding" 51 ) 52 53 var ( 54 testHistoryTimerTaskData = []byte("random history timer task data") 55 ) 56 57 func NewHistoryTimerTaskSuite( 58 t *testing.T, 59 store sqlplugin.HistoryTimerTask, 60 ) *historyHistoryTimerTaskSuite { 61 return &historyHistoryTimerTaskSuite{ 62 Assertions: require.New(t), 63 store: store, 64 } 65 } 66 67 func (s *historyHistoryTimerTaskSuite) SetupSuite() { 68 69 } 70 71 func (s *historyHistoryTimerTaskSuite) TearDownSuite() { 72 73 } 74 75 func (s *historyHistoryTimerTaskSuite) SetupTest() { 76 s.Assertions = require.New(s.T()) 77 } 78 79 func (s *historyHistoryTimerTaskSuite) TearDownTest() { 80 81 } 82 83 func (s *historyHistoryTimerTaskSuite) TestInsert_Single_Success() { 84 shardID := rand.Int31() 85 timestamp := s.now() 86 taskID := int64(1) 87 88 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 89 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task}) 90 s.NoError(err) 91 rowsAffected, err := result.RowsAffected() 92 s.NoError(err) 93 s.Equal(1, int(rowsAffected)) 94 } 95 96 func (s *historyHistoryTimerTaskSuite) TestInsert_Multiple_Success() { 97 shardID := rand.Int31() 98 timestamp := s.now() 99 taskID := int64(1) 100 101 task1 := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 102 timestamp = timestamp.Add(time.Millisecond) 103 taskID++ 104 task2 := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 105 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task1, task2}) 106 s.NoError(err) 107 rowsAffected, err := result.RowsAffected() 108 s.NoError(err) 109 s.Equal(2, int(rowsAffected)) 110 } 111 112 func (s *historyHistoryTimerTaskSuite) TestInsert_Single_Fail_Duplicate() { 113 shardID := rand.Int31() 114 timestamp := s.now() 115 taskID := int64(1) 116 117 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 118 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task}) 119 s.NoError(err) 120 rowsAffected, err := result.RowsAffected() 121 s.NoError(err) 122 s.Equal(1, int(rowsAffected)) 123 124 task = s.newRandomTimerTaskRow(shardID, timestamp, taskID) 125 _, err = s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task}) 126 s.Error(err) // TODO persistence layer should do proper error translation 127 } 128 129 func (s *historyHistoryTimerTaskSuite) TestInsert_Multiple_Fail_Duplicate() { 130 shardID := rand.Int31() 131 timestamp := s.now() 132 taskID := int64(1) 133 134 task1 := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 135 timestamp = timestamp.Add(time.Millisecond) 136 taskID++ 137 task2 := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 138 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task1, task2}) 139 s.NoError(err) 140 rowsAffected, err := result.RowsAffected() 141 s.NoError(err) 142 s.Equal(2, int(rowsAffected)) 143 144 task2 = s.newRandomTimerTaskRow(shardID, timestamp, taskID) 145 timestamp = timestamp.Add(time.Millisecond) 146 taskID++ 147 task3 := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 148 _, err = s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task2, task3}) 149 s.Error(err) // TODO persistence layer should do proper error translation 150 } 151 152 func (s *historyHistoryTimerTaskSuite) TestInsertSelect_Single() { 153 shardID := rand.Int31() 154 timestamp := s.now() 155 taskID := int64(1) 156 157 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 158 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task}) 159 s.NoError(err) 160 rowsAffected, err := result.RowsAffected() 161 s.NoError(err) 162 s.Equal(1, int(rowsAffected)) 163 164 rangeFilter := sqlplugin.TimerTasksRangeFilter{ 165 ShardID: shardID, 166 InclusiveMinTaskID: taskID, 167 InclusiveMinVisibilityTimestamp: timestamp, 168 ExclusiveMaxVisibilityTimestamp: timestamp.Add(persistence.ScheduledTaskMinPrecision), 169 PageSize: 1, 170 } 171 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), rangeFilter) 172 s.NoError(err) 173 for index := range rows { 174 rows[index].ShardID = shardID 175 } 176 s.Equal([]sqlplugin.TimerTasksRow{task}, rows) 177 } 178 179 func (s *historyHistoryTimerTaskSuite) TestInsertSelect_Multiple() { 180 numTasks := 20 181 182 shardID := rand.Int31() 183 timestamp := s.now() 184 minTimestamp := timestamp 185 taskID := int64(1) 186 maxTimestamp := timestamp.Add(time.Duration(numTasks) * time.Millisecond) 187 188 var tasks []sqlplugin.TimerTasksRow 189 for i := 0; i < numTasks; i++ { 190 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 191 timestamp = timestamp.Add(time.Millisecond) 192 taskID++ 193 tasks = append(tasks, task) 194 } 195 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), tasks) 196 s.NoError(err) 197 rowsAffected, err := result.RowsAffected() 198 s.NoError(err) 199 s.Equal(numTasks, int(rowsAffected)) 200 201 filter := sqlplugin.TimerTasksRangeFilter{ 202 ShardID: shardID, 203 InclusiveMinVisibilityTimestamp: minTimestamp, 204 ExclusiveMaxVisibilityTimestamp: maxTimestamp, 205 PageSize: numTasks, 206 } 207 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), filter) 208 s.NoError(err) 209 for index := range rows { 210 rows[index].ShardID = shardID 211 } 212 s.Equal(tasks, rows) 213 } 214 215 func (s *historyHistoryTimerTaskSuite) TestDeleteSelect_Single() { 216 shardID := rand.Int31() 217 timestamp := s.now() 218 taskID := int64(1) 219 220 filter := sqlplugin.TimerTasksFilter{ 221 ShardID: shardID, 222 VisibilityTimestamp: timestamp, 223 TaskID: taskID, 224 } 225 result, err := s.store.DeleteFromTimerTasks(newExecutionContext(), filter) 226 s.NoError(err) 227 rowsAffected, err := result.RowsAffected() 228 s.NoError(err) 229 s.Equal(0, int(rowsAffected)) 230 231 rangeFilter := sqlplugin.TimerTasksRangeFilter{ 232 ShardID: shardID, 233 InclusiveMinTaskID: taskID, 234 InclusiveMinVisibilityTimestamp: timestamp, 235 ExclusiveMaxVisibilityTimestamp: timestamp.Add(persistence.ScheduledTaskMinPrecision), 236 PageSize: 1, 237 } 238 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), rangeFilter) 239 s.NoError(err) 240 for index := range rows { 241 rows[index].ShardID = shardID 242 } 243 s.Equal([]sqlplugin.TimerTasksRow(nil), rows) 244 } 245 246 func (s *historyHistoryTimerTaskSuite) TestDeleteSelect_Multiple() { 247 pageSize := 100 248 249 shardID := rand.Int31() 250 minTimestamp := s.now() 251 maxTimestamp := minTimestamp.Add(time.Minute) 252 253 filter := sqlplugin.TimerTasksRangeFilter{ 254 ShardID: shardID, 255 InclusiveMinVisibilityTimestamp: minTimestamp, 256 ExclusiveMaxVisibilityTimestamp: maxTimestamp, 257 PageSize: 0, 258 } 259 result, err := s.store.RangeDeleteFromTimerTasks(newExecutionContext(), filter) 260 s.NoError(err) 261 rowsAffected, err := result.RowsAffected() 262 s.NoError(err) 263 s.Equal(0, int(rowsAffected)) 264 265 filter.PageSize = pageSize 266 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), filter) 267 s.NoError(err) 268 for index := range rows { 269 rows[index].ShardID = shardID 270 } 271 s.Equal([]sqlplugin.TimerTasksRow(nil), rows) 272 } 273 274 func (s *historyHistoryTimerTaskSuite) TestInsertDeleteSelect_Single() { 275 shardID := rand.Int31() 276 timestamp := s.now() 277 taskID := int64(1) 278 279 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 280 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), []sqlplugin.TimerTasksRow{task}) 281 s.NoError(err) 282 rowsAffected, err := result.RowsAffected() 283 s.NoError(err) 284 s.Equal(1, int(rowsAffected)) 285 286 filter := sqlplugin.TimerTasksFilter{ 287 ShardID: shardID, 288 VisibilityTimestamp: timestamp, 289 TaskID: taskID, 290 } 291 result, err = s.store.DeleteFromTimerTasks(newExecutionContext(), filter) 292 s.NoError(err) 293 rowsAffected, err = result.RowsAffected() 294 s.NoError(err) 295 s.Equal(1, int(rowsAffected)) 296 297 rangeFilter := sqlplugin.TimerTasksRangeFilter{ 298 ShardID: shardID, 299 InclusiveMinTaskID: taskID, 300 InclusiveMinVisibilityTimestamp: timestamp, 301 ExclusiveMaxVisibilityTimestamp: timestamp.Add(persistence.ScheduledTaskMinPrecision), 302 PageSize: 1, 303 } 304 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), rangeFilter) 305 s.NoError(err) 306 for index := range rows { 307 rows[index].ShardID = shardID 308 } 309 s.Equal([]sqlplugin.TimerTasksRow(nil), rows) 310 } 311 312 func (s *historyHistoryTimerTaskSuite) TestInsertDeleteSelect_Multiple() { 313 numTasks := 20 314 pageSize := numTasks 315 316 shardID := rand.Int31() 317 timestamp := s.now() 318 minTimestamp := timestamp 319 taskID := int64(1) 320 maxTimestamp := timestamp.Add(time.Duration(numTasks) * time.Millisecond) 321 322 var tasks []sqlplugin.TimerTasksRow 323 for i := 0; i < numTasks; i++ { 324 task := s.newRandomTimerTaskRow(shardID, timestamp, taskID) 325 timestamp = timestamp.Add(time.Millisecond) 326 taskID++ 327 tasks = append(tasks, task) 328 } 329 result, err := s.store.InsertIntoTimerTasks(newExecutionContext(), tasks) 330 s.NoError(err) 331 rowsAffected, err := result.RowsAffected() 332 s.NoError(err) 333 s.Equal(numTasks, int(rowsAffected)) 334 335 filter := sqlplugin.TimerTasksRangeFilter{ 336 ShardID: shardID, 337 InclusiveMinVisibilityTimestamp: minTimestamp, 338 ExclusiveMaxVisibilityTimestamp: maxTimestamp, 339 PageSize: 0, 340 } 341 result, err = s.store.RangeDeleteFromTimerTasks(newExecutionContext(), filter) 342 s.NoError(err) 343 rowsAffected, err = result.RowsAffected() 344 s.NoError(err) 345 s.Equal(numTasks, int(rowsAffected)) 346 347 filter.PageSize = pageSize 348 rows, err := s.store.RangeSelectFromTimerTasks(newExecutionContext(), filter) 349 s.NoError(err) 350 for index := range rows { 351 rows[index].ShardID = shardID 352 } 353 s.Equal([]sqlplugin.TimerTasksRow(nil), rows) 354 } 355 356 func (s *historyHistoryTimerTaskSuite) now() time.Time { 357 return time.Now().UTC().Truncate(time.Millisecond) 358 } 359 360 func (s *historyHistoryTimerTaskSuite) newRandomTimerTaskRow( 361 shardID int32, 362 timestamp time.Time, 363 taskID int64, 364 ) sqlplugin.TimerTasksRow { 365 return sqlplugin.TimerTasksRow{ 366 ShardID: shardID, 367 VisibilityTimestamp: timestamp, 368 TaskID: taskID, 369 Data: shuffle.Bytes(testHistoryTimerTaskData), 370 DataEncoding: testHistoryTimerTaskEncoding, 371 } 372 }