From 628532b25f00126a42cbe0d6895f7025b1324e31 Mon Sep 17 00:00:00 2001 From: Ben H <133617495+bennavapbc@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:19:38 -0700 Subject: [PATCH] Add details for 'coverage period missing or year,month query incorrect' log statements (#1418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎫 Ticket - https://jira.cms.gov/browse/AB2D-6418 - https://jira.cms.gov/browse/AB2D-6425 ## 🛠 Changes Add details to log message for `coverage period missing or year,month query incorrect` error messages. ## ℹ️ Context When we receive a Slack notification of a failed job, the relevant details (e.g. coverage month and year) are not present in Splunk. This PR adds those details for debugging purposes. ![image](https://github.com/user-attachments/assets/87cfcea5-c673-4198-a65d-fb6315cb5f9b) ## 🧪 Validation Added unit tests that verified additional statements were printed to the logs ![image](https://github.com/user-attachments/assets/b7b29df6-7cf8-46e7-8128-846537ed2a99) --- .../coverage/CoverageDriverImpl.java | 14 +++++--- .../coverage/CoverageDriverUnitTest.java | 35 ++++++++++++++++--- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/worker/src/main/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverImpl.java b/worker/src/main/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverImpl.java index 78810ac47..98047fbe1 100644 --- a/worker/src/main/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverImpl.java +++ b/worker/src/main/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverImpl.java @@ -562,22 +562,28 @@ public CoveragePagingResult pageCoverage(Job job, ContractDTO contract) { } ZonedDateTime startDateTime = getStartDateTime(contract); - + // Additional details to log in the event of exception + Optional additionalDetails = Optional.empty(); try { // Check that all coverage periods necessary are present before beginning to page while (startDateTime.isBefore(now)) { + additionalDetails = Optional.of(String.format("contract='%s' month='%s', year='%s'", + contract.getContractNumber(), + startDateTime.getMonthValue(), + startDateTime.getYear())); // Will throw exception if it doesn't exist coverageService.getCoveragePeriod(mapping.map(contract), startDateTime.getMonthValue(), startDateTime.getYear()); startDateTime = startDateTime.plusMonths(1); } + additionalDetails = Optional.empty(); // Make initial request which returns a result and a request starting at the next cursor CoveragePagingRequest request = new CoveragePagingRequest(PAGING_SIZE, null, mapping.map(contract), job.getCreatedAt()); - + additionalDetails = Optional.of(request.toString()); // Make request for coverage metadata return coverageService.pageCoverage(request); } catch (Exception exception) { - log.error("coverage period missing or year,month query incorrect, driver should have resolved earlier"); + log.error("coverage period missing or year,month query incorrect, driver should have resolved earlier - {}", additionalDetails.orElse("")); throw new CoverageDriverException("coverage driver failing preconditions", exception); } } @@ -632,7 +638,7 @@ public CoveragePagingResult pageCoverage(CoveragePagingRequest request) { try { return coverageService.pageCoverage(request); } catch (Exception exception) { - log.error("coverage period missing or year,month query incorrect, driver should have resolved earlier"); + log.error("coverage period missing or year,month query incorrect, driver should have resolved earlier - {}", request.toString()); throw new CoverageDriverException("coverage driver failing preconditions", exception); } } diff --git a/worker/src/test/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverUnitTest.java b/worker/src/test/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverUnitTest.java index 2e8d81264..d13c670a0 100644 --- a/worker/src/test/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverUnitTest.java +++ b/worker/src/test/java/gov/cms/ab2d/worker/processor/coverage/CoverageDriverUnitTest.java @@ -27,6 +27,7 @@ import javax.persistence.EntityNotFoundException; import gov.cms.ab2d.worker.service.coveragesnapshot.CoverageSnapshotService; +import lombok.val; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -36,6 +37,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.test.util.ReflectionTestUtils; @@ -60,7 +63,7 @@ /** * Tests for paging coverage which are much easier using mocked resources */ -@ExtendWith(MockitoExtension.class) +@ExtendWith({MockitoExtension.class, OutputCaptureExtension.class}) class CoverageDriverUnitTest { @Mock @@ -229,9 +232,30 @@ void pageRequestWhenSinceDateAfterNow() { assertNotNull(result); } + @DisplayName("Paging coverage fails when all coverage periods are present but CoverageService#pageCoverage throws exception") + @Test + void failPagingWhenCoveragePeriodsPresentButUnderlyingMethodThrowsException(CapturedOutput output) { + when(coverageService.getCoveragePeriod(any(ContractForCoverageDTO.class), anyInt(), anyInt())).thenAnswer((invocationOnMock) -> { + CoveragePeriod period = new CoveragePeriod(); + period.setContractNumber((invocationOnMock.getArgument(0).toString())); + period.setMonth(invocationOnMock.getArgument(1)); + period.setYear(invocationOnMock.getArgument(2)); + return period; + }); + + when(coverageService.pageCoverage(any())).thenThrow(RuntimeException.class); + + Job job = new Job(); + ContractDTO contract = new ContractDTO(null, "Contract-0", null, AB2D_EPOCH.toOffsetDateTime(), null, 0, 0); + when(mapping.map(any(ContractDTO.class))).thenReturn(new ContractForCoverageDTO("Contract-0", contract.getAttestedOn(), ContractForCoverageDTO.ContractType.NORMAL)); + + assertThrows(CoverageDriverException.class, () -> driver.pageCoverage(job, contract)); + assertTrue(output.getOut().contains("coverage period missing or year,month query incorrect, driver should have resolved earlier - CoveragePagingRequest(jobStartTime=null, contract=ContractForCoverageDTO(contractNumber=Contract-0, attestedOn=2020-01-01T00:00-05:00, contractType=NORMAL), pageSize=10000, cursor=Optional.empty)")); + } + @DisplayName("Paging coverage fails when coverage periods are missing") @Test - void failPagingWhenCoveragePeriodMissing() { + void failPagingWhenCoveragePeriodMissing(CapturedOutput output) { when(coverageService.getCoveragePeriod(any(), anyInt(), anyInt())).thenThrow(new EntityNotFoundException()); @@ -240,6 +264,7 @@ void failPagingWhenCoveragePeriodMissing() { CoverageDriverException startDateInFuture = assertThrows(CoverageDriverException.class, () -> driver.pageCoverage(job, contract)); assertEquals(EntityNotFoundException.class, startDateInFuture.getCause().getClass()); + assertTrue(output.getOut().contains("coverage period missing or year,month query incorrect, driver should have resolved earlier - contract='null' month='1', year='2020'")); } @DisplayName("Paging coverage periods") @@ -354,7 +379,7 @@ void failureToLockCoverageAvailableFailsQuietly() { @DisplayName("When paging coverage fails throw coverage driver exception") @Test - void failureToPageCausesExceptions() { + void failureToPageCausesExceptions(CapturedOutput output) { when(coverageService.pageCoverage(any())).thenThrow(RuntimeException.class); CoverageDriver driver = new CoverageDriverImpl(null, null, coverageService, null, null, null,null, snapshotService); @@ -362,8 +387,10 @@ void failureToPageCausesExceptions() { ContractForCoverageDTO contract = new ContractForCoverageDTO(); contract.setContractNumber("contractNum"); - CoverageDriverException exception = assertThrows(CoverageDriverException.class, () -> driver.pageCoverage(new CoveragePagingRequest( 1000, null, contract, OffsetDateTime.now()))); + val coveragePagingRequest = new CoveragePagingRequest( 1000, null, contract, AB2D_EPOCH.toOffsetDateTime()); + CoverageDriverException exception = assertThrows(CoverageDriverException.class, () -> driver.pageCoverage(coveragePagingRequest)); assertTrue(exception.getMessage().contains("coverage driver failing preconditions")); + assertTrue(output.getOut().contains("coverage period missing or year,month query incorrect, driver should have resolved earlier - CoveragePagingRequest(jobStartTime=2020-01-01T00:00-05:00, contract=ContractForCoverageDTO(contractNumber=contractNum, attestedOn=null, contractType=null), pageSize=1000, cursor=Optional.empty")); } @DisplayName("When loading a mapping job exit early if conditions not met")