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