FetchAmiJob implements FullstopJob { @Scheduled(fixedRate = 60_000 * 60 * 4, initialDelay = -1) public void run() { log.info("Running job {}", getClass().getSimpleName()); final List<String> regions = jobsProperties.getWhitelistedRegions(); for (final String account : allAccountIds.get()) { for (final String region : regions) { runOn(account, region); } } } @Autowired  FetchAmiJob(final ViolationSink violationSink,
                       final ClientProvider clientProvider,
                       final AccountIdSupplier allAccountIds,
                       final JobsProperties jobsProperties,
                       final ViolationService violationService,
                       final FetchTaupageYaml fetchTaupageYaml,
                       @Value("${FULLSTOP_TAUPAGE_NAME_PREFIX}") final String taupageNamePrefix,
                       @Value("${FULLSTOP_TAUPAGE_OWNERS}") final String taupageOwners,
                       final JobExceptionHandler jobExceptionHandler,
                       final TaupageExpirationTimeProvider taupageExpirationTimeProvider); @PostConstruct void init(); @Scheduled(fixedRate = 60_000 * 60 * 4, initialDelay = -1) // ((1 min * 60) * 4) = 4 hours rate, 0 min delay void run();  }
@Test public void testRunWithMultipleAccountsAndRegions() { final DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult() .withReservations(new Reservation().withInstances(instance1)); final Image image = new Image() .withImageId(IMAGE_ID) .withName("Taupage-AMI-" + LocalDate.now().format(ofPattern("yyyyMMdd")) + "-123456") .withOwnerId(ACCOUNT_1); when(mockExpirationTimeProvider.getExpirationTime(eq(REGION_1), anyString(), anyString())).thenReturn(ZonedDateTime.now().plusDays(10)); when(mockExpirationTimeProvider.getExpirationTime(eq(REGION_2), anyString(), anyString())).thenReturn(null); when(mockAccountIdSupplier.get()).thenReturn(ACCOUNTS); when(mockJobsProperties.getWhitelistedRegions()).thenReturn(REGIONS); when(mockClientProvider.getClient(eq(AmazonEC2Client.class), anyString(), any())).thenReturn(mockEC2Client); when(mockEC2Client.describeInstances(any(DescribeInstancesRequest.class))).thenReturn(describeInstancesResult); when(mockEC2Client.describeImages(any(DescribeImagesRequest.class))).thenReturn(new DescribeImagesResult().withImages(image)); job.run(); verify(mockAccountIdSupplier).get(); verify(mockJobsProperties).getWhitelistedRegions(); REGIONS.forEach(regionName -> { verify(mockExpirationTimeProvider, times(ACCOUNTS.size())).getExpirationTime(eq(regionName), eq(ACCOUNT_1), eq(IMAGE_ID)); ACCOUNTS.forEach(account -> { verify(mockClientProvider).getClient(eq(AmazonEC2Client.class), eq(account), eq(getRegion(Regions.fromName(regionName)))); verify(mockViolationService).violationExists(eq(account), eq(regionName), eq(FetchAmiJob.EVENT_ID), eq(INSTANCE_ID), eq(OUTDATED_TAUPAGE)); }); }); final int accountsTimesRegions = ACCOUNTS.size() * REGIONS.size(); final ArgumentCaptor<DescribeInstancesRequest> describeInstances = ArgumentCaptor.forClass(DescribeInstancesRequest.class); verify(mockEC2Client, times(accountsTimesRegions)).describeInstances(describeInstances.capture()); assertThat(describeInstances.getValue().getNextToken()).isNull(); final ArgumentCaptor<DescribeImagesRequest> describeImages = ArgumentCaptor.forClass(DescribeImagesRequest.class); verify(mockEC2Client, times(accountsTimesRegions)).describeImages(describeImages.capture()); assertThat(describeImages.getValue().getImageIds()).containsExactly(IMAGE_ID); }
@Test public void testFindOutdatedTaupage() { final DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult() .withReservations(new Reservation().withInstances(instance1)); final Image image = new Image() .withImageId(IMAGE_ID) .withName("Taupage-AMI-" + LocalDate.now().minusDays(70).format(ofPattern("yyyyMMdd")) + "-123456") .withOwnerId(ACCOUNT_1); when(mockExpirationTimeProvider.getExpirationTime(anyString(), anyString(), anyString())).thenReturn(ZonedDateTime.now().minusDays(1)); when(mockAccountIdSupplier.get()).thenReturn(singleton(ACCOUNT_1)); when(mockJobsProperties.getWhitelistedRegions()).thenReturn(singletonList(REGION_1)); when(mockClientProvider.getClient(eq(AmazonEC2Client.class), anyString(), any())).thenReturn(mockEC2Client); when(mockEC2Client.describeInstances(any(DescribeInstancesRequest.class))).thenReturn(describeInstancesResult); when(mockEC2Client.describeImages(any(DescribeImagesRequest.class))).thenReturn(new DescribeImagesResult().withImages(image)); job.run(); verify(mockExpirationTimeProvider).getExpirationTime(eq(REGION_1), eq(ACCOUNT_1), eq(IMAGE_ID)); verify(mockAccountIdSupplier).get(); verify(mockJobsProperties).getWhitelistedRegions(); verify(mockClientProvider).getClient(eq(AmazonEC2Client.class), eq(ACCOUNT_1), eq(getRegion(Regions.fromName(REGION_1)))); verify(mockViolationService).violationExists(eq(ACCOUNT_1), eq(REGION_1), eq(FetchAmiJob.EVENT_ID), eq(INSTANCE_ID), eq(OUTDATED_TAUPAGE)); final ArgumentCaptor<DescribeInstancesRequest> describeInstances = ArgumentCaptor.forClass(DescribeInstancesRequest.class); verify(mockEC2Client).describeInstances(describeInstances.capture()); assertThat(describeInstances.getValue().getNextToken()).isNull(); final ArgumentCaptor<DescribeImagesRequest> describeImages = ArgumentCaptor.forClass(DescribeImagesRequest.class); verify(mockEC2Client).describeImages(describeImages.capture()); assertThat(describeImages.getValue().getImageIds()).containsExactly(IMAGE_ID); verify(mockFetchTaupageYaml).getTaupageYaml(eq(INSTANCE_ID), eq(ACCOUNT_1), eq(REGION_1)); final ArgumentCaptor<Violation> violation = ArgumentCaptor.forClass(Violation.class); verify(mockViolationSink).put(violation.capture()); assertThat(violation.getValue()) .extracting( Violation::getAccountId, Violation::getRegion, Violation::getInstanceId, Violation::getViolationType) .containsExactly( ACCOUNT_1, REGION_1, INSTANCE_ID, OUTDATED_TAUPAGE); }
@Test public void testFollowPagination() { final DescribeInstancesResult result1 = new DescribeInstancesResult().withNextToken("123"); final DescribeInstancesResult result2 = new DescribeInstancesResult().withNextToken("456"); final DescribeInstancesResult result3 = new DescribeInstancesResult(); when(mockAccountIdSupplier.get()).thenReturn(singleton(ACCOUNT_1)); when(mockJobsProperties.getWhitelistedRegions()).thenReturn(singletonList(REGION_1)); when(mockClientProvider.getClient(eq(AmazonEC2Client.class), anyString(), any())).thenReturn(mockEC2Client); when(mockEC2Client.describeInstances(any(DescribeInstancesRequest.class))).thenReturn(result1, result2, result3); job.run(); verify(mockAccountIdSupplier).get(); verify(mockJobsProperties).getWhitelistedRegions(); verify(mockClientProvider).getClient(eq(AmazonEC2Client.class), eq(ACCOUNT_1), eq(getRegion(Regions.fromName(REGION_1)))); final ArgumentCaptor<DescribeInstancesRequest> describeInstances = ArgumentCaptor.forClass(DescribeInstancesRequest.class); verify(mockEC2Client, times(3)).describeInstances(describeInstances.capture()); assertThat(describeInstances.getAllValues()).extracting(DescribeInstancesRequest::getNextToken).containsExactly(null, "123", "456"); }