diff --git a/buildSrc/src/main/groovy/bio.terra.landingzone.java-common-conventions.gradle b/buildSrc/src/main/groovy/bio.terra.landingzone.java-common-conventions.gradle index df90f1223..844dc6fe3 100644 --- a/buildSrc/src/main/groovy/bio.terra.landingzone.java-common-conventions.gradle +++ b/buildSrc/src/main/groovy/bio.terra.landingzone.java-common-conventions.gradle @@ -42,23 +42,18 @@ dependencies { compileOnly "com.google.code.findbugs:annotations:3.0.1" implementation 'org.slf4j:slf4j-api' implementation 'io.swagger.core.v3:swagger-annotations:2.1.12' + implementation 'io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.2.0' + // Needed for @VisibleForTesting and more: + // TCL 1.0.10 tries to expose this as an api dependency, but does so without specifying an explicit version + // (it derives the version from com.google.cloud:libraries-bom, which it doesn't expose to consumers). + // If TCL instead exposed the BOM, or exposed guava with a specified version, this could be removed. + implementation 'com.google.guava:guava:33.1.0-jre' swaggerCodegen 'io.swagger.codegen.v3:swagger-codegen-cli:3.0.47' testImplementation 'ch.qos.logback:logback-classic' testImplementation 'org.hamcrest:hamcrest:2.2' - var openTelemetryVersion = '1.32.0' - implementation "io.opentelemetry:opentelemetry-api:${openTelemetryVersion}" - implementation "io.opentelemetry:opentelemetry-sdk:${openTelemetryVersion}" - implementation "io.opentelemetry:opentelemetry-sdk-metrics:${openTelemetryVersion}" - implementation "io.opentelemetry:opentelemetry-exporter-logging:${openTelemetryVersion}" - implementation "io.opentelemetry.semconv:opentelemetry-semconv:1.21.0-alpha" - implementation "io.opentelemetry.instrumentation:opentelemetry-spring-webmvc-6.0:${openTelemetryVersion}-alpha" - implementation "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:${openTelemetryVersion}" - implementation "io.opentelemetry.instrumentation:opentelemetry-spring-boot:${openTelemetryVersion}-alpha" - implementation "com.google.cloud.opentelemetry:exporter-trace:0.25.2" - - implementation ('bio.terra:terra-common-lib:0.1.6-SNAPSHOT'){ + implementation ('bio.terra:terra-common-lib:1.0.10-SNAPSHOT') { exclude group: "org.broadinstitute.dsde.workbench", module: "sam-client_2.13" } } diff --git a/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-app-conventions.gradle b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-app-conventions.gradle index a5454135a..e26ddbeac 100644 --- a/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-app-conventions.gradle +++ b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-app-conventions.gradle @@ -1,9 +1,4 @@ plugins { - id 'bio.terra.landingzone.java-common-conventions' - id 'io.spring.dependency-management' - id 'org.springframework.boot' + id 'bio.terra.landingzone.java-spring-conventions' id 'application' } - -// Spring Boot 3.1.2 pulls in postgresql 42.6.0, vulnerable to CVE-2024-1597 -ext['postgresql.version'] = '42.7.2' diff --git a/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-conventions.gradle b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-conventions.gradle new file mode 100644 index 000000000..7229913bc --- /dev/null +++ b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-conventions.gradle @@ -0,0 +1,11 @@ +plugins { + id 'bio.terra.landingzone.java-common-conventions' + id 'io.spring.dependency-management' + id 'org.springframework.boot' +} + +// Spring Boot 3.1.2 pulls in postgresql 42.6.0, vulnerable to CVE-2024-1597 +ext['postgresql.version'] = '42.7.2' +// Spring Boot 3.1.2 pulls in opentelemetry-bom 1.25.0. +// It must have version >= 1.34.1 for compatibility with terra-common-lib 1.0.9: +ext['opentelemetry.version'] = '1.36.0' diff --git a/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-library-conventions.gradle b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-library-conventions.gradle index 63c597802..e63f646b5 100644 --- a/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-library-conventions.gradle +++ b/buildSrc/src/main/groovy/bio.terra.landingzone.java-spring-library-conventions.gradle @@ -1,7 +1,5 @@ plugins { - id 'bio.terra.landingzone.java-common-conventions' - id 'io.spring.dependency-management' - id 'org.springframework.boot' + id 'bio.terra.landingzone.java-spring-conventions' id 'java-library' id 'maven-publish' } diff --git a/library/build.gradle b/library/build.gradle index 2c43a8e3b..4d1ba8cbd 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -11,7 +11,6 @@ plugins { apply from: 'publishing.gradle' dependencies { - implementation 'bio.terra:terra-common-lib' implementation 'org.apache.commons:commons-dbcp2' implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web' @@ -57,7 +56,7 @@ dependencies { testImplementation 'org.mockito:mockito-inline:5.2.0' testImplementation 'org.awaitility:awaitility:4.2.0' - testImplementation('org.springframework.boot:spring-boot-starter-test:3.1.2') { + testImplementation('org.springframework.boot:spring-boot-starter-test') { // Fixes warning about multiple occurrences of JSONObject on the classpath exclude group: 'com.vaadin.external.google', module: 'android-json' } diff --git a/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobBuilder.java b/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobBuilder.java index fa4f575a7..7f55f9223 100644 --- a/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobBuilder.java +++ b/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobBuilder.java @@ -8,7 +8,6 @@ import bio.terra.landingzone.job.exception.InvalidJobParameterException; import bio.terra.landingzone.job.model.OperationType; import bio.terra.landingzone.service.landingzone.azure.model.LandingZoneRequest; -import bio.terra.landingzone.stairway.common.utils.LandingZoneMdcHook; import bio.terra.landingzone.stairway.flight.LandingZoneFlightMapKeys; import bio.terra.stairway.Flight; import bio.terra.stairway.FlightMap; @@ -20,7 +19,6 @@ public class LandingZoneJobBuilder { private final LandingZoneJobService jobService; private final StairwayComponent stairwayComponent; - private final LandingZoneMdcHook mdcHook; private final FlightMap jobParameterMap; private final OpenTelemetry openTelemetry; private Class flightClass; @@ -33,11 +31,9 @@ public class LandingZoneJobBuilder { public LandingZoneJobBuilder( LandingZoneJobService jobService, StairwayComponent stairwayComponent, - LandingZoneMdcHook mdcHook, OpenTelemetry openTelemetry) { this.jobService = jobService; this.stairwayComponent = stairwayComponent; - this.mdcHook = mdcHook; this.openTelemetry = openTelemetry; this.jobParameterMap = new FlightMap(); } @@ -126,8 +122,7 @@ private void populateInputParams() { jobId = stairwayComponent.get().createFlightId(); } - // Always add the MDC logging and tracing span parameters for the mdc hook - addParameter(LandingZoneMdcHook.MDC_FLIGHT_MAP_KEY, mdcHook.getSerializedCurrentContext()); + // Always add the tracing span parameters addParameter( MonitoringHook.SUBMISSION_SPAN_CONTEXT_MAP_KEY, MonitoringHook.serializeCurrentTracingContext(openTelemetry)); diff --git a/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobService.java b/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobService.java index 22af2bd62..2d6cccbe8 100644 --- a/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobService.java +++ b/library/src/main/java/bio/terra/landingzone/job/LandingZoneJobService.java @@ -27,7 +27,7 @@ import bio.terra.landingzone.service.iam.SamRethrow; import bio.terra.landingzone.service.landingzone.azure.model.DeletedLandingZone; import bio.terra.landingzone.service.landingzone.azure.model.LandingZoneRequest; -import bio.terra.landingzone.stairway.common.utils.LandingZoneMdcHook; +import bio.terra.landingzone.stairway.common.utils.StairwayLoggingHook; import bio.terra.landingzone.stairway.flight.LandingZoneFlightMapKeys; import bio.terra.stairway.Flight; import bio.terra.stairway.FlightDebugInfo; @@ -68,7 +68,7 @@ public class LandingZoneJobService { private final LandingZoneIngressConfiguration ingressConfig; private final LandingZoneStairwayDatabaseConfiguration stairwayDatabaseConfiguration; private final ScheduledExecutorService executor; - private final LandingZoneMdcHook mdcHook; + private final StairwayLoggingHook stairwayLoggingHook; private final StairwayComponent stairwayComponent; private final LandingZoneFlightBeanBag flightBeanBag; private final ObjectMapper objectMapper; @@ -81,7 +81,7 @@ public LandingZoneJobService( LandingZoneJobConfiguration jobConfig, LandingZoneIngressConfiguration ingressConfig, LandingZoneStairwayDatabaseConfiguration stairwayDatabaseConfiguration, - LandingZoneMdcHook mdcHook, + StairwayLoggingHook stairwayLoggingHook, @Qualifier("landingZoneStairwayComponent") StairwayComponent stairwayComponent, LandingZoneFlightBeanBag flightBeanBag, ObjectMapper objectMapper, @@ -91,7 +91,7 @@ public LandingZoneJobService( this.ingressConfig = ingressConfig; this.stairwayDatabaseConfiguration = stairwayDatabaseConfiguration; this.executor = Executors.newScheduledThreadPool(jobConfig.getMaxThreads()); - this.mdcHook = mdcHook; + this.stairwayLoggingHook = stairwayLoggingHook; this.stairwayComponent = stairwayComponent; this.flightBeanBag = flightBeanBag; this.objectMapper = objectMapper; @@ -101,7 +101,7 @@ public LandingZoneJobService( // Fully fluent style of JobBuilder public LandingZoneJobBuilder newJob() { - return new LandingZoneJobBuilder(this, stairwayComponent, mdcHook, openTelemetry); + return new LandingZoneJobBuilder(this, stairwayComponent, openTelemetry); } // submit a new job to stairway @@ -176,7 +176,7 @@ public void initialize() { .newStairwayOptionsBuilder() .dataSource(DataSourceInitializer.initializeDataSource(stairwayDatabaseConfiguration)) .context(flightBeanBag) - .addHook(mdcHook) + .addHook(stairwayLoggingHook) .addHook(new MonitoringHook(openTelemetry)) .exceptionSerializer(new StairwayExceptionSerializer(objectMapper))); } diff --git a/library/src/main/java/bio/terra/landingzone/stairway/common/exception/MDCHandlingException.java b/library/src/main/java/bio/terra/landingzone/stairway/common/exception/MDCHandlingException.java deleted file mode 100644 index d4bfe84c0..000000000 --- a/library/src/main/java/bio/terra/landingzone/stairway/common/exception/MDCHandlingException.java +++ /dev/null @@ -1,27 +0,0 @@ -package bio.terra.landingzone.stairway.common.exception; - -import bio.terra.common.exception.InternalServerErrorException; -import java.util.List; - -public class MDCHandlingException extends InternalServerErrorException { - - public MDCHandlingException(String message) { - super(message); - } - - public MDCHandlingException(String message, Throwable cause) { - super(message, cause); - } - - public MDCHandlingException(Throwable cause) { - super(cause); - } - - public MDCHandlingException(String message, List causes) { - super(message, causes); - } - - public MDCHandlingException(String message, Throwable cause, List causes) { - super(message, cause, causes); - } -} diff --git a/library/src/main/java/bio/terra/landingzone/stairway/common/utils/LandingZoneMdcHook.java b/library/src/main/java/bio/terra/landingzone/stairway/common/utils/LandingZoneMdcHook.java deleted file mode 100644 index 19bbd0455..000000000 --- a/library/src/main/java/bio/terra/landingzone/stairway/common/utils/LandingZoneMdcHook.java +++ /dev/null @@ -1,138 +0,0 @@ -package bio.terra.landingzone.stairway.common.utils; - -import bio.terra.landingzone.stairway.common.exception.MDCHandlingException; -import bio.terra.stairway.FlightContext; -import bio.terra.stairway.FlightMap; -import bio.terra.stairway.HookAction; -import bio.terra.stairway.StairwayHook; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableMap; -import java.util.Map; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * A {@link StairwayHook} for propagating MDC context across steps using the input {@link - * FlightMap}. - * - *

This allows steps to have the same MDC context as when their flight was created. Note that any - * modifications to the MDC context within a step are not propagated to other steps. - */ -@Component -public class LandingZoneMdcHook implements StairwayHook { - private static final Logger logger = LoggerFactory.getLogger(LandingZoneMdcHook.class); - private static final String FLIGHT_LOG_FORMAT = "Operation: {}, flightClass: {}, flightId: {}"; - private static final String STEP_LOG_FORMAT = - "Operation: {}, flightClass: {}, flightId: {}, stepClass: {}, stepIndex: {}, direction: {}"; - - /** The key to use in {@link FlightMap} for storing the MDC context. */ - public static final String MDC_FLIGHT_MAP_KEY = "mdcKey"; - - private static final TypeReference> mapType = new TypeReference<>() {}; - - private final ObjectMapper objectMapper; - - @Autowired - public LandingZoneMdcHook(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - /** - * Returns a serialized version of the current MDC context. - * - *

This is meant to be used to set up the initial {@link FlightMap} when a Flight is being - * created to propagate the context of the flight creation to the steps. - */ - public Object getSerializedCurrentContext() { - return serializeMdc(MDC.getCopyOfContextMap()); - } - - @Override - public HookAction startStep(FlightContext flightContext) { - logger.info( - STEP_LOG_FORMAT, - "startStep", - flightContext.getFlightClassName(), - flightContext.getFlightId(), - flightContext.getStepClassName(), - flightContext.getStepIndex(), - flightContext.getDirection().name()); - String serializedMdc = flightContext.getInputParameters().get(MDC_FLIGHT_MAP_KEY, String.class); - // Note that this destroys any previous context on this thread. - MDC.setContextMap(deserializeMdc(serializedMdc)); - return HookAction.CONTINUE; - } - - @Override - public HookAction endStep(FlightContext flightContext) { - logger.info( - STEP_LOG_FORMAT, - "endStep", - flightContext.getFlightClassName(), - flightContext.getFlightId(), - flightContext.getStepClassName(), - flightContext.getStepIndex(), - flightContext.getDirection().name()); - MDC.clear(); - return HookAction.CONTINUE; - } - - @Override - public HookAction startFlight(FlightContext flightContext) { - logger.info( - FLIGHT_LOG_FORMAT, - "startFlight", - flightContext.getFlightClassName(), - flightContext.getFlightId()); - return HookAction.CONTINUE; - } - - @Override - public HookAction endFlight(FlightContext flightContext) { - logger.info( - FLIGHT_LOG_FORMAT, - "endFlight", - flightContext.getFlightClassName(), - flightContext.getFlightId()); - return HookAction.CONTINUE; - } - - private String serializeMdc(@Nullable Map mdcMap) { - try { - return objectMapper.writeValueAsString(mdcMap); - } catch (JsonProcessingException e) { - throw new MDCHandlingException( - "Error serializing MDC map from string: " - + (mdcMap == null ? "null" : mdcMap.toString())); - } - } - - private Map deserializeMdc(@Nullable String serializedMdc) { - if (serializedMdc == null) { - return ImmutableMap.of(); - } - Map mdcContext; - try { - mdcContext = objectMapper.readValue(serializedMdc, mapType); - } catch (JsonProcessingException e) { - throw new MDCHandlingException("Error deserializing MDC map from string: " + serializedMdc); - } - if (mdcContext == null) { - return ImmutableMap.of(); - } - return mdcContext; - } - - @Override - public HookAction stateTransition(FlightContext context) throws InterruptedException { - logger.info( - "Flight ID {} changed status to {}.", context.getFlightId(), context.getFlightStatus()); - return HookAction.CONTINUE; - } -} diff --git a/library/src/main/java/bio/terra/landingzone/stairway/common/utils/StairwayLoggingHook.java b/library/src/main/java/bio/terra/landingzone/stairway/common/utils/StairwayLoggingHook.java new file mode 100644 index 000000000..381e892f2 --- /dev/null +++ b/library/src/main/java/bio/terra/landingzone/stairway/common/utils/StairwayLoggingHook.java @@ -0,0 +1,74 @@ +package bio.terra.landingzone.stairway.common.utils; + +import bio.terra.stairway.FlightContext; +import bio.terra.stairway.FlightMap; +import bio.terra.stairway.HookAction; +import bio.terra.stairway.StairwayHook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** A {@link StairwayHook} which supplements logging at notable flight state transitions. */ +@Component +public class StairwayLoggingHook implements StairwayHook { + private static final Logger logger = LoggerFactory.getLogger(StairwayLoggingHook.class); + private static final String FLIGHT_LOG_FORMAT = "Operation: {}, flightClass: {}, flightId: {}"; + private static final String STEP_LOG_FORMAT = + "Operation: {}, flightClass: {}, flightId: {}, stepClass: {}, stepIndex: {}, direction: {}"; + + /** The key to use in {@link FlightMap} for storing the MDC context. */ + public static final String MDC_FLIGHT_MAP_KEY = "mdcKey"; + + @Override + public HookAction startStep(FlightContext flightContext) { + logger.info( + STEP_LOG_FORMAT, + "startStep", + flightContext.getFlightClassName(), + flightContext.getFlightId(), + flightContext.getStepClassName(), + flightContext.getStepIndex(), + flightContext.getDirection().name()); + return HookAction.CONTINUE; + } + + @Override + public HookAction endStep(FlightContext flightContext) { + logger.info( + STEP_LOG_FORMAT, + "endStep", + flightContext.getFlightClassName(), + flightContext.getFlightId(), + flightContext.getStepClassName(), + flightContext.getStepIndex(), + flightContext.getDirection().name()); + return HookAction.CONTINUE; + } + + @Override + public HookAction startFlight(FlightContext flightContext) { + logger.info( + FLIGHT_LOG_FORMAT, + "startFlight", + flightContext.getFlightClassName(), + flightContext.getFlightId()); + return HookAction.CONTINUE; + } + + @Override + public HookAction endFlight(FlightContext flightContext) { + logger.info( + FLIGHT_LOG_FORMAT, + "endFlight", + flightContext.getFlightClassName(), + flightContext.getFlightId()); + return HookAction.CONTINUE; + } + + @Override + public HookAction stateTransition(FlightContext context) { + logger.info( + "Flight ID {} changed status to {}.", context.getFlightId(), context.getFlightStatus()); + return HookAction.CONTINUE; + } +} diff --git a/library/src/main/java/bio/terra/landingzone/stairway/flight/utils/FlightUtils.java b/library/src/main/java/bio/terra/landingzone/stairway/flight/utils/FlightUtils.java index 4feecf47e..b5fd22359 100644 --- a/library/src/main/java/bio/terra/landingzone/stairway/flight/utils/FlightUtils.java +++ b/library/src/main/java/bio/terra/landingzone/stairway/flight/utils/FlightUtils.java @@ -4,7 +4,6 @@ import bio.terra.landingzone.db.model.LandingZoneRecord; import bio.terra.landingzone.job.JobMapKeys; import bio.terra.landingzone.job.model.ErrorReport; -import bio.terra.landingzone.stairway.common.utils.LandingZoneMdcHook; import bio.terra.landingzone.stairway.flight.exception.MissingRequiredFieldsException; import bio.terra.stairway.FlightContext; import bio.terra.stairway.FlightMap; @@ -26,8 +25,6 @@ public class FlightUtils { LandingZoneRecord.class, JobMapKeys.SUBJECT_ID.getKeyName(), String.class, - LandingZoneMdcHook.MDC_FLIGHT_MAP_KEY, - Object.class, MonitoringHook.SUBMISSION_SPAN_CONTEXT_MAP_KEY, Object.class); diff --git a/library/src/test/java/bio/terra/landingzone/job/LandingZoneJobServiceTest.java b/library/src/test/java/bio/terra/landingzone/job/LandingZoneJobServiceTest.java index b111911b4..6bde3a255 100644 --- a/library/src/test/java/bio/terra/landingzone/job/LandingZoneJobServiceTest.java +++ b/library/src/test/java/bio/terra/landingzone/job/LandingZoneJobServiceTest.java @@ -27,7 +27,7 @@ import bio.terra.landingzone.service.landingzone.azure.model.DeletedLandingZone; import bio.terra.landingzone.service.landingzone.azure.model.LandingZoneRequest; import bio.terra.landingzone.service.landingzone.azure.model.StartLandingZoneCreation; -import bio.terra.landingzone.stairway.common.utils.LandingZoneMdcHook; +import bio.terra.landingzone.stairway.common.utils.StairwayLoggingHook; import bio.terra.landingzone.stairway.flight.LandingZoneFlightMapKeys; import bio.terra.stairway.FlightMap; import bio.terra.stairway.FlightState; @@ -57,7 +57,7 @@ class LandingZoneJobServiceTest { @Mock private LandingZoneJobConfiguration jobConfig; @Mock private LandingZoneIngressConfiguration ingressConfig; @Mock private LandingZoneStairwayDatabaseConfiguration dbConfig; - @Mock private LandingZoneMdcHook mdcHook; + @Mock private StairwayLoggingHook stairwayLoggingHook; @Mock private StairwayComponent stairwayComponent; @Mock private LandingZoneFlightBeanBag flightBeanBag; @Mock private ObjectMapper mapper; @@ -77,7 +77,7 @@ void setUpFailedScenarioForRetrieveStartingAsyncJobResult() { jobConfig, ingressConfig, dbConfig, - mdcHook, + stairwayLoggingHook, stairwayComponent, flightBeanBag, mapper, diff --git a/library/src/test/java/bio/terra/landingzone/service/iam/LandingZoneSamServiceTest.java b/library/src/test/java/bio/terra/landingzone/service/iam/LandingZoneSamServiceTest.java index df39676af..fd609e738 100644 --- a/library/src/test/java/bio/terra/landingzone/service/iam/LandingZoneSamServiceTest.java +++ b/library/src/test/java/bio/terra/landingzone/service/iam/LandingZoneSamServiceTest.java @@ -44,12 +44,13 @@ class LandingZoneSamServiceTest { private static final SamUser SAM_USER = new SamUser("test@example.com", "Subject", new BearerToken("0123.456-789AbCd")); - private static final String SAM_BASE_PATH = "not_real"; private static final String RESOURCE_TYPE = "resource_type"; private static final String RESOURCE_ID = "resource_id"; private static final String RESOURCE_ACTION = "action"; private static final UUID LANDING_ZONE_ID = UUID.randomUUID(); private static final UUID BILLING_PROFILE_ID = UUID.randomUUID(); + private static final ApiException API_EXCEPTION = + new ApiException("Message: SomeError\nHTTP response code: 500"); private LandingZoneSamService samService; @Mock private LandingZoneSamClient samClient; @@ -114,7 +115,7 @@ void isAuthorized_noPermission() throws ApiException, InterruptedException { void isAuthorized_throwsSamInternalServerErrorException() throws ApiException { var token = SAM_USER.getBearerToken(); // Setup mocks - doThrow(new ApiException("...")) + doThrow(API_EXCEPTION) .when(resourcesApi) .resourcePermissionV2(RESOURCE_TYPE, RESOURCE_ID, RESOURCE_ACTION); when(samClient.resourcesApi(anyString())).thenReturn(resourcesApi); @@ -201,7 +202,7 @@ void createLandingZone_throwsSamInternalServerErrorException() throws ApiExcepti setupSamUserInfoMock(false); when(samClient.usersApi(anyString())).thenReturn(usersApi); when(samClient.getLandingZoneResourceUsers()).thenReturn(listOfUsers); - doThrow(new ApiException("...")) + doThrow(API_EXCEPTION) .when(resourcesApi) .createResourceV2( eq(SamConstants.SamResourceType.LANDING_ZONE), any(CreateResourceRequestV2.class)); @@ -244,7 +245,7 @@ void deleteLandingZone_notFound() throws ApiException, InterruptedException { void deleteLandingZone_throws() throws ApiException { var token = SAM_USER.getBearerToken(); // Setup Mocks - doThrow(new ApiException("...")) + doThrow(API_EXCEPTION) .when(resourcesApi) .deleteResourceV2(SamConstants.SamResourceType.LANDING_ZONE, LANDING_ZONE_ID.toString()); when(samClient.resourcesApi(anyString())).thenReturn(resourcesApi); @@ -328,10 +329,10 @@ void listLandingZoneResourceIds_listOfResources_Success() } @Test - void listLandingZoneResourceIds_throws() throws InterruptedException, ApiException { + void listLandingZoneResourceIds_throws() throws ApiException { var token = SAM_USER.getBearerToken(); // Setup Mocks - doThrow(new ApiException("...")) + doThrow(API_EXCEPTION) .when(resourcesApi) .listResourcesAndPoliciesV2(SamConstants.SamResourceType.LANDING_ZONE); when(samClient.resourcesApi(anyString())).thenReturn(resourcesApi); diff --git a/service/src/test/java/bio/terra/lz/futureservice/app/controller/LandingZoneApiControllerTest.java b/service/src/test/java/bio/terra/lz/futureservice/app/controller/LandingZoneApiControllerTest.java index e7d9285ec..727c2885c 100644 --- a/service/src/test/java/bio/terra/lz/futureservice/app/controller/LandingZoneApiControllerTest.java +++ b/service/src/test/java/bio/terra/lz/futureservice/app/controller/LandingZoneApiControllerTest.java @@ -32,10 +32,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.UUID; import java.util.stream.Stream; -import org.apache.http.HttpStatus; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -44,6 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultMatcher; @@ -83,7 +84,7 @@ public void createAzureLandingZoneJobRunning() throws Exception { .content(objectMapper.writeValueAsString(requestBody)) .characterEncoding("utf-8"), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_ACCEPTED)) + .andExpect(status().isAccepted()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id", Matchers.is(JOB_ID))) @@ -108,7 +109,7 @@ public void createAzureLandingZoneWithoutDefinitionValidationFailed() throws Exc .content(objectMapper.writeValueAsString(requestBody)) .characterEncoding("utf-8"), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)); + .andExpect(status().isBadRequest()); } @Test @@ -129,7 +130,7 @@ public void createAzureLandingZoneWithoutBillingProfileValidationFailed() throws .content(objectMapper.writeValueAsString(requestBody)) .characterEncoding("utf-8"), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)); + .andExpect(status().isBadRequest()); } @Test @@ -145,7 +146,7 @@ public void getCreateAzureLandingZoneResultJobRunning() throws Exception { .perform( MockMvcUtils.addAuth( get(GET_CREATE_AZURE_LANDING_ZONE_RESULT + "/{jobId}", JOB_ID), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_ACCEPTED)) + .andExpect(status().isAccepted()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id", Matchers.is(JOB_ID))) @@ -165,7 +166,7 @@ public void getCreateAzureLandingZoneResultJobSucceeded() throws Exception { .perform( MockMvcUtils.addAuth( get(GET_CREATE_AZURE_LANDING_ZONE_RESULT + "/{jobId}", JOB_ID), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_OK)) + .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.landingZone").exists()) @@ -229,7 +230,7 @@ public void deleteAzureLandingZoneSuccess() throws Exception { .content(objectMapper.writeValueAsString(requestBody)) .characterEncoding("utf-8"), USER_REQUEST)) - .andExpect(status().is(HttpStatus.SC_ACCEPTED)) + .andExpect(status().isAccepted()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.jobReport.id").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.landingZoneId").exists()) @@ -311,7 +312,8 @@ void listAzureLandingZoneResourcesNoResourcesSuccess() throws Exception { @Test void getAzureLandingZoneByLandingZoneIdSuccess() throws Exception { - var lzCreateDate = Instant.now().atOffset(ZoneOffset.UTC); + // Truncating to milliseconds so that our later comparison is performed at the same granularity. + var lzCreateDate = Instant.now().truncatedTo(ChronoUnit.MILLIS).atOffset(ZoneOffset.UTC); ApiAzureLandingZone landingZone = AzureLandingZoneFixtures.buildDefaultApiAzureLandingZone( LANDING_ZONE_ID, BILLING_PROFILE_ID, "definition", "version", lzCreateDate); @@ -410,12 +412,12 @@ private static Stream getDeleteAzureLandingZoneResultScenario() { return Stream.of( Arguments.of( ApiJobReport.StatusEnum.SUCCEEDED, - HttpStatus.SC_OK, + HttpStatus.OK.value(), MockMvcResultMatchers.jsonPath("$.landingZoneId").exists(), MockMvcResultMatchers.jsonPath("$.resources").exists()), Arguments.of( ApiJobReport.StatusEnum.RUNNING, - HttpStatus.SC_ACCEPTED, + HttpStatus.ACCEPTED.value(), MockMvcResultMatchers.jsonPath("$.landingZoneId").doesNotExist(), MockMvcResultMatchers.jsonPath("$.resources").doesNotExist())); } diff --git a/service/src/test/java/bio/terra/lz/futureservice/app/controller/PublicApiControllerTest.java b/service/src/test/java/bio/terra/lz/futureservice/app/controller/PublicApiControllerTest.java index 585ef0070..83d34a39c 100644 --- a/service/src/test/java/bio/terra/lz/futureservice/app/controller/PublicApiControllerTest.java +++ b/service/src/test/java/bio/terra/lz/futureservice/app/controller/PublicApiControllerTest.java @@ -10,7 +10,6 @@ import bio.terra.lz.futureservice.common.BaseSpringUnitTest; import bio.terra.lz.futureservice.common.fixture.SystemStatusFixtures; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.HttpStatus; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -54,7 +53,7 @@ public VersionConfiguration versionConfigurationTest() { public void testServiceVersionSuccess() throws Exception { mockMvc .perform(get(AZURE_SYSTEM_VERSION_PATH)) - .andExpect(status().is(HttpStatus.SC_OK)) + .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.gitTag").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.gitTag", Matchers.is(gitTag))) .andExpect(MockMvcResultMatchers.jsonPath("$.gitHash").exists()) @@ -75,7 +74,7 @@ public void testServiceStatusSuccess() throws Exception { mockMvc .perform(get(AZURE_SYSTEM_STATUS_PATH)) - .andExpect(status().is(HttpStatus.SC_OK)) + .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.ok").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.ok", Matchers.is(true))) .andExpect(MockMvcResultMatchers.jsonPath("$.systems").exists()) @@ -95,7 +94,7 @@ public void testServiceStatusServiceUnavailable() throws Exception { mockMvc .perform(get(AZURE_SYSTEM_STATUS_PATH)) - .andExpect(status().is(HttpStatus.SC_SERVICE_UNAVAILABLE)) + .andExpect(status().isServiceUnavailable()) .andExpect(MockMvcResultMatchers.jsonPath("$.ok").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.ok", Matchers.is(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.systems").exists()) diff --git a/testharness/build.gradle b/testharness/build.gradle index 106949ce8..0f48af384 100644 --- a/testharness/build.gradle +++ b/testharness/build.gradle @@ -11,7 +11,6 @@ dependencies { } implementation 'net.minidev:json-smart:2.5.0' - implementation 'bio.terra:terra-common-lib' implementation 'org.apache.commons:commons-dbcp2' implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web'