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