From 8dde7b361a0ce43587c6279db902e340e6051115 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:23:15 +0000 Subject: [PATCH 1/7] chore(deps): Bump the maven group across 2 directories with 2 updates Bumps the maven group with 2 updates in the / directory: [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) and org.apache.tomcat.embed:tomcat-embed-core. Bumps the maven group with 2 updates in the /rest-api directory: [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) and org.apache.tomcat.embed:tomcat-embed-core. Updates `ch.qos.logback:logback-core` from 1.5.13 to 1.5.25 - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.13...v_1.5.25) Updates `org.apache.tomcat.embed:tomcat-embed-core` from 10.1.45 to 10.1.47 Updates `ch.qos.logback:logback-core` from 1.5.13 to 1.5.25 - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.13...v_1.5.25) Updates `org.apache.tomcat.embed:tomcat-embed-core` from 10.1.45 to 10.1.47 --- updated-dependencies: - dependency-name: ch.qos.logback:logback-core dependency-version: 1.5.25 dependency-type: direct:production dependency-group: maven - dependency-name: org.apache.tomcat.embed:tomcat-embed-core dependency-version: 10.1.47 dependency-type: direct:production dependency-group: maven - dependency-name: ch.qos.logback:logback-core dependency-version: 1.5.25 dependency-type: direct:production dependency-group: maven - dependency-name: org.apache.tomcat.embed:tomcat-embed-core dependency-version: 10.1.47 dependency-type: direct:production dependency-group: maven ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- rest-api/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b7f2a8651..043da8d1c 100644 --- a/pom.xml +++ b/pom.xml @@ -475,7 +475,7 @@ ch.qos.logback logback-core - 1.5.13 + 1.5.25 diff --git a/rest-api/pom.xml b/rest-api/pom.xml index c4449322b..ced291d11 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -226,7 +226,7 @@ org.apache.tomcat.embed tomcat-embed-core - 10.1.45 + 10.1.47 org.apache.tomcat.embed From 3b32ed11385d810014f35d19dfa86be431d1a4a1 Mon Sep 17 00:00:00 2001 From: ckawell-sb Date: Wed, 18 Feb 2026 12:49:54 -0600 Subject: [PATCH 2/7] feat: QPPA-0000 update boot dependencies --- .github/workflows/publish-release.yml | 64 ++++++++++++++++----------- rest-api/pom.xml | 8 ++-- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 70475584d..2f31f6e7c 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -37,31 +37,45 @@ jobs: echo "Published release ${{ steps.get_release.outputs.tag_name }} as latest" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + backfill: + name: Backfill master to develop branch + runs-on: ubuntu-latest + steps: + - name: Check params + run: | + echo "head.ref = ${{github.event.pull_request.head.ref}}" + echo "base.ref = ${{github.event.pull_request.base.ref}}" + + - uses: actions/checkout@v4 + with: + ref: master + token: ${{ secrets.ACTIONS_NICHOLAS_PAT }} - - name: Create backfill PR to develop + - name: Create backfill branch + run: git checkout -b backfill/master; + + # In order to make a commit, we need to initialize a user. + - name: Initialize mandatory git config run: | - # Check if a PR already exists - EXISTING_PR=$(gh pr list --base develop --head master --json number --jq '.[0].number' || echo "") - - if [ -n "$EXISTING_PR" ]; then - echo "PR #${EXISTING_PR} already exists for master -> develop" - exit 0 - fi - - # Create the backfill PR - gh pr create \ - --base develop \ - --head master \ - --title "Backfill master into develop" \ - --body "This PR backfills changes from master into develop after production deployment. - - ## Changes - This includes all changes that were merged to master. - - ## Notes - - Review for any conflicts - - Merge after verifying all changes are appropriate for develop branch" - - echo "Created backfill PR from master to develop" + git config user.name "GitHub actions" + git config user.email noreply@github.com + + - name: Push backfill branch env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.ACTIONS_NICHOLAS_PAT }} + run: | + git push origin backfill/master + + - name: Create backfill pull request to develop branch + uses: thomaseizinger/create-pull-request@1.4.0 + with: + github_token: ${{ secrets.ACTIONS_NICHOLAS_PAT }} + head: backfill/master + base: develop + draft: true + title: Backfill ${{ github.event.pull_request.base.ref }} branch to develop branch + body: | + Hi @${{ github.actor }}! + + This PR was created in response to a trigger of the release workflow here: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}. + Following a release, this is a backfill from the main branch to the develop branch. diff --git a/rest-api/pom.xml b/rest-api/pom.xml index ced291d11..095f263bd 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -195,7 +195,7 @@ org.springframework.boot spring-boot-dependencies - 3.4.11 + 3.5.10 pom import @@ -226,17 +226,17 @@ org.apache.tomcat.embed tomcat-embed-core - 10.1.47 + 10.1.52 org.apache.tomcat.embed tomcat-embed-el - 10.1.45 + 10.1.52 org.apache.tomcat.embed tomcat-embed-websocket - 10.1.45 + 10.1.52 From c1bc9f42c1d83facbb2c76c29497570ba8b4f272 Mon Sep 17 00:00:00 2001 From: Chetan Munegowda Date: Thu, 19 Feb 2026 09:53:32 -0500 Subject: [PATCH 3/7] QPPA-11385: downgrade datadog logging --- pom.xml | 2 +- .../GlobalExceptionHandler.java} | 25 +++-- .../GlobalExceptionHandlerTest.java} | 92 ++++++++++--------- 3 files changed, 60 insertions(+), 59 deletions(-) rename rest-api/src/main/java/gov/cms/qpp/conversion/api/{controllers/v1/ExceptionHandlerControllerV1.java => exceptions/GlobalExceptionHandler.java} (89%) rename rest-api/src/test/java/gov/cms/qpp/conversion/api/{controllers/v1/ExceptionHandlerControllerV1Test.java => exceptions/GlobalExceptionHandlerTest.java} (80%) diff --git a/pom.xml b/pom.xml index a4f39f83e..b6a7f50a5 100644 --- a/pom.xml +++ b/pom.xml @@ -469,7 +469,7 @@ ch.qos.logback logback-classic - 1.5.13 + 1.5.25 diff --git a/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1.java b/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java similarity index 89% rename from rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1.java rename to rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java index 314d3decd..1f05376ab 100644 --- a/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1.java +++ b/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java @@ -1,15 +1,10 @@ -package gov.cms.qpp.conversion.api.controllers.v1; +package gov.cms.qpp.conversion.api.exceptions; -import gov.cms.qpp.conversion.api.exceptions.InvalidFileTypeException; -import gov.cms.qpp.conversion.api.exceptions.InvalidPurposeException; -import gov.cms.qpp.conversion.api.exceptions.NoFileInDatabaseException; +import com.amazonaws.AmazonServiceException; import gov.cms.qpp.conversion.api.services.AuditService; import gov.cms.qpp.conversion.model.error.AllErrors; import gov.cms.qpp.conversion.model.error.QppValidationException; import gov.cms.qpp.conversion.model.error.TransformException; - -import com.amazonaws.AmazonServiceException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; @@ -22,14 +17,12 @@ import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import gov.cms.qpp.conversion.api.exceptions.BadZipException; - /** * Modify the controller to send back different responses for exceptions */ @ControllerAdvice -public class ExceptionHandlerControllerV1 extends ResponseEntityExceptionHandler { - private static final Logger API_LOG = LoggerFactory.getLogger(ExceptionHandlerControllerV1.class); +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + private static final Logger API_LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class); private AuditService auditService; @@ -38,7 +31,7 @@ public class ExceptionHandlerControllerV1 extends ResponseEntityExceptionHandler * * @param auditService {@link AuditService} facilitates persistence of conversion results */ - public ExceptionHandlerControllerV1(final AuditService auditService) { + public GlobalExceptionHandler(final AuditService auditService) { this.auditService = auditService; } @@ -52,7 +45,9 @@ public ExceptionHandlerControllerV1(final AuditService auditService) { @ExceptionHandler(TransformException.class) @ResponseBody ResponseEntity handleTransformException(TransformException exception) { - API_LOG.error("Transform exception occurred", exception); + API_LOG.info("Transform failed validation (422): {}", exception.getMessage()); + API_LOG.debug("TransformException details", exception); + auditService.failConversion(exception.getConversionReport()); return cope(exception); } @@ -67,7 +62,9 @@ ResponseEntity handleTransformException(TransformException exception) @ExceptionHandler(QppValidationException.class) @ResponseBody ResponseEntity handleQppValidationException(QppValidationException exception) { - API_LOG.error("Validation exception occurred", exception); + API_LOG.info("Submission validation failed (422): {}", exception.getMessage()); + API_LOG.debug("QppValidationException details", exception); + auditService.failValidation(exception.getConversionReport()); return cope(exception); } diff --git a/rest-api/src/test/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1Test.java b/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java similarity index 80% rename from rest-api/src/test/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1Test.java rename to rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java index d96b552f1..1cd94847a 100644 --- a/rest-api/src/test/java/gov/cms/qpp/conversion/api/controllers/v1/ExceptionHandlerControllerV1Test.java +++ b/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java @@ -1,13 +1,26 @@ -package gov.cms.qpp.conversion.api.controllers.v1; +package gov.cms.qpp.conversion.api.exceptions; import com.amazonaws.AmazonServiceException; import com.google.common.truth.Truth; +import gov.cms.qpp.conversion.ConversionReport; +import gov.cms.qpp.conversion.Converter; +import gov.cms.qpp.conversion.PathSource; +import gov.cms.qpp.conversion.api.controllers.v1.QrdaControllerV1; +import gov.cms.qpp.conversion.api.helper.AdvancedApmHelper; +import gov.cms.qpp.conversion.api.model.Constants; +import gov.cms.qpp.conversion.api.services.AuditService; +import gov.cms.qpp.conversion.api.services.QrdaService; +import gov.cms.qpp.conversion.api.services.ValidationService; +import gov.cms.qpp.conversion.model.error.AllErrors; +import gov.cms.qpp.conversion.model.error.QppValidationException; +import gov.cms.qpp.conversion.model.error.TransformException; +import gov.cms.qpp.test.MockitoExtension; +import gov.cms.qpp.test.logging.LoggerContract; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -20,20 +33,6 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import gov.cms.qpp.conversion.ConversionReport; -import gov.cms.qpp.conversion.Converter; -import gov.cms.qpp.conversion.PathSource; -import gov.cms.qpp.conversion.api.exceptions.InvalidFileTypeException; -import gov.cms.qpp.conversion.api.exceptions.InvalidPurposeException; -import gov.cms.qpp.conversion.api.exceptions.NoFileInDatabaseException; -import gov.cms.qpp.conversion.api.helper.AdvancedApmHelper; -import gov.cms.qpp.conversion.api.services.AuditService; -import gov.cms.qpp.conversion.model.error.AllErrors; -import gov.cms.qpp.conversion.model.error.QppValidationException; -import gov.cms.qpp.conversion.model.error.TransformException; -import gov.cms.qpp.test.MockitoExtension; -import gov.cms.qpp.test.logging.LoggerContract; - import java.nio.file.Path; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -41,24 +40,23 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) -class ExceptionHandlerControllerV1Test implements LoggerContract { +class GlobalExceptionHandlerTest implements LoggerContract { private static ConversionReport report; - private static AllErrors allErrors = new AllErrors(); + private static final AllErrors allErrors = new AllErrors(); @InjectMocks - private ExceptionHandlerControllerV1 objectUnderTest; + private GlobalExceptionHandler objectUnderTest; @Mock private AuditService auditService; @BeforeAll static void setup() { + // NOTE: If this path is flaky in CI, move the file to src/test/resources and load via classpath. Path path = Path.of("../qrda-files/valid-QRDA-III-latest.xml"); report = new Converter(new PathSource(path)).getReport(); report.setReportDetails(allErrors); @@ -68,6 +66,8 @@ static void setup() { void before() { when(auditService.failConversion(any(ConversionReport.class))) .thenReturn(CompletableFuture.completedFuture(null)); + when(auditService.failValidation(any(ConversionReport.class))) + .thenReturn(CompletableFuture.completedFuture(null)); } @Test @@ -99,13 +99,14 @@ void testTransformExceptionBody() { new TransformException("test transform exception", new NullPointerException(), report); ResponseEntity responseEntity = objectUnderTest.handleTransformException(exception); + assertThat(responseEntity.getBody()).isEqualTo(allErrors); } @Test void testQppValidationExceptionStatusCode() { QppValidationException exception = - new QppValidationException("test transform exception", new NullPointerException(), report); + new QppValidationException("test validation exception", new NullPointerException(), report); ResponseEntity responseEntity = objectUnderTest.handleQppValidationException(exception); @@ -117,7 +118,7 @@ void testQppValidationExceptionStatusCode() { @Test void testQppValidationExceptionHeaderContentType() { QppValidationException exception = - new QppValidationException("test transform exception", new NullPointerException(), report); + new QppValidationException("test validation exception", new NullPointerException(), report); ResponseEntity responseEntity = objectUnderTest.handleQppValidationException(exception); @@ -128,9 +129,10 @@ void testQppValidationExceptionHeaderContentType() { @Test void testQppValidationExceptionBody() { QppValidationException exception = - new QppValidationException("test transform exception", new NullPointerException(), report); + new QppValidationException("test validation exception", new NullPointerException(), report); ResponseEntity responseEntity = objectUnderTest.handleQppValidationException(exception); + assertThat(responseEntity.getBody()).isEqualTo(allErrors); } @@ -141,7 +143,7 @@ void testFileNotFoundExceptionStatusCode() { ResponseEntity responseEntity = objectUnderTest.handleFileNotFoundException(exception); - assertWithMessage("The response entity's status code must be 422.") + assertWithMessage("The response entity's status code must be 404.") .that(responseEntity.getStatusCode()) .isEqualTo(HttpStatus.NOT_FOUND); } @@ -163,6 +165,7 @@ void testFileNotFoundExceptionBody() { new NoFileInDatabaseException(AdvancedApmHelper.FILE_NOT_FOUND); ResponseEntity responseEntity = objectUnderTest.handleFileNotFoundException(exception); + assertThat(responseEntity.getBody()).isEqualTo(AdvancedApmHelper.FILE_NOT_FOUND); } @@ -173,7 +176,7 @@ void testInvalidFileTypeExceptionStatusCode() { ResponseEntity responseEntity = objectUnderTest.handleInvalidFileTypeException(exception); - assertWithMessage("The response entity's status code must be 422.") + assertWithMessage("The response entity's status code must be 404.") .that(responseEntity.getStatusCode()) .isEqualTo(HttpStatus.NOT_FOUND); } @@ -195,6 +198,7 @@ void testInvalidFileTypeExceptionBody() { new InvalidFileTypeException(AdvancedApmHelper.FILE_NOT_FOUND); ResponseEntity responseEntity = objectUnderTest.handleInvalidFileTypeException(exception); + assertThat(responseEntity.getBody()).isEqualTo(AdvancedApmHelper.FILE_NOT_FOUND); } @@ -208,15 +212,6 @@ void testHandleAmazonExceptionStatusCode() { Truth.assertThat(response.getStatusCodeValue()).isEqualTo(404); } -// @Test -// void testHandleAmazonExceptionResponseBody() { -// AmazonServiceException exception = new AmazonServiceException("some message"); -// -// ResponseEntity response = objectUnderTest.handleAmazonException(exception); -// -// Truth.assertThat(response.getBody()).contains("some message"); -// } - @Test void testHandleInvalidPurposeExceptionExceptionResponseBody() { InvalidPurposeException exception = new InvalidPurposeException("some message"); @@ -228,23 +223,32 @@ void testHandleInvalidPurposeExceptionExceptionResponseBody() { @Test void testHandleInvalidPurposeExceptionResponseBodyDoesInterception() throws Exception { - QrdaControllerV1 mock = Mockito.mock(QrdaControllerV1.class); - MockMvc mvc = MockMvcBuilders.standaloneSetup(mock) - .setControllerAdvice(new ExceptionHandlerControllerV1(auditService)) + // Use a real controller instance (with mocked deps) so Spring MVC can route to it reliably. + QrdaService qrdaService = Mockito.mock(QrdaService.class); + ValidationService validationService = Mockito.mock(ValidationService.class); + + QrdaControllerV1 controller = new QrdaControllerV1(qrdaService, validationService, auditService); + + MockMvc mvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(new GlobalExceptionHandler(auditService)) .build(); - when(mock.uploadQrdaFile(ArgumentMatchers.any(), ArgumentMatchers.anyString())).thenCallRealMethod(); String purpose = "this is an invalid purpose because it's too long" + UUID.randomUUID(); + RequestBuilder builder = MockMvcRequestBuilders.multipart("/") - .file("file", ArrayUtils.EMPTY_BYTE_ARRAY) - .header("Purpose", purpose); + .file("file", ArrayUtils.EMPTY_BYTE_ARRAY) + .header("Purpose", purpose) + .header("Accept", Constants.V1_API_ACCEPT); + MvcResult result = mvc.perform(builder).andReturn(); - Truth.assertThat(result.getResponse().getContentAsString()).isEqualTo("Given Purpose (header) is too large. Max length is " - + "25, yours was " + purpose.length()); + + Truth.assertThat(result.getResponse().getStatus()).isEqualTo(400); + Truth.assertThat(result.getResponse().getContentAsString()) + .isEqualTo("Given Purpose (header) is too large. Max length is 25, yours was " + purpose.length()); } @Override public Class getLoggerType() { - return ExceptionHandlerControllerV1.class; + return GlobalExceptionHandler.class; } } From 46f3676a05ee8bc76042f41dc40931c9f1f981a8 Mon Sep 17 00:00:00 2001 From: Chetan Munegowda Date: Thu, 19 Feb 2026 10:27:28 -0500 Subject: [PATCH 4/7] QPPA-11386: normalize 404 datadog loggin issue --- .../exceptions/GlobalExceptionHandler.java | 22 ++++++++++++++ .../GlobalExceptionHandlerTest.java | 30 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java b/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java index 1f05376ab..c3099a397 100644 --- a/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java +++ b/rest-api/src/main/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandler.java @@ -10,12 +10,15 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import org.springframework.web.servlet.resource.NoResourceFoundException; /** * Modify the controller to send back different responses for exceptions @@ -69,6 +72,25 @@ ResponseEntity handleQppValidationException(QppValidationException ex return cope(exception); } + /** + * Handles {@link NoResourceFoundException} for requests to non-existent paths/resources. + * Returns a clean 404 and logs at DEBUG/TRACE to avoid ERROR-level noise. + */ + @Override + protected ResponseEntity handleNoResourceFoundException( + NoResourceFoundException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + + API_LOG.debug("No resource found ({}): {}", status.value(), ex.getMessage()); + API_LOG.trace("NoResourceFoundException details", ex); + + return ResponseEntity.status(status) + .contentType(MediaType.TEXT_PLAIN) + .body("Not found"); + } + /** * "Catch" the {@link NoFileInDatabaseException}. * Return the {@link AllErrors} with an HTTP status 404. diff --git a/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java b/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java index 1cd94847a..295ff4242 100644 --- a/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java +++ b/rest-api/src/test/java/gov/cms/qpp/conversion/api/exceptions/GlobalExceptionHandlerTest.java @@ -27,11 +27,15 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.resource.NoResourceFoundException; import java.nio.file.Path; import java.util.UUID; @@ -247,6 +251,32 @@ void testHandleInvalidPurposeExceptionResponseBodyDoesInterception() throws Exce .isEqualTo("Given Purpose (header) is too large. Max length is 25, yours was " + purpose.length()); } + @Test + void testHandleNoResourceFoundExceptionReturnsPlain404() throws Exception { + NoResourceFoundException ex; + try { + ex = NoResourceFoundException.class + .getConstructor(HttpMethod.class, String.class) + .newInstance(HttpMethod.GET, "/test"); + } catch (NoSuchMethodException ignore) { + ex = NoResourceFoundException.class + .getConstructor(HttpMethod.class, String.class, String.class) + .newInstance(HttpMethod.GET, "/test", "/test"); + } + + ResponseEntity response = objectUnderTest.handleNoResourceFoundException( + ex, + new HttpHeaders(), + HttpStatus.NOT_FOUND, + Mockito.mock(WebRequest.class) + ); + + Truth.assertThat(response.getStatusCodeValue()).isEqualTo(404); + Truth.assertThat(response.getHeaders().getContentType()) + .isEquivalentAccordingToCompareTo(MediaType.TEXT_PLAIN); + Truth.assertThat(response.getBody()).isEqualTo("Not found"); + } + @Override public Class getLoggerType() { return GlobalExceptionHandler.class; From f8d63ab67330d190a599244d67e1e55c1408141a Mon Sep 17 00:00:00 2001 From: ckawell-sb Date: Mon, 23 Feb 2026 09:52:58 -0600 Subject: [PATCH 5/7] revert: QPPA-0000 revert spring boot dep upgrade --- rest-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-api/pom.xml b/rest-api/pom.xml index c3ffd77db..626c4f1f0 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -195,7 +195,7 @@ org.springframework.boot spring-boot-dependencies - 3.5.10 + 3.4.11 pom import From 639695798193f53a195c42190b7b12f2bb39acd8 Mon Sep 17 00:00:00 2001 From: GitHub actions Date: Fri, 27 Feb 2026 18:15:24 +0000 Subject: [PATCH 6/7] Prepare release vv2026.02.27.01 --- acceptance-tests/pom.xml | 2 +- commandline/pom.xml | 2 +- commons/pom.xml | 2 +- converter/pom.xml | 4 ++-- generate-race-cpcplus/pom.xml | 2 +- generate/pom.xml | 2 +- pom.xml | 2 +- qrda3-update-measures/pom.xml | 2 +- rest-api/pom.xml | 2 +- test-commons/pom.xml | 2 +- test-coverage/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/acceptance-tests/pom.xml b/acceptance-tests/pom.xml index 681cb59fd..a225f096f 100644 --- a/acceptance-tests/pom.xml +++ b/acceptance-tests/pom.xml @@ -3,7 +3,7 @@ 4.0.0 acceptance-tests gov.cms.qpp.conversion - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE conversion-tests jar diff --git a/commandline/pom.xml b/commandline/pom.xml index 8da3eba94..518f45fa9 100644 --- a/commandline/pom.xml +++ b/commandline/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml diff --git a/commons/pom.xml b/commons/pom.xml index 11fdf3d7d..6d861dec3 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml diff --git a/converter/pom.xml b/converter/pom.xml index 5854a098d..4d151f654 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml @@ -185,7 +185,7 @@ gov.cms.qpp.conversion commons - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE compile diff --git a/generate-race-cpcplus/pom.xml b/generate-race-cpcplus/pom.xml index 7f2a135e2..66362187a 100644 --- a/generate-race-cpcplus/pom.xml +++ b/generate-race-cpcplus/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion generateRaceCpcPlus - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE generate-race-cpcplus jar diff --git a/generate/pom.xml b/generate/pom.xml index ebca4f022..7a9473a7a 100644 --- a/generate/pom.xml +++ b/generate/pom.xml @@ -5,7 +5,7 @@ qpp-conversion-tool-parent gov.cms.qpp.conversion - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index b6a7f50a5..92806e9d9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent pom - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE QPP Conversion Tool diff --git a/qrda3-update-measures/pom.xml b/qrda3-update-measures/pom.xml index 374c4795f..244b4ea72 100644 --- a/qrda3-update-measures/pom.xml +++ b/qrda3-update-measures/pom.xml @@ -4,7 +4,7 @@ gov.cms.qpp.conversion qpp-update-measures - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE qrda3-update-measures jar diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 626c4f1f0..1f25bf657 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -19,7 +19,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml diff --git a/test-commons/pom.xml b/test-commons/pom.xml index 58463b598..c6b1c8962 100644 --- a/test-commons/pom.xml +++ b/test-commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index dcaee6ac6..5ffa50a9a 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.02.17.01-RELEASE + v2026.02.27.01-RELEASE ../pom.xml From 0157f74f3d509d610affb08e33a9dba3c5d5d28b Mon Sep 17 00:00:00 2001 From: John Manack Date: Fri, 27 Feb 2026 13:20:42 -0500 Subject: [PATCH 7/7] chore: removes typo in release version --- acceptance-tests/pom.xml | 2 +- commandline/pom.xml | 2 +- commons/pom.xml | 2 +- converter/pom.xml | 4 ++-- generate-race-cpcplus/pom.xml | 2 +- generate/pom.xml | 2 +- pom.xml | 2 +- qrda3-update-measures/pom.xml | 2 +- rest-api/pom.xml | 2 +- test-commons/pom.xml | 2 +- test-coverage/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/acceptance-tests/pom.xml b/acceptance-tests/pom.xml index a225f096f..13edbb302 100644 --- a/acceptance-tests/pom.xml +++ b/acceptance-tests/pom.xml @@ -3,7 +3,7 @@ 4.0.0 acceptance-tests gov.cms.qpp.conversion - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE conversion-tests jar diff --git a/commandline/pom.xml b/commandline/pom.xml index 518f45fa9..fa95be16d 100644 --- a/commandline/pom.xml +++ b/commandline/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml diff --git a/commons/pom.xml b/commons/pom.xml index 6d861dec3..61b1d3e20 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml diff --git a/converter/pom.xml b/converter/pom.xml index 4d151f654..a4b53f0a9 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml @@ -185,7 +185,7 @@ gov.cms.qpp.conversion commons - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE compile diff --git a/generate-race-cpcplus/pom.xml b/generate-race-cpcplus/pom.xml index 66362187a..54be01e9f 100644 --- a/generate-race-cpcplus/pom.xml +++ b/generate-race-cpcplus/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion generateRaceCpcPlus - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE generate-race-cpcplus jar diff --git a/generate/pom.xml b/generate/pom.xml index 7a9473a7a..b360c7c10 100644 --- a/generate/pom.xml +++ b/generate/pom.xml @@ -5,7 +5,7 @@ qpp-conversion-tool-parent gov.cms.qpp.conversion - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 92806e9d9..2639017c8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent pom - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE QPP Conversion Tool diff --git a/qrda3-update-measures/pom.xml b/qrda3-update-measures/pom.xml index 244b4ea72..2bc2e94ec 100644 --- a/qrda3-update-measures/pom.xml +++ b/qrda3-update-measures/pom.xml @@ -4,7 +4,7 @@ gov.cms.qpp.conversion qpp-update-measures - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE qrda3-update-measures jar diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 1f25bf657..a03798f1a 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -19,7 +19,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml diff --git a/test-commons/pom.xml b/test-commons/pom.xml index c6b1c8962..c1acef3f5 100644 --- a/test-commons/pom.xml +++ b/test-commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index 5ffa50a9a..32a3949d2 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - v2026.02.27.01-RELEASE + 2026.02.27.01-RELEASE ../pom.xml