github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/storetest/job_store.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package storetest 5 6 import ( 7 "testing" 8 9 "time" 10 11 "github.com/mattermost/mattermost-server/model" 12 "github.com/mattermost/mattermost-server/store" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestJobStore(t *testing.T, ss store.Store) { 17 t.Run("JobSaveGet", func(t *testing.T) { testJobSaveGet(t, ss) }) 18 t.Run("JobGetAllByType", func(t *testing.T) { testJobGetAllByType(t, ss) }) 19 t.Run("JobGetAllByTypePage", func(t *testing.T) { testJobGetAllByTypePage(t, ss) }) 20 t.Run("JobGetAllPage", func(t *testing.T) { testJobGetAllPage(t, ss) }) 21 t.Run("JobGetAllByStatus", func(t *testing.T) { testJobGetAllByStatus(t, ss) }) 22 t.Run("GetNewestJobByStatusAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusAndType(t, ss) }) 23 t.Run("GetCountByStatusAndType", func(t *testing.T) { testJobStoreGetCountByStatusAndType(t, ss) }) 24 t.Run("JobUpdateOptimistically", func(t *testing.T) { testJobUpdateOptimistically(t, ss) }) 25 t.Run("JobUpdateStatusUpdateStatusOptimistically", func(t *testing.T) { testJobUpdateStatusUpdateStatusOptimistically(t, ss) }) 26 t.Run("JobDelete", func(t *testing.T) { testJobDelete(t, ss) }) 27 } 28 29 func testJobSaveGet(t *testing.T, ss store.Store) { 30 job := &model.Job{ 31 Id: model.NewId(), 32 Type: model.NewId(), 33 Status: model.NewId(), 34 Data: map[string]string{ 35 "Processed": "0", 36 "Total": "12345", 37 "LastProcessed": "abcd", 38 }, 39 } 40 41 if result := <-ss.Job().Save(job); result.Err != nil { 42 t.Fatal(result.Err) 43 } 44 45 defer func() { 46 <-ss.Job().Delete(job.Id) 47 }() 48 49 if result := <-ss.Job().Get(job.Id); result.Err != nil { 50 t.Fatal(result.Err) 51 } else if received := result.Data.(*model.Job); received.Id != job.Id { 52 t.Fatal("received incorrect job after save") 53 } else if received.Data["Total"] != "12345" { 54 t.Fatal("data field was not retrieved successfully:", received.Data) 55 } 56 } 57 58 func testJobGetAllByType(t *testing.T, ss store.Store) { 59 jobType := model.NewId() 60 61 jobs := []*model.Job{ 62 { 63 Id: model.NewId(), 64 Type: jobType, 65 }, 66 { 67 Id: model.NewId(), 68 Type: jobType, 69 }, 70 { 71 Id: model.NewId(), 72 Type: model.NewId(), 73 }, 74 } 75 76 for _, job := range jobs { 77 store.Must(ss.Job().Save(job)) 78 defer ss.Job().Delete(job.Id) 79 } 80 81 if result := <-ss.Job().GetAllByType(jobType); result.Err != nil { 82 t.Fatal(result.Err) 83 } else if received := result.Data.([]*model.Job); len(received) != 2 { 84 t.Fatal("received wrong number of jobs") 85 } else if received[0].Id != jobs[0].Id && received[1].Id != jobs[0].Id { 86 t.Fatal("should've received first jobs") 87 } else if received[0].Id != jobs[1].Id && received[1].Id != jobs[1].Id { 88 t.Fatal("should've received second jobs") 89 } 90 } 91 92 func testJobGetAllByTypePage(t *testing.T, ss store.Store) { 93 jobType := model.NewId() 94 95 jobs := []*model.Job{ 96 { 97 Id: model.NewId(), 98 Type: jobType, 99 CreateAt: 1000, 100 }, 101 { 102 Id: model.NewId(), 103 Type: jobType, 104 CreateAt: 999, 105 }, 106 { 107 Id: model.NewId(), 108 Type: jobType, 109 CreateAt: 1001, 110 }, 111 { 112 Id: model.NewId(), 113 Type: model.NewId(), 114 CreateAt: 1002, 115 }, 116 } 117 118 for _, job := range jobs { 119 store.Must(ss.Job().Save(job)) 120 defer ss.Job().Delete(job.Id) 121 } 122 123 if result := <-ss.Job().GetAllByTypePage(jobType, 0, 2); result.Err != nil { 124 t.Fatal(result.Err) 125 } else if received := result.Data.([]*model.Job); len(received) != 2 { 126 t.Fatal("received wrong number of jobs") 127 } else if received[0].Id != jobs[2].Id { 128 t.Fatal("should've received newest job first") 129 } else if received[1].Id != jobs[0].Id { 130 t.Fatal("should've received second newest job second") 131 } 132 133 if result := <-ss.Job().GetAllByTypePage(jobType, 2, 2); result.Err != nil { 134 t.Fatal(result.Err) 135 } else if received := result.Data.([]*model.Job); len(received) != 1 { 136 t.Fatal("received wrong number of jobs") 137 } else if received[0].Id != jobs[1].Id { 138 t.Fatal("should've received oldest job last") 139 } 140 } 141 142 func testJobGetAllPage(t *testing.T, ss store.Store) { 143 jobType := model.NewId() 144 createAtTime := model.GetMillis() 145 146 jobs := []*model.Job{ 147 { 148 Id: model.NewId(), 149 Type: jobType, 150 CreateAt: createAtTime + 1, 151 }, 152 { 153 Id: model.NewId(), 154 Type: jobType, 155 CreateAt: createAtTime, 156 }, 157 { 158 Id: model.NewId(), 159 Type: jobType, 160 CreateAt: createAtTime + 2, 161 }, 162 } 163 164 for _, job := range jobs { 165 store.Must(ss.Job().Save(job)) 166 defer ss.Job().Delete(job.Id) 167 } 168 169 if result := <-ss.Job().GetAllPage(0, 2); result.Err != nil { 170 t.Fatal(result.Err) 171 } else if received := result.Data.([]*model.Job); len(received) != 2 { 172 t.Fatal("received wrong number of jobs") 173 } else if received[0].Id != jobs[2].Id { 174 t.Fatal("should've received newest job first") 175 } else if received[1].Id != jobs[0].Id { 176 t.Fatal("should've received second newest job second") 177 } 178 179 if result := <-ss.Job().GetAllPage(2, 2); result.Err != nil { 180 t.Fatal(result.Err) 181 } else if received := result.Data.([]*model.Job); len(received) < 1 { 182 t.Fatal("received wrong number of jobs") 183 } else if received[0].Id != jobs[1].Id { 184 t.Fatal("should've received oldest job last") 185 } 186 } 187 188 func testJobGetAllByStatus(t *testing.T, ss store.Store) { 189 jobType := model.NewId() 190 status := model.NewId() 191 192 jobs := []*model.Job{ 193 { 194 Id: model.NewId(), 195 Type: jobType, 196 CreateAt: 1000, 197 Status: status, 198 Data: map[string]string{ 199 "test": "data", 200 }, 201 }, 202 { 203 Id: model.NewId(), 204 Type: jobType, 205 CreateAt: 999, 206 Status: status, 207 }, 208 { 209 Id: model.NewId(), 210 Type: jobType, 211 CreateAt: 1001, 212 Status: status, 213 }, 214 { 215 Id: model.NewId(), 216 Type: jobType, 217 CreateAt: 1002, 218 Status: model.NewId(), 219 }, 220 } 221 222 for _, job := range jobs { 223 store.Must(ss.Job().Save(job)) 224 defer ss.Job().Delete(job.Id) 225 } 226 227 if result := <-ss.Job().GetAllByStatus(status); result.Err != nil { 228 t.Fatal(result.Err) 229 } else if received := result.Data.([]*model.Job); len(received) != 3 { 230 t.Fatal("received wrong number of jobs") 231 } else if received[0].Id != jobs[1].Id || received[1].Id != jobs[0].Id || received[2].Id != jobs[2].Id { 232 t.Fatal("should've received jobs ordered by CreateAt time") 233 } else if received[1].Data["test"] != "data" { 234 t.Fatal("should've received job data field back as saved") 235 } 236 } 237 238 func testJobStoreGetNewestJobByStatusAndType(t *testing.T, ss store.Store) { 239 jobType1 := model.NewId() 240 jobType2 := model.NewId() 241 status1 := model.NewId() 242 status2 := model.NewId() 243 244 jobs := []*model.Job{ 245 { 246 Id: model.NewId(), 247 Type: jobType1, 248 CreateAt: 1001, 249 Status: status1, 250 }, 251 { 252 Id: model.NewId(), 253 Type: jobType1, 254 CreateAt: 1000, 255 Status: status1, 256 }, 257 { 258 Id: model.NewId(), 259 Type: jobType2, 260 CreateAt: 1003, 261 Status: status1, 262 }, 263 { 264 Id: model.NewId(), 265 Type: jobType1, 266 CreateAt: 1004, 267 Status: status2, 268 }, 269 } 270 271 for _, job := range jobs { 272 store.Must(ss.Job().Save(job)) 273 defer ss.Job().Delete(job.Id) 274 } 275 276 result := <-ss.Job().GetNewestJobByStatusAndType(status1, jobType1) 277 assert.Nil(t, result.Err) 278 assert.EqualValues(t, jobs[0].Id, result.Data.(*model.Job).Id) 279 280 result = <-ss.Job().GetNewestJobByStatusAndType(model.NewId(), model.NewId()) 281 assert.Nil(t, result.Err) 282 assert.Nil(t, result.Data.(*model.Job)) 283 } 284 285 func testJobStoreGetCountByStatusAndType(t *testing.T, ss store.Store) { 286 jobType1 := model.NewId() 287 jobType2 := model.NewId() 288 status1 := model.NewId() 289 status2 := model.NewId() 290 291 jobs := []*model.Job{ 292 { 293 Id: model.NewId(), 294 Type: jobType1, 295 CreateAt: 1000, 296 Status: status1, 297 }, 298 { 299 Id: model.NewId(), 300 Type: jobType1, 301 CreateAt: 999, 302 Status: status1, 303 }, 304 { 305 Id: model.NewId(), 306 Type: jobType2, 307 CreateAt: 1001, 308 Status: status1, 309 }, 310 { 311 Id: model.NewId(), 312 Type: jobType1, 313 CreateAt: 1002, 314 Status: status2, 315 }, 316 } 317 318 for _, job := range jobs { 319 store.Must(ss.Job().Save(job)) 320 defer ss.Job().Delete(job.Id) 321 } 322 323 result := <-ss.Job().GetCountByStatusAndType(status1, jobType1) 324 assert.Nil(t, result.Err) 325 assert.EqualValues(t, 2, result.Data.(int64)) 326 327 result = <-ss.Job().GetCountByStatusAndType(status2, jobType2) 328 assert.Nil(t, result.Err) 329 assert.EqualValues(t, 0, result.Data.(int64)) 330 331 result = <-ss.Job().GetCountByStatusAndType(status1, jobType2) 332 assert.Nil(t, result.Err) 333 assert.EqualValues(t, 1, result.Data.(int64)) 334 335 result = <-ss.Job().GetCountByStatusAndType(status2, jobType1) 336 assert.Nil(t, result.Err) 337 assert.EqualValues(t, 1, result.Data.(int64)) 338 } 339 340 func testJobUpdateOptimistically(t *testing.T, ss store.Store) { 341 job := &model.Job{ 342 Id: model.NewId(), 343 Type: model.JOB_TYPE_DATA_RETENTION, 344 CreateAt: model.GetMillis(), 345 Status: model.JOB_STATUS_PENDING, 346 } 347 348 if result := <-ss.Job().Save(job); result.Err != nil { 349 t.Fatal(result.Err) 350 } 351 defer ss.Job().Delete(job.Id) 352 353 job.LastActivityAt = model.GetMillis() 354 job.Status = model.JOB_STATUS_IN_PROGRESS 355 job.Progress = 50 356 job.Data = map[string]string{ 357 "Foo": "Bar", 358 } 359 360 if result := <-ss.Job().UpdateOptimistically(job, model.JOB_STATUS_SUCCESS); result.Err != nil { 361 if result.Data.(bool) { 362 t.Fatal("should have failed due to incorrect old status") 363 } 364 } 365 366 time.Sleep(2 * time.Millisecond) 367 368 if result := <-ss.Job().UpdateOptimistically(job, model.JOB_STATUS_PENDING); result.Err != nil { 369 t.Fatal(result.Err) 370 } else { 371 if !result.Data.(bool) { 372 t.Fatal("Should have successfully updated") 373 } 374 375 var updatedJob *model.Job 376 377 if result := <-ss.Job().Get(job.Id); result.Err != nil { 378 t.Fatal(result.Err) 379 } else { 380 updatedJob = result.Data.(*model.Job) 381 } 382 383 if updatedJob.Type != job.Type || updatedJob.CreateAt != job.CreateAt || updatedJob.Status != job.Status || updatedJob.LastActivityAt <= job.LastActivityAt || updatedJob.Progress != job.Progress || updatedJob.Data["Foo"] != job.Data["Foo"] { 384 t.Fatal("Some update property was not as expected") 385 } 386 } 387 388 } 389 390 func testJobUpdateStatusUpdateStatusOptimistically(t *testing.T, ss store.Store) { 391 job := &model.Job{ 392 Id: model.NewId(), 393 Type: model.JOB_TYPE_DATA_RETENTION, 394 CreateAt: model.GetMillis(), 395 Status: model.JOB_STATUS_SUCCESS, 396 } 397 398 var lastUpdateAt int64 399 if result := <-ss.Job().Save(job); result.Err != nil { 400 t.Fatal(result.Err) 401 } else { 402 lastUpdateAt = result.Data.(*model.Job).LastActivityAt 403 } 404 405 defer ss.Job().Delete(job.Id) 406 407 time.Sleep(2 * time.Millisecond) 408 409 if result := <-ss.Job().UpdateStatus(job.Id, model.JOB_STATUS_PENDING); result.Err != nil { 410 t.Fatal(result.Err) 411 } else { 412 received := result.Data.(*model.Job) 413 if received.Status != model.JOB_STATUS_PENDING { 414 t.Fatal("status wasn't updated") 415 } 416 if received.LastActivityAt <= lastUpdateAt { 417 t.Fatal("lastActivityAt wasn't updated") 418 } 419 lastUpdateAt = received.LastActivityAt 420 } 421 422 time.Sleep(2 * time.Millisecond) 423 424 if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS); result.Err != nil { 425 t.Fatal(result.Err) 426 } else { 427 if result.Data.(bool) { 428 t.Fatal("should be false due to incorrect original status") 429 } 430 } 431 432 if result := <-ss.Job().Get(job.Id); result.Err != nil { 433 t.Fatal(result.Err) 434 } else { 435 received := result.Data.(*model.Job) 436 if received.Status != model.JOB_STATUS_PENDING { 437 t.Fatal("should still be pending") 438 } 439 if received.LastActivityAt != lastUpdateAt { 440 t.Fatal("last activity at shouldn't have changed") 441 } 442 } 443 444 time.Sleep(2 * time.Millisecond) 445 446 if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS); result.Err != nil { 447 t.Fatal(result.Err) 448 } else { 449 if !result.Data.(bool) { 450 t.Fatal("should have succeeded") 451 } 452 } 453 454 var startAtSet int64 455 if result := <-ss.Job().Get(job.Id); result.Err != nil { 456 t.Fatal(result.Err) 457 } else { 458 received := result.Data.(*model.Job) 459 if received.Status != model.JOB_STATUS_IN_PROGRESS { 460 t.Fatal("should be in progress") 461 } 462 if received.StartAt == 0 { 463 t.Fatal("received should have start at set") 464 } 465 if received.LastActivityAt <= lastUpdateAt { 466 t.Fatal("lastActivityAt wasn't updated") 467 } 468 lastUpdateAt = received.LastActivityAt 469 startAtSet = received.StartAt 470 } 471 472 time.Sleep(2 * time.Millisecond) 473 474 if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS); result.Err != nil { 475 t.Fatal(result.Err) 476 } else { 477 if !result.Data.(bool) { 478 t.Fatal("should have succeeded") 479 } 480 } 481 482 if result := <-ss.Job().Get(job.Id); result.Err != nil { 483 t.Fatal(result.Err) 484 } else { 485 received := result.Data.(*model.Job) 486 if received.Status != model.JOB_STATUS_SUCCESS { 487 t.Fatal("should be success status") 488 } 489 if received.StartAt != startAtSet { 490 t.Fatal("startAt should not have changed") 491 } 492 if received.LastActivityAt <= lastUpdateAt { 493 t.Fatal("lastActivityAt wasn't updated") 494 } 495 } 496 } 497 498 func testJobDelete(t *testing.T, ss store.Store) { 499 job := store.Must(ss.Job().Save(&model.Job{ 500 Id: model.NewId(), 501 })).(*model.Job) 502 503 if result := <-ss.Job().Delete(job.Id); result.Err != nil { 504 t.Fatal(result.Err) 505 } 506 }