|
1 | 1 | import { Octokit } from '@octokit/rest';
|
| 2 | +import { RequestError } from '@octokit/request-error'; |
2 | 3 | import moment from 'moment';
|
3 | 4 | import nock from 'nock';
|
4 | 5 |
|
@@ -403,6 +404,121 @@ describe('Scale down runners', () => {
|
403 | 404 | expect(mockTerminateRunners).toHaveBeenCalledWith(orphanRunner.instanceId);
|
404 | 405 | });
|
405 | 406 |
|
| 407 | + it('Should handle 404 error when checking orphaned runner (JIT) - treat as orphaned', async () => { |
| 408 | + // arrange |
| 409 | + const orphanRunner = createRunnerTestData( |
| 410 | + 'orphan-jit-404', |
| 411 | + type, |
| 412 | + MINIMUM_BOOT_TIME + 1, |
| 413 | + false, |
| 414 | + true, |
| 415 | + true, // should be terminated when 404 |
| 416 | + undefined, |
| 417 | + 1234567890, |
| 418 | + ); |
| 419 | + const runners = [orphanRunner]; |
| 420 | + |
| 421 | + mockGitHubRunners([]); |
| 422 | + mockAwsRunners(runners); |
| 423 | + |
| 424 | + // Mock 404 error response |
| 425 | + const error404 = new RequestError('Runner not found', 404, { |
| 426 | + request: { |
| 427 | + method: 'GET', |
| 428 | + url: 'https://api.github.com/test', |
| 429 | + headers: {}, |
| 430 | + }, |
| 431 | + }); |
| 432 | + |
| 433 | + if (type === 'Repo') { |
| 434 | + mockOctokit.actions.getSelfHostedRunnerForRepo.mockRejectedValueOnce(error404); |
| 435 | + } else { |
| 436 | + mockOctokit.actions.getSelfHostedRunnerForOrg.mockRejectedValueOnce(error404); |
| 437 | + } |
| 438 | + |
| 439 | + // act |
| 440 | + await scaleDown(); |
| 441 | + |
| 442 | + // assert - should terminate since 404 means runner doesn't exist on GitHub |
| 443 | + expect(mockTerminateRunners).toHaveBeenCalledWith(orphanRunner.instanceId); |
| 444 | + }); |
| 445 | + |
| 446 | + it('Should handle 404 error when checking runner busy state - treat as not busy', async () => { |
| 447 | + // arrange |
| 448 | + const runner = createRunnerTestData( |
| 449 | + 'runner-404', |
| 450 | + type, |
| 451 | + MINIMUM_TIME_RUNNING_IN_MINUTES + 1, |
| 452 | + true, |
| 453 | + false, |
| 454 | + true, // should be terminated since not busy due to 404 |
| 455 | + ); |
| 456 | + const runners = [runner]; |
| 457 | + |
| 458 | + mockGitHubRunners(runners); |
| 459 | + mockAwsRunners(runners); |
| 460 | + |
| 461 | + // Mock 404 error response for busy state check |
| 462 | + const error404 = new RequestError('Runner not found', 404, { |
| 463 | + request: { |
| 464 | + method: 'GET', |
| 465 | + url: 'https://api.github.com/test', |
| 466 | + headers: {}, |
| 467 | + }, |
| 468 | + }); |
| 469 | + |
| 470 | + if (type === 'Repo') { |
| 471 | + mockOctokit.actions.getSelfHostedRunnerForRepo.mockRejectedValueOnce(error404); |
| 472 | + } else { |
| 473 | + mockOctokit.actions.getSelfHostedRunnerForOrg.mockRejectedValueOnce(error404); |
| 474 | + } |
| 475 | + |
| 476 | + // act |
| 477 | + await scaleDown(); |
| 478 | + |
| 479 | + // assert - should terminate since 404 means runner is not busy |
| 480 | + checkTerminated(runners); |
| 481 | + }); |
| 482 | + |
| 483 | + it('Should re-throw non-404 errors when checking runner state', async () => { |
| 484 | + // arrange |
| 485 | + const orphanRunner = createRunnerTestData( |
| 486 | + 'orphan-error', |
| 487 | + type, |
| 488 | + MINIMUM_BOOT_TIME + 1, |
| 489 | + false, |
| 490 | + true, |
| 491 | + false, |
| 492 | + undefined, |
| 493 | + 1234567890, |
| 494 | + ); |
| 495 | + const runners = [orphanRunner]; |
| 496 | + |
| 497 | + mockGitHubRunners([]); |
| 498 | + mockAwsRunners(runners); |
| 499 | + |
| 500 | + // Mock non-404 error response |
| 501 | + const error500 = new RequestError('Internal server error', 500, { |
| 502 | + request: { |
| 503 | + method: 'GET', |
| 504 | + url: 'https://api.github.com/test', |
| 505 | + headers: {}, |
| 506 | + }, |
| 507 | + }); |
| 508 | + |
| 509 | + if (type === 'Repo') { |
| 510 | + mockOctokit.actions.getSelfHostedRunnerForRepo.mockRejectedValueOnce(error500); |
| 511 | + } else { |
| 512 | + mockOctokit.actions.getSelfHostedRunnerForOrg.mockRejectedValueOnce(error500); |
| 513 | + } |
| 514 | + |
| 515 | + // act & assert - should not throw because error handling is in terminateOrphan |
| 516 | + await expect(scaleDown()).resolves.not.toThrow(); |
| 517 | + |
| 518 | + // Should not terminate since the error was not a 404 |
| 519 | + expect(terminateRunner).not.toHaveBeenCalledWith(orphanRunner.instanceId); |
| 520 | + }); |
| 521 | + |
406 | 522 | it(`Should ignore errors when termination orphan fails.`, async () => {
|
407 | 523 | // setup
|
408 | 524 | const orphanRunner = createRunnerTestData('orphan-1', type, MINIMUM_BOOT_TIME + 1, false, true, true);
|
|
0 commit comments