@@ -346,12 +346,13 @@ describe('scaleUp with GHES', () => {
346346 return [ ] ;
347347 } ) ;
348348
349- let callCount = 0 ;
350349 mockOctokit . actions . generateRunnerJitconfigForOrg . mockImplementation ( ( { name } ) => {
351- callCount ++ ;
352350 if ( name === 'unit-test-i-instance-2' ) {
353351 // Simulate a 503 Service Unavailable error from GitHub
354- const error = new Error ( 'Service Unavailable' ) as any ;
352+ const error = new Error ( 'Service Unavailable' ) as Error & {
353+ status : number ;
354+ response : { status : number ; data : { message : string } } ;
355+ } ;
355356 error . status = 503 ;
356357 error . response = {
357358 status : 503 ,
@@ -361,7 +362,7 @@ describe('scaleUp with GHES', () => {
361362 }
362363 return {
363364 data : {
364- runner : { id : 9876543210 + callCount } ,
365+ runner : { id : 9876543210 } ,
365366 encoded_jit_config : `TEST_JIT_CONFIG_${ name } ` ,
366367 } ,
367368 headers : { } ,
@@ -410,6 +411,97 @@ describe('scaleUp with GHES', () => {
410411 } ) ;
411412 } ) ;
412413
414+ it ( 'should handle retryable errors with error handling logic' , async ( ) => {
415+ process . env . RUNNERS_MAXIMUM_COUNT = '5' ;
416+ mockCreateRunner . mockImplementation ( async ( ) => {
417+ return [ 'i-instance-1' , 'i-instance-2' ] ;
418+ } ) ;
419+ mockListRunners . mockImplementation ( async ( ) => {
420+ return [ ] ;
421+ } ) ;
422+
423+ mockOctokit . actions . generateRunnerJitconfigForOrg . mockImplementation ( ( { name } ) => {
424+ if ( name === 'unit-test-i-instance-1' ) {
425+ const error = new Error ( 'Internal Server Error' ) as Error & {
426+ status : number ;
427+ response : { status : number ; data : { message : string } } ;
428+ } ;
429+ error . status = 500 ;
430+ error . response = {
431+ status : 500 ,
432+ data : { message : 'Internal server error' } ,
433+ } ;
434+ throw error ;
435+ }
436+ return {
437+ data : {
438+ runner : { id : 9876543210 } ,
439+ encoded_jit_config : `TEST_JIT_CONFIG_${ name } ` ,
440+ } ,
441+ headers : { } ,
442+ } ;
443+ } ) ;
444+
445+ await scaleUpModule . scaleUp ( TEST_DATA ) ;
446+
447+ expect ( mockSSMClient ) . toHaveReceivedCommandWith ( PutParameterCommand , {
448+ Name : '/github-action-runners/default/runners/config/i-instance-2' ,
449+ Value : 'TEST_JIT_CONFIG_unit-test-i-instance-2' ,
450+ Type : 'SecureString' ,
451+ Tags : [ { Key : 'InstanceId' , Value : 'i-instance-2' } ] ,
452+ } ) ;
453+
454+ expect ( mockSSMClient ) . not . toHaveReceivedCommandWith ( PutParameterCommand , {
455+ Name : '/github-action-runners/default/runners/config/i-instance-1' ,
456+ } ) ;
457+ } ) ;
458+
459+ it ( 'should handle non-retryable 4xx errors gracefully' , async ( ) => {
460+ process . env . RUNNERS_MAXIMUM_COUNT = '5' ;
461+ mockCreateRunner . mockImplementation ( async ( ) => {
462+ return [ 'i-instance-1' , 'i-instance-2' ] ;
463+ } ) ;
464+ mockListRunners . mockImplementation ( async ( ) => {
465+ return [ ] ;
466+ } ) ;
467+
468+ mockOctokit . actions . generateRunnerJitconfigForOrg . mockImplementation ( ( { name } ) => {
469+ if ( name === 'unit-test-i-instance-1' ) {
470+ // 404 is not retryable - will fail immediately
471+ const error = new Error ( 'Not Found' ) as Error & {
472+ status : number ;
473+ response : { status : number ; data : { message : string } } ;
474+ } ;
475+ error . status = 404 ;
476+ error . response = {
477+ status : 404 ,
478+ data : { message : 'Resource not found' } ,
479+ } ;
480+ throw error ;
481+ }
482+ return {
483+ data : {
484+ runner : { id : 9876543210 } ,
485+ encoded_jit_config : `TEST_JIT_CONFIG_${ name } ` ,
486+ } ,
487+ headers : { } ,
488+ } ;
489+ } ) ;
490+
491+ await scaleUpModule . scaleUp ( TEST_DATA ) ;
492+
493+ expect ( mockSSMClient ) . toHaveReceivedCommandWith ( PutParameterCommand , {
494+ Name : '/github-action-runners/default/runners/config/i-instance-2' ,
495+ Value : 'TEST_JIT_CONFIG_unit-test-i-instance-2' ,
496+ Type : 'SecureString' ,
497+ Tags : [ { Key : 'InstanceId' , Value : 'i-instance-2' } ] ,
498+ } ) ;
499+
500+ expect ( mockSSMClient ) . not . toHaveReceivedCommandWith ( PutParameterCommand , {
501+ Name : '/github-action-runners/default/runners/config/i-instance-1' ,
502+ } ) ;
503+ } ) ;
504+
413505 it . each ( RUNNER_TYPES ) (
414506 'calls create start runner config of 40' + ' instances (ssm rate limit condition) to test time delay ' ,
415507 async ( type : RunnerType ) => {
0 commit comments