@@ -5,7 +5,7 @@ import nock from 'nock';
5
5
6
6
import { RunnerInfo , RunnerList } from '../aws/runners.d' ;
7
7
import * as ghAuth from '../gh-auth/gh-auth' ;
8
- import { listEC2Runners , terminateRunner } from './../aws/runners' ;
8
+ import { listEC2Runners , terminateRunner , tag } from './../aws/runners' ;
9
9
import { githubCache } from './cache' ;
10
10
import { newestFirstStrategy , oldestFirstStrategy , scaleDown } from './scale-down' ;
11
11
@@ -42,6 +42,7 @@ const mockedAppAuth = mocked(ghAuth.createGithubAppAuth, { shallow: false });
42
42
const mockedInstallationAuth = mocked ( ghAuth . createGithubInstallationAuth , { shallow : false } ) ;
43
43
const mockCreateClient = mocked ( ghAuth . createOctoClient , { shallow : false } ) ;
44
44
const mockListRunners = mocked ( listEC2Runners ) ;
45
+ const mockTagRunners = mocked ( tag ) ;
45
46
const mockTerminateRunners = mocked ( terminateRunner ) ;
46
47
47
48
export interface TestData {
@@ -172,7 +173,7 @@ describe('Scale down runners', () => {
172
173
describe . each ( runnerTypes ) ( 'For %s runners.' , ( type ) => {
173
174
it ( 'Should not call terminate when no runners online.' , async ( ) => {
174
175
// setup
175
- mockListRunners . mockResolvedValue ( [ ] ) ;
176
+ mockAwsRunners ( [ ] ) ;
176
177
177
178
// act
178
179
await scaleDown ( ) ;
@@ -197,7 +198,8 @@ describe('Scale down runners', () => {
197
198
198
199
mockGitHubRunners ( runners ) ;
199
200
mockListRunners . mockResolvedValue ( runners ) ;
200
- // act
201
+ mockAwsRunners ( runners ) ;
202
+
201
203
await scaleDown ( ) ;
202
204
203
205
// assert
@@ -220,7 +222,7 @@ describe('Scale down runners', () => {
220
222
const runners = [ createRunnerTestData ( 'idle-1' , type , MINIMUM_TIME_RUNNING_IN_MINUTES - 1 , true , false , false ) ] ;
221
223
222
224
mockGitHubRunners ( runners ) ;
223
- mockListRunners . mockResolvedValue ( runners ) ;
225
+ mockAwsRunners ( runners ) ;
224
226
225
227
// act
226
228
await scaleDown ( ) ;
@@ -235,7 +237,7 @@ describe('Scale down runners', () => {
235
237
const runners = [ createRunnerTestData ( 'booting-1' , type , MINIMUM_BOOT_TIME - 1 , false , false , false ) ] ;
236
238
237
239
mockGitHubRunners ( runners ) ;
238
- mockListRunners . mockResolvedValue ( runners ) ;
240
+ mockAwsRunners ( runners ) ;
239
241
240
242
// act
241
243
await scaleDown ( ) ;
@@ -250,7 +252,7 @@ describe('Scale down runners', () => {
250
252
const runners = [ createRunnerTestData ( 'busy-1' , type , MINIMUM_TIME_RUNNING_IN_MINUTES + 1 , true , false , false ) ] ;
251
253
252
254
mockGitHubRunners ( runners ) ;
253
- mockListRunners . mockResolvedValue ( runners ) ;
255
+ mockAwsRunners ( runners ) ;
254
256
255
257
// act
256
258
await scaleDown ( ) ;
@@ -274,7 +276,7 @@ describe('Scale down runners', () => {
274
276
] ;
275
277
276
278
mockGitHubRunners ( runners ) ;
277
- mockListRunners . mockResolvedValue ( runners ) ;
279
+ mockAwsRunners ( runners ) ;
278
280
mockOctokit . actions . deleteSelfHostedRunnerFromRepo . mockImplementation ( ( ) => {
279
281
return { status : 500 } ;
280
282
} ) ;
@@ -293,10 +295,31 @@ describe('Scale down runners', () => {
293
295
294
296
it ( `Should terminate orphan.` , async ( ) => {
295
297
// setup
296
- const runners = [ createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , true , true ) ] ;
298
+ const orphanRunner = createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , false , false ) ;
299
+ const idleRunner = createRunnerTestData ( 'idle-1' , type , MINIMUM_BOOT_TIME + 1 , true , false , false ) ;
300
+ const runners = [ orphanRunner , idleRunner ] ;
297
301
298
- mockGitHubRunners ( [ ] ) ;
299
- mockListRunners . mockResolvedValue ( runners ) ;
302
+ mockGitHubRunners ( [ idleRunner ] ) ;
303
+ mockAwsRunners ( runners ) ;
304
+
305
+ // act
306
+ await scaleDown ( ) ;
307
+
308
+ // assert
309
+ checkTerminated ( runners ) ;
310
+ checkNonTerminated ( runners ) ;
311
+
312
+ expect ( mockTagRunners ) . toHaveBeenCalledWith ( orphanRunner . instanceId , [
313
+ {
314
+ Key : 'orphan' ,
315
+ Value : 'true' ,
316
+ } ,
317
+ ] ) ;
318
+ expect ( mockTagRunners ) . not . toHaveBeenCalledWith ( idleRunner . instanceId , expect . anything ( ) ) ;
319
+
320
+ // next cycle, update test data set orphan to true and terminate should be true
321
+ orphanRunner . orphan = true ;
322
+ orphanRunner . shouldBeTerminated = true ;
300
323
301
324
// act
302
325
await scaleDown ( ) ;
@@ -306,21 +329,60 @@ describe('Scale down runners', () => {
306
329
checkNonTerminated ( runners ) ;
307
330
} ) ;
308
331
309
- it ( `Should orphan termination failure is not resulting in an exception. .` , async ( ) => {
332
+ it ( `Should ignore errors when termination orphan fails .` , async ( ) => {
310
333
// setup
311
- const runners = [ createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , true , true ) ] ;
334
+ const orphanRunner = createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , true , true ) ;
335
+ const runners = [ orphanRunner ] ;
312
336
313
337
mockGitHubRunners ( [ ] ) ;
314
- mockListRunners . mockResolvedValue ( runners ) ;
315
- mockTerminateRunners . mockRejectedValue ( new Error ( 'Termination failed' ) ) ;
338
+ mockAwsRunners ( runners ) ;
339
+ mockTerminateRunners . mockImplementation ( ( ) => {
340
+ throw new Error ( 'Failed to terminate' ) ;
341
+ } ) ;
316
342
317
- // act and ensure no exception is thrown
318
- await expect ( scaleDown ( ) ) . resolves . not . toThrow ( ) ;
343
+ // act
344
+ await scaleDown ( ) ;
345
+
346
+ // assert
347
+ checkTerminated ( runners ) ;
348
+ checkNonTerminated ( runners ) ;
349
+ } ) ;
350
+
351
+ describe ( 'When orphan termination fails' , ( ) => {
352
+ it ( `Should not throw in case of list runner exception.` , async ( ) => {
353
+ // setup
354
+ const runners = [ createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , true , true ) ] ;
355
+
356
+ mockGitHubRunners ( [ ] ) ;
357
+ mockListRunners . mockRejectedValueOnce ( new Error ( 'Failed to list runners' ) ) ;
358
+ mockAwsRunners ( runners ) ;
359
+
360
+ // ac
361
+ await scaleDown ( ) ;
362
+
363
+ // assert
364
+ checkNonTerminated ( runners ) ;
365
+ } ) ;
366
+
367
+ it ( `Should not throw in case of terminate runner exception.` , async ( ) => {
368
+ // setup
369
+ const runners = [ createRunnerTestData ( 'orphan-1' , type , MINIMUM_BOOT_TIME + 1 , false , true , true ) ] ;
370
+
371
+ mockGitHubRunners ( [ ] ) ;
372
+ mockAwsRunners ( runners ) ;
373
+ mockTerminateRunners . mockRejectedValue ( new Error ( 'Failed to terminate' ) ) ;
374
+
375
+ // act and ensure no exception is thrown
376
+ await scaleDown ( ) ;
377
+
378
+ // assert
379
+ checkNonTerminated ( runners ) ;
380
+ } ) ;
319
381
} ) ;
320
382
321
383
it ( `Should not terminate instance in case de-register fails.` , async ( ) => {
322
384
// setup
323
- const runners = [ createRunnerTestData ( 'idle-1' , type , MINIMUM_TIME_RUNNING_IN_MINUTES + 1 , true , true , false ) ] ;
385
+ const runners = [ createRunnerTestData ( 'idle-1' , type , MINIMUM_TIME_RUNNING_IN_MINUTES + 1 , true , false , false ) ] ;
324
386
325
387
mockOctokit . actions . deleteSelfHostedRunnerFromOrg . mockImplementation ( ( ) => {
326
388
return { status : 500 } ;
@@ -330,7 +392,7 @@ describe('Scale down runners', () => {
330
392
} ) ;
331
393
332
394
mockGitHubRunners ( runners ) ;
333
- mockListRunners . mockResolvedValue ( runners ) ;
395
+ mockAwsRunners ( runners ) ;
334
396
335
397
// act and should resolve
336
398
await expect ( scaleDown ( ) ) . resolves . not . toThrow ( ) ;
@@ -352,7 +414,7 @@ describe('Scale down runners', () => {
352
414
} ) ;
353
415
354
416
mockGitHubRunners ( runners ) ;
355
- mockListRunners . mockResolvedValue ( runners ) ;
417
+ mockAwsRunners ( runners ) ;
356
418
357
419
// act
358
420
await expect ( scaleDown ( ) ) . resolves . not . toThrow ( ) ;
@@ -383,7 +445,7 @@ describe('Scale down runners', () => {
383
445
] ;
384
446
385
447
mockGitHubRunners ( runners ) ;
386
- mockListRunners . mockResolvedValue ( runners ) ;
448
+ mockAwsRunners ( runners ) ;
387
449
388
450
// act
389
451
await scaleDown ( ) ;
@@ -502,6 +564,12 @@ describe('Scale down runners', () => {
502
564
} ) ;
503
565
} ) ;
504
566
567
+ function mockAwsRunners ( runners : RunnerTestItem [ ] ) {
568
+ mockListRunners . mockImplementation ( async ( filter ) => {
569
+ return runners . filter ( ( r ) => ! filter ?. orphan || filter ?. orphan === r . orphan ) ;
570
+ } ) ;
571
+ }
572
+
505
573
function checkNonTerminated ( runners : RunnerTestItem [ ] ) {
506
574
const notTerminated = runners . filter ( ( r ) => ! r . shouldBeTerminated ) ;
507
575
for ( const toTerminate of notTerminated ) {
0 commit comments