go.temporal.io/server@v1.23.0/common/persistence/tests/task_queue.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 "context" 29 "math/rand" 30 "testing" 31 "time" 32 33 "github.com/google/uuid" 34 "github.com/stretchr/testify/require" 35 "github.com/stretchr/testify/suite" 36 enumspb "go.temporal.io/api/enums/v1" 37 "go.temporal.io/api/serviceerror" 38 "google.golang.org/protobuf/types/known/timestamppb" 39 40 persistencespb "go.temporal.io/server/api/persistence/v1" 41 "go.temporal.io/server/common/debug" 42 "go.temporal.io/server/common/log" 43 p "go.temporal.io/server/common/persistence" 44 "go.temporal.io/server/common/persistence/serialization" 45 "go.temporal.io/server/common/testing/protorequire" 46 ) 47 48 type ( 49 TaskQueueSuite struct { 50 suite.Suite 51 *require.Assertions 52 protorequire.ProtoAssertions 53 54 stickyTTL time.Duration 55 namespaceID string 56 taskQueueName string 57 taskQueueType enumspb.TaskQueueType 58 59 taskManager p.TaskManager 60 logger log.Logger 61 62 ctx context.Context 63 cancel context.CancelFunc 64 } 65 ) 66 67 func NewTaskQueueSuite( 68 t *testing.T, 69 taskManager p.TaskStore, 70 logger log.Logger, 71 ) *TaskQueueSuite { 72 return &TaskQueueSuite{ 73 Assertions: require.New(t), 74 ProtoAssertions: protorequire.New(t), 75 taskManager: p.NewTaskManager( 76 taskManager, 77 serialization.NewSerializer(), 78 ), 79 logger: logger, 80 } 81 } 82 83 func (s *TaskQueueSuite) SetupSuite() { 84 } 85 86 func (s *TaskQueueSuite) TearDownSuite() { 87 } 88 89 func (s *TaskQueueSuite) SetupTest() { 90 s.Assertions = require.New(s.T()) 91 s.ctx, s.cancel = context.WithTimeout(context.Background(), 30*time.Second*debug.TimeoutMultiplier) 92 93 s.stickyTTL = time.Second * 10 94 s.namespaceID = uuid.New().String() 95 s.taskQueueName = uuid.New().String() 96 s.taskQueueType = enumspb.TaskQueueType(rand.Int31n( 97 int32(len(enumspb.TaskQueueType_value)) + 1), 98 ) 99 } 100 101 func (s *TaskQueueSuite) TearDownTest() { 102 s.cancel() 103 } 104 105 func (s *TaskQueueSuite) TestCreate_Normal() { 106 rangID := rand.Int63() 107 taskQueue := s.createTaskQueue(rangID, enumspb.TASK_QUEUE_KIND_NORMAL) 108 109 s.assertEqualWithDB(rangID, taskQueue) 110 } 111 112 func (s *TaskQueueSuite) TestCreate_Sticky() { 113 rangID := rand.Int63() 114 taskQueue := s.createTaskQueue(rangID, enumspb.TASK_QUEUE_KIND_STICKY) 115 116 s.assertEqualWithDB(rangID, taskQueue) 117 } 118 119 func (s *TaskQueueSuite) TestCreate_Normal_Dup() { 120 rangID := rand.Int63() 121 taskQueue := s.createTaskQueue(rangID, enumspb.TASK_QUEUE_KIND_NORMAL) 122 123 _, err := s.taskManager.CreateTaskQueue(s.ctx, &p.CreateTaskQueueRequest{ 124 RangeID: rangID, 125 TaskQueueInfo: s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_NORMAL), 126 }) 127 s.IsType(&p.ConditionFailedError{}, err) 128 129 s.assertEqualWithDB(rangID, taskQueue) 130 } 131 132 func (s *TaskQueueSuite) TestCreate_Sticky_Dup() { 133 rangID := rand.Int63() 134 taskQueue := s.createTaskQueue(rangID, enumspb.TASK_QUEUE_KIND_STICKY) 135 136 _, err := s.taskManager.CreateTaskQueue(s.ctx, &p.CreateTaskQueueRequest{ 137 RangeID: rangID, 138 TaskQueueInfo: s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_STICKY), 139 }) 140 s.IsType(&p.ConditionFailedError{}, err) 141 142 s.assertEqualWithDB(rangID, taskQueue) 143 } 144 145 func (s *TaskQueueSuite) TestUpdate_Normal() { 146 prevRangeID := rand.Int63() 147 _ = s.createTaskQueue(prevRangeID, enumspb.TASK_QUEUE_KIND_NORMAL) 148 149 rangID := rand.Int63() 150 taskQueue := s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_NORMAL) 151 _, err := s.taskManager.UpdateTaskQueue(s.ctx, &p.UpdateTaskQueueRequest{ 152 RangeID: rangID, 153 TaskQueueInfo: taskQueue, 154 155 PrevRangeID: prevRangeID, 156 }) 157 s.NoError(err) 158 159 s.assertEqualWithDB(rangID, taskQueue) 160 } 161 162 func (s *TaskQueueSuite) TestUpdate_Normal_Conflict() { 163 prevRangeID := rand.Int63() 164 taskQueue := s.createTaskQueue(prevRangeID, enumspb.TASK_QUEUE_KIND_NORMAL) 165 166 rangID := rand.Int63() 167 _, err := s.taskManager.UpdateTaskQueue(s.ctx, &p.UpdateTaskQueueRequest{ 168 RangeID: rangID, 169 TaskQueueInfo: s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_NORMAL), 170 171 PrevRangeID: rand.Int63(), 172 }) 173 s.IsType(&p.ConditionFailedError{}, err) 174 175 s.assertEqualWithDB(prevRangeID, taskQueue) 176 } 177 178 func (s *TaskQueueSuite) TestUpdate_Sticky() { 179 prevRangeID := rand.Int63() 180 _ = s.createTaskQueue(prevRangeID, enumspb.TASK_QUEUE_KIND_STICKY) 181 182 rangID := rand.Int63() 183 taskQueue := s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_STICKY) 184 _, err := s.taskManager.UpdateTaskQueue(s.ctx, &p.UpdateTaskQueueRequest{ 185 RangeID: rangID, 186 TaskQueueInfo: taskQueue, 187 188 PrevRangeID: prevRangeID, 189 }) 190 s.NoError(err) 191 192 s.assertEqualWithDB(rangID, taskQueue) 193 } 194 195 func (s *TaskQueueSuite) TestUpdate_Sticky_Conflict() { 196 prevRangeID := rand.Int63() 197 taskQueue := s.createTaskQueue(prevRangeID, enumspb.TASK_QUEUE_KIND_STICKY) 198 199 rangID := rand.Int63() 200 _, err := s.taskManager.UpdateTaskQueue(s.ctx, &p.UpdateTaskQueueRequest{ 201 RangeID: rangID, 202 TaskQueueInfo: s.randomTaskQueueInfo(enumspb.TASK_QUEUE_KIND_STICKY), 203 204 PrevRangeID: rand.Int63(), 205 }) 206 s.IsType(&p.ConditionFailedError{}, err) 207 208 s.assertEqualWithDB(prevRangeID, taskQueue) 209 } 210 211 func (s *TaskQueueSuite) TestDelete() { 212 rangeID := rand.Int63() 213 taskQueue := s.createTaskQueue( 214 rangeID, 215 enumspb.TaskQueueKind(rand.Int31n( 216 int32(len(enumspb.TaskQueueKind_value))+1), 217 ), 218 ) 219 220 err := s.taskManager.DeleteTaskQueue(s.ctx, &p.DeleteTaskQueueRequest{ 221 TaskQueue: &p.TaskQueueKey{ 222 NamespaceID: taskQueue.NamespaceId, 223 TaskQueueName: taskQueue.Name, 224 TaskQueueType: taskQueue.TaskType, 225 }, 226 RangeID: rangeID, 227 }) 228 s.NoError(err) 229 230 s.assertMissingFromDB(taskQueue.NamespaceId, taskQueue.Name, taskQueue.TaskType) 231 } 232 233 func (s *TaskQueueSuite) TestDelete_Conflict() { 234 rangeID := rand.Int63() 235 taskQueue := s.createTaskQueue( 236 rangeID, 237 enumspb.TaskQueueKind(rand.Int31n( 238 int32(len(enumspb.TaskQueueKind_value))+1), 239 ), 240 ) 241 242 err := s.taskManager.DeleteTaskQueue(s.ctx, &p.DeleteTaskQueueRequest{ 243 TaskQueue: &p.TaskQueueKey{ 244 NamespaceID: taskQueue.NamespaceId, 245 TaskQueueName: taskQueue.Name, 246 TaskQueueType: taskQueue.TaskType, 247 }, 248 RangeID: rand.Int63(), 249 }) 250 s.IsType(&p.ConditionFailedError{}, err) 251 252 s.assertEqualWithDB(rangeID, taskQueue) 253 } 254 255 func (s *TaskQueueSuite) TesList() { 256 // TODO there exists a SQL impl, but no cassandra impl ... 257 } 258 259 func (s *TaskQueueSuite) createTaskQueue( 260 rangeID int64, 261 taskQueueKind enumspb.TaskQueueKind, 262 ) *persistencespb.TaskQueueInfo { 263 taskQueue := s.randomTaskQueueInfo(taskQueueKind) 264 _, err := s.taskManager.CreateTaskQueue(s.ctx, &p.CreateTaskQueueRequest{ 265 RangeID: rangeID, 266 TaskQueueInfo: taskQueue, 267 }) 268 s.NoError(err) 269 return taskQueue 270 } 271 272 func (s *TaskQueueSuite) randomTaskQueueInfo( 273 taskQueueKind enumspb.TaskQueueKind, 274 ) *persistencespb.TaskQueueInfo { 275 now := time.Now().UTC() 276 var expiryTime *timestamppb.Timestamp 277 if taskQueueKind == enumspb.TASK_QUEUE_KIND_STICKY { 278 expiryTime = timestamppb.New(now.Add(s.stickyTTL)) 279 } 280 281 return &persistencespb.TaskQueueInfo{ 282 NamespaceId: s.namespaceID, 283 Name: s.taskQueueName, 284 TaskType: s.taskQueueType, 285 Kind: taskQueueKind, 286 AckLevel: rand.Int63(), 287 ExpiryTime: expiryTime, 288 LastUpdateTime: timestamppb.New(now), 289 } 290 } 291 292 func (s *TaskQueueSuite) assertMissingFromDB( 293 namespaceID string, 294 taskQueue string, 295 taskType enumspb.TaskQueueType, 296 ) { 297 _, err := s.taskManager.GetTaskQueue(s.ctx, &p.GetTaskQueueRequest{ 298 NamespaceID: namespaceID, 299 TaskQueue: taskQueue, 300 TaskType: taskType, 301 }) 302 s.IsType(&serviceerror.NotFound{}, err) 303 } 304 305 func (s *TaskQueueSuite) assertEqualWithDB( 306 rangeID int64, 307 taskQueueInfo *persistencespb.TaskQueueInfo, 308 ) { 309 resp, err := s.taskManager.GetTaskQueue(s.ctx, &p.GetTaskQueueRequest{ 310 NamespaceID: taskQueueInfo.NamespaceId, 311 TaskQueue: taskQueueInfo.Name, 312 TaskType: taskQueueInfo.TaskType, 313 }) 314 s.NoError(err) 315 316 s.Equal(rangeID, resp.RangeID) 317 s.ProtoEqual(taskQueueInfo, resp.TaskQueueInfo) 318 }