github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/jobs/jobs_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package jobs 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/masterhung0112/hk_server/v5/einterfaces/mocks" 12 "github.com/masterhung0112/hk_server/v5/model" 13 "github.com/masterhung0112/hk_server/v5/store" 14 "github.com/masterhung0112/hk_server/v5/store/storetest/mockstore" 15 "github.com/masterhung0112/hk_server/v5/utils/testutils" 16 ) 17 18 func makeJobServer(t *testing.T) (*JobServer, *mockstore.Store, *mocks.MetricsInterface) { 19 configService := &testutils.StaticConfigService{} 20 21 mockStore := &mockstore.Store{} 22 t.Cleanup(func() { 23 mockStore.AssertExpectations(t) 24 }) 25 26 mockMetrics := &mocks.MetricsInterface{} 27 t.Cleanup(func() { 28 mockMetrics.AssertExpectations(t) 29 }) 30 31 jobServer := NewJobServer(configService, mockStore, mockMetrics) 32 33 return jobServer, mockStore, mockMetrics 34 } 35 36 func expectErrorId(t *testing.T, errId string, appErr *model.AppError) { 37 t.Helper() 38 require.NotNil(t, appErr) 39 require.Equal(t, errId, appErr.Id) 40 } 41 42 func makeTeamEditionJobServer(t *testing.T) (*JobServer, *mockstore.Store) { 43 configService := &testutils.StaticConfigService{} 44 45 mockStore := &mockstore.Store{} 46 t.Cleanup(func() { 47 mockStore.AssertExpectations(t) 48 }) 49 50 jobServer := NewJobServer(configService, mockStore, nil) 51 52 return jobServer, mockStore 53 } 54 55 func TestClaimJob(t *testing.T) { 56 t.Run("error claiming job", func(t *testing.T) { 57 jobServer, mockStore, _ := makeJobServer(t) 58 59 job := &model.Job{ 60 Id: "job_id", 61 Type: "job_type", 62 } 63 64 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS).Return(false, &model.AppError{Message: "message"}) 65 66 updated, err := jobServer.ClaimJob(job) 67 expectErrorId(t, "app.job.update.app_error", err) 68 require.False(t, updated) 69 }) 70 71 t.Run("no existing job to update", func(t *testing.T) { 72 jobServer, mockStore, _ := makeJobServer(t) 73 74 job := &model.Job{ 75 Id: "job_id", 76 Type: "job_type", 77 } 78 79 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS).Return(false, nil) 80 81 updated, err := jobServer.ClaimJob(job) 82 require.Nil(t, err) 83 require.False(t, updated) 84 }) 85 86 t.Run("pending job updated", func(t *testing.T) { 87 jobServer, mockStore, mockMetrics := makeJobServer(t) 88 89 job := &model.Job{ 90 Id: "job_id", 91 Type: "job_type", 92 } 93 94 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 95 mockMetrics.On("IncrementJobActive", "job_type") 96 97 updated, err := jobServer.ClaimJob(job) 98 require.Nil(t, err) 99 require.True(t, updated) 100 }) 101 102 t.Run("pending job updated, nil metrics service", func(t *testing.T) { 103 jobServer, mockStore := makeTeamEditionJobServer(t) 104 105 job := &model.Job{ 106 Id: "job_id", 107 Type: "job_type", 108 } 109 110 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 111 112 updated, err := jobServer.ClaimJob(job) 113 require.Nil(t, err) 114 require.True(t, updated) 115 }) 116 } 117 118 func TestSetJobProgress(t *testing.T) { 119 t.Run("error setting progress", func(t *testing.T) { 120 jobServer, mockStore, _ := makeJobServer(t) 121 122 progress := int64(50) 123 job := &model.Job{ 124 Id: "job_id", 125 Type: "job_type", 126 } 127 128 job.Status = model.JOB_STATUS_IN_PROGRESS 129 job.Progress = progress 130 131 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, &model.AppError{Message: "message"}) 132 133 err := jobServer.SetJobProgress(job, progress) 134 expectErrorId(t, "app.job.update.app_error", err) 135 }) 136 137 t.Run("progress updated", func(t *testing.T) { 138 jobServer, mockStore, _ := makeJobServer(t) 139 140 progress := int64(50) 141 job := &model.Job{ 142 Id: "job_id", 143 Type: "job_type", 144 } 145 146 job.Status = model.JOB_STATUS_IN_PROGRESS 147 job.Progress = progress 148 149 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 150 151 err := jobServer.SetJobProgress(job, progress) 152 require.Nil(t, err) 153 }) 154 } 155 156 func TestSetJobWarning(t *testing.T) { 157 t.Run("error setting status", func(t *testing.T) { 158 jobServer, mockStore, _ := makeJobServer(t) 159 160 job := &model.Job{ 161 Id: "job_id", 162 Type: "job_type", 163 } 164 165 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_WARNING).Return(job, &model.AppError{Message: "message"}) 166 167 err := jobServer.SetJobWarning(job) 168 expectErrorId(t, "app.job.update.app_error", err) 169 }) 170 171 t.Run("status updated", func(t *testing.T) { 172 jobServer, mockStore, _ := makeJobServer(t) 173 174 job := &model.Job{ 175 Id: "job_id", 176 Type: "job_type", 177 } 178 179 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_WARNING).Return(job, nil) 180 181 err := jobServer.SetJobWarning(job) 182 require.Nil(t, err) 183 }) 184 } 185 186 func TestSetJobSuccess(t *testing.T) { 187 t.Run("error setting status", func(t *testing.T) { 188 jobServer, mockStore, _ := makeJobServer(t) 189 190 job := &model.Job{ 191 Id: "job_id", 192 Type: "job_type", 193 } 194 195 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_SUCCESS).Return(job, &model.AppError{Message: "message"}) 196 197 err := jobServer.SetJobSuccess(job) 198 expectErrorId(t, "app.job.update.app_error", err) 199 }) 200 201 t.Run("status updated", func(t *testing.T) { 202 jobServer, mockStore, mockMetrics := makeJobServer(t) 203 204 job := &model.Job{ 205 Id: "job_id", 206 Type: "job_type", 207 } 208 209 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_SUCCESS).Return(job, nil) 210 mockMetrics.On("DecrementJobActive", "job_type") 211 212 err := jobServer.SetJobSuccess(job) 213 require.Nil(t, err) 214 }) 215 216 t.Run("status updated, nil metrics service", func(t *testing.T) { 217 jobServer, mockStore := makeTeamEditionJobServer(t) 218 219 job := &model.Job{ 220 Id: "job_id", 221 Type: "job_type", 222 } 223 224 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_SUCCESS).Return(job, nil) 225 226 err := jobServer.SetJobSuccess(job) 227 require.Nil(t, err) 228 }) 229 } 230 231 func TestSetJobError(t *testing.T) { 232 t.Run("nil provided job error", func(t *testing.T) { 233 t.Run("error setting status", func(t *testing.T) { 234 jobServer, mockStore, _ := makeJobServer(t) 235 236 job := &model.Job{ 237 Id: "job_id", 238 Type: "job_type", 239 } 240 241 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_ERROR).Return(job, &model.AppError{Message: "message"}) 242 243 err := jobServer.SetJobError(job, nil) 244 expectErrorId(t, "app.job.update.app_error", err) 245 }) 246 247 t.Run("status updated", func(t *testing.T) { 248 jobServer, mockStore, mockMetrics := makeJobServer(t) 249 250 job := &model.Job{ 251 Id: "job_id", 252 Type: "job_type", 253 } 254 255 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_ERROR).Return(job, nil) 256 mockMetrics.On("DecrementJobActive", "job_type") 257 258 err := jobServer.SetJobError(job, nil) 259 require.Nil(t, err) 260 }) 261 262 t.Run("status updated, nil metrics service", func(t *testing.T) { 263 jobServer, mockStore := makeTeamEditionJobServer(t) 264 265 job := &model.Job{ 266 Id: "job_id", 267 Type: "job_type", 268 } 269 270 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_ERROR).Return(job, nil) 271 272 err := jobServer.SetJobError(job, nil) 273 require.Nil(t, err) 274 }) 275 }) 276 277 t.Run("provided job error", func(t *testing.T) { 278 t.Run("error setting status", func(t *testing.T) { 279 jobServer, mockStore, _ := makeJobServer(t) 280 281 jobError := &model.AppError{Message: "message"} 282 283 job := &model.Job{ 284 Id: "job_id", 285 Type: "job_type", 286 Progress: -1, 287 Data: map[string]string{"error": jobError.Message}, 288 } 289 290 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, &model.AppError{Message: "message"}) 291 292 err := jobServer.SetJobError(job, jobError) 293 expectErrorId(t, "app.job.update.app_error", err) 294 }) 295 296 t.Run("status updated", func(t *testing.T) { 297 jobServer, mockStore, mockMetrics := makeJobServer(t) 298 299 jobError := &model.AppError{Message: "message"} 300 301 job := &model.Job{ 302 Id: "job_id", 303 Type: "job_type", 304 Progress: -1, 305 Data: map[string]string{"error": jobError.Message}, 306 } 307 308 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 309 mockMetrics.On("DecrementJobActive", "job_type") 310 311 err := jobServer.SetJobError(job, jobError) 312 require.Nil(t, err) 313 }) 314 315 t.Run("status updated, nil metrics service", func(t *testing.T) { 316 jobServer, mockStore := makeTeamEditionJobServer(t) 317 318 jobError := &model.AppError{Message: "message"} 319 320 job := &model.Job{ 321 Id: "job_id", 322 Type: "job_type", 323 Progress: -1, 324 Data: map[string]string{"error": jobError.Message}, 325 } 326 327 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 328 329 err := jobServer.SetJobError(job, jobError) 330 require.Nil(t, err) 331 }) 332 333 t.Run("status not updated, request cancellation, error setting status", func(t *testing.T) { 334 jobServer, mockStore, _ := makeJobServer(t) 335 336 jobError := &model.AppError{Message: "message"} 337 338 job := &model.Job{ 339 Id: "job_id", 340 Type: "job_type", 341 Progress: -1, 342 Data: map[string]string{"error": jobError.Message}, 343 } 344 345 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, nil) 346 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_CANCEL_REQUESTED).Return(false, &model.AppError{Message: "message"}) 347 348 err := jobServer.SetJobError(job, jobError) 349 expectErrorId(t, "app.job.update.app_error", err) 350 }) 351 352 t.Run("status not updated, request cancellation, status not updated", func(t *testing.T) { 353 jobServer, mockStore, _ := makeJobServer(t) 354 355 jobError := &model.AppError{Message: "message"} 356 357 job := &model.Job{ 358 Id: "job_id", 359 Type: "job_type", 360 Progress: -1, 361 Data: map[string]string{"error": jobError.Message}, 362 } 363 364 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, nil) 365 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_CANCEL_REQUESTED).Return(false, nil) 366 367 err := jobServer.SetJobError(job, jobError) 368 expectErrorId(t, "jobs.set_job_error.update.error", err) 369 }) 370 371 t.Run("status not updated, request cancellation, status updated", func(t *testing.T) { 372 jobServer, mockStore, _ := makeJobServer(t) 373 374 jobError := &model.AppError{Message: "message"} 375 376 job := &model.Job{ 377 Id: "job_id", 378 Type: "job_type", 379 Progress: -1, 380 Data: map[string]string{"error": jobError.Message}, 381 } 382 383 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, nil) 384 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_CANCEL_REQUESTED).Return(true, nil) 385 386 err := jobServer.SetJobError(job, jobError) 387 require.Nil(t, err) 388 }) 389 }) 390 } 391 392 func TestSetJobCanceled(t *testing.T) { 393 t.Run("error setting status", func(t *testing.T) { 394 jobServer, mockStore, _ := makeJobServer(t) 395 396 job := &model.Job{ 397 Id: "job_id", 398 Type: "job_type", 399 } 400 401 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_CANCELED).Return(job, &model.AppError{Message: "message"}) 402 403 err := jobServer.SetJobCanceled(job) 404 expectErrorId(t, "app.job.update.app_error", err) 405 }) 406 407 t.Run("status updated", func(t *testing.T) { 408 jobServer, mockStore, mockMetrics := makeJobServer(t) 409 410 job := &model.Job{ 411 Id: "job_id", 412 Type: "job_type", 413 } 414 415 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_CANCELED).Return(job, nil) 416 mockMetrics.On("DecrementJobActive", "job_type") 417 418 err := jobServer.SetJobCanceled(job) 419 require.Nil(t, err) 420 }) 421 422 t.Run("status updated, nil metrics service", func(t *testing.T) { 423 jobServer, mockStore := makeTeamEditionJobServer(t) 424 425 job := &model.Job{ 426 Id: "job_id", 427 Type: "job_type", 428 } 429 430 mockStore.JobStore.On("UpdateStatus", "job_id", model.JOB_STATUS_CANCELED).Return(job, nil) 431 432 err := jobServer.SetJobCanceled(job) 433 require.Nil(t, err) 434 }) 435 } 436 437 func TestUpdateInProgressJobData(t *testing.T) { 438 t.Run("error updating", func(t *testing.T) { 439 jobServer, mockStore, _ := makeJobServer(t) 440 441 job := &model.Job{ 442 Id: "job_id", 443 Type: "job_type", 444 } 445 446 job.Status = model.JOB_STATUS_IN_PROGRESS 447 448 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(false, &model.AppError{Message: "message"}) 449 450 err := jobServer.UpdateInProgressJobData(job) 451 expectErrorId(t, "app.job.update.app_error", err) 452 }) 453 454 t.Run("progress updated", func(t *testing.T) { 455 jobServer, mockStore, _ := makeJobServer(t) 456 457 job := &model.Job{ 458 Id: "job_id", 459 Type: "job_type", 460 } 461 462 job.Status = model.JOB_STATUS_IN_PROGRESS 463 464 mockStore.JobStore.On("UpdateOptimistically", job, model.JOB_STATUS_IN_PROGRESS).Return(true, nil) 465 466 err := jobServer.UpdateInProgressJobData(job) 467 require.Nil(t, err) 468 }) 469 } 470 471 func TestRequestCancellation(t *testing.T) { 472 t.Run("error cancelling", func(t *testing.T) { 473 jobServer, mockStore, _ := makeJobServer(t) 474 475 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(false, &model.AppError{Message: "message"}) 476 477 err := jobServer.RequestCancellation("job_id") 478 expectErrorId(t, "app.job.update.app_error", err) 479 }) 480 481 t.Run("cancelled, job not found", func(t *testing.T) { 482 jobServer, mockStore, _ := makeJobServer(t) 483 484 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(true, nil) 485 mockStore.JobStore.On("Get", "job_id").Return(nil, &store.ErrNotFound{}) 486 487 err := jobServer.RequestCancellation("job_id") 488 expectErrorId(t, "app.job.update.app_error", err) 489 }) 490 491 t.Run("cancelled, success", func(t *testing.T) { 492 jobServer, mockStore, mockMetrics := makeJobServer(t) 493 494 job := &model.Job{ 495 Id: "job_id", 496 Type: "job_type", 497 } 498 499 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(true, nil) 500 mockStore.JobStore.On("Get", "job_id").Return(job, nil) 501 mockMetrics.On("DecrementJobActive", "job_type") 502 503 err := jobServer.RequestCancellation("job_id") 504 require.Nil(t, err) 505 }) 506 507 t.Run("cancelled, success, nil metrics service", func(t *testing.T) { 508 jobServer, mockStore := makeTeamEditionJobServer(t) 509 510 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(true, nil) 511 512 err := jobServer.RequestCancellation("job_id") 513 require.Nil(t, err) 514 }) 515 516 t.Run("unable to cancel, requesting cancellation instead, error setting status", func(t *testing.T) { 517 jobServer, mockStore, _ := makeJobServer(t) 518 519 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(false, nil) 520 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_CANCEL_REQUESTED).Return(false, &model.AppError{Message: "message"}) 521 522 err := jobServer.RequestCancellation("job_id") 523 expectErrorId(t, "app.job.update.app_error", err) 524 }) 525 526 t.Run("unable to cancel, requesting cancellation instead, success", func(t *testing.T) { 527 jobServer, mockStore, _ := makeJobServer(t) 528 529 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(false, nil) 530 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_CANCEL_REQUESTED).Return(true, nil) 531 532 err := jobServer.RequestCancellation("job_id") 533 require.Nil(t, err) 534 }) 535 536 t.Run("unable to cancel, requesting cancellation instead, unexpected state", func(t *testing.T) { 537 jobServer, mockStore, _ := makeJobServer(t) 538 539 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_PENDING, model.JOB_STATUS_CANCELED).Return(false, nil) 540 mockStore.JobStore.On("UpdateStatusOptimistically", "job_id", model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_CANCEL_REQUESTED).Return(false, nil) 541 542 err := jobServer.RequestCancellation("job_id") 543 expectErrorId(t, "jobs.request_cancellation.status.error", err) 544 }) 545 }