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