From dacc6fbfeaddb532c28b7aa490b226f6d680db91 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Fri, 27 Sep 2024 17:19:50 -0700 Subject: [PATCH] Addresses Issue #599, LocationLevel return over time for constant values. Includes tests to verify functionality --- .../java/cwms/cda/api/LevelsController.java | 68 ++++----- .../cwms/cda/data/dao/LocationLevelsDao.java | 3 +- .../cda/data/dao/LocationLevelsDaoImpl.java | 130 +++++++++++++----- .../java/cwms/cda/data/dto/LocationLevel.java | 63 ++++++++- .../cwms/cda/api/LevelsControllerTestIT.java | 79 ++++++++++- 5 files changed, 258 insertions(+), 85 deletions(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java index d51bd0c87..6e4e8903d 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java @@ -24,36 +24,6 @@ package cwms.cda.api; -import static com.codahale.metrics.MetricRegistry.name; -import static cwms.cda.api.Controllers.BEGIN; -import static cwms.cda.api.Controllers.CASCADE_DELETE; -import static cwms.cda.api.Controllers.CREATE; -import static cwms.cda.api.Controllers.DATE; -import static cwms.cda.api.Controllers.DATUM; -import static cwms.cda.api.Controllers.DELETE; -import static cwms.cda.api.Controllers.EFFECTIVE_DATE; -import static cwms.cda.api.Controllers.END; -import static cwms.cda.api.Controllers.FORMAT; -import static cwms.cda.api.Controllers.GET_ALL; -import static cwms.cda.api.Controllers.GET_ONE; -import static cwms.cda.api.Controllers.LEVEL_ID; -import static cwms.cda.api.Controllers.LEVEL_ID_MASK; -import static cwms.cda.api.Controllers.NAME; -import static cwms.cda.api.Controllers.OFFICE; -import static cwms.cda.api.Controllers.PAGE; -import static cwms.cda.api.Controllers.PAGE_SIZE; -import static cwms.cda.api.Controllers.RESULTS; -import static cwms.cda.api.Controllers.SIZE; -import static cwms.cda.api.Controllers.STATUS_200; -import static cwms.cda.api.Controllers.TIMEZONE; -import static cwms.cda.api.Controllers.UNIT; -import static cwms.cda.api.Controllers.UPDATE; -import static cwms.cda.api.Controllers.VERSION; -import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning; -import static cwms.cda.api.Controllers.queryParamAsClass; -import static cwms.cda.api.Controllers.requiredParam; -import static cwms.cda.data.dao.JooqDao.getDslContext; - import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; @@ -67,7 +37,6 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import cwms.cda.api.enums.UnitSystem; -import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.LocationLevelsDao; import cwms.cda.data.dao.LocationLevelsDaoImpl; import cwms.cda.data.dto.LocationLevel; @@ -89,13 +58,19 @@ import io.javalin.plugin.openapi.annotations.OpenApiParam; import io.javalin.plugin.openapi.annotations.OpenApiRequestBody; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import org.jetbrains.annotations.NotNull; +import org.jooq.DSLContext; + +import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; +import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; -import javax.servlet.http.HttpServletResponse; -import org.jetbrains.annotations.NotNull; -import org.jooq.DSLContext; + +import static com.codahale.metrics.MetricRegistry.name; +import static cwms.cda.api.Controllers.*; +import static cwms.cda.data.dao.JooqDao.getDslContext; public class LevelsController implements CrudHandler { @@ -280,8 +255,7 @@ public void getAll(@NotNull Context ctx) { boolean isLegacyVersion = version.equals("1"); - if (format.isEmpty() && !isLegacyVersion) - { + if (format.isEmpty() && !isLegacyVersion) { String cursor = ctx.queryParamAsClass(PAGE, String.class) .getOrDefault(""); int pageSize = ctx.queryParamAsClass(PAGE_SIZE, Integer.class) @@ -315,12 +289,10 @@ public void getAll(@NotNull Context ctx) { ctx.status(HttpServletResponse.SC_OK); ctx.result(results); requestResultSize.update(results.length()); - if (isLegacyVersion) - { + if (isLegacyVersion) { ctx.contentType(contentType.toString()); } - else - { + else { ctx.contentType(contentType.getType()); } } @@ -344,6 +316,12 @@ public void getAll(@NotNull Context ctx) { + "specified), as well as the time zone of any times in the response." + " If this field is not specified, the default time zone of UTC " + "shall be used."), + @OpenApiParam(name = START, type = Instant.class, description = "Specifies the start of the time " + + "window for data to be included in the response. Both this field and the end field must be " + + " specified, or no time window will be used."), + @OpenApiParam(name = END, type = Instant.class, description = "Specifies the end of the time " + + "window for data to be included in the response. Both this field and the start field must be" + + " specified, or no time window will be used."), @OpenApiParam(name = UNIT, description = "Desired unit for " + "the values retrieved.") }, @@ -362,16 +340,22 @@ public void getOne(@NotNull Context ctx, @NotNull String levelId) { String dateString = queryParamAsClass(ctx, new String[]{EFFECTIVE_DATE, DATE}, String.class, null, metrics, name(LevelsController.class.getName(), GET_ONE)); + Instant start = ctx.queryParamAsClass(START, Long.class).getOrDefault(null) == null ? null + : Instant.ofEpochMilli(ctx.queryParamAsClass(START, Long.class).get()); + Instant end = ctx.queryParamAsClass(END, Long.class).getOrDefault(null) == null ? null + : Instant.ofEpochMilli(ctx.queryParamAsClass(END, Long.class).getOrDefault(null)); String timezone = ctx.queryParamAsClass(TIMEZONE, String.class) .getOrDefault("UTC"); try (final Timer.Context ignored = markAndTime(GET_ONE)) { DSLContext dsl = getDslContext(ctx); ZonedDateTime unmarshalledDateTime = DateUtils.parseUserDate(dateString, timezone); + ZonedDateTime startZdt = start == null ? null : ZonedDateTime.ofInstant(start, ZoneId.of(timezone)); + ZonedDateTime endZdt = end == null ? null : ZonedDateTime.ofInstant(end, ZoneId.of(timezone)); LocationLevelsDao levelsDao = getLevelsDao(dsl); LocationLevel locationLevel = levelsDao.retrieveLocationLevel(levelId, - units, unmarshalledDateTime, office); + units, unmarshalledDateTime, office, startZdt, endZdt); ctx.json(locationLevel); ctx.status(HttpServletResponse.SC_OK); } @@ -429,7 +413,7 @@ public void update(@NotNull Context ctx, @NotNull String oldLevelId) { ZoneId.systemDefault().getId()); //retrieveLocationLevel will throw an error if level does not exist LocationLevel existingLevelLevel = levelsDao.retrieveLocationLevel(oldLevelId, - UnitSystem.EN.getValue(), unmarshalledDateTime, officeId); + UnitSystem.EN.getValue(), unmarshalledDateTime, officeId, null, null); existingLevelLevel = updatedClearedFields(ctx.body(), contentType.getType(), existingLevelLevel); //only store (update) if level does exist diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDao.java index 58ff3a8e4..1fedc8d06 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDao.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDao.java @@ -31,7 +31,6 @@ import mil.army.usace.hec.metadata.Interval; import java.time.Instant; -import java.time.ZoneId; import java.time.ZonedDateTime; public interface LocationLevelsDao { @@ -43,7 +42,7 @@ void deleteLocationLevel(String locationLevelName, ZonedDateTime date, String of void renameLocationLevel(String oldLocationLevelName, String newLocationLevelName, String officeId); LocationLevel retrieveLocationLevel(String locationLevelName, String unitSystem, - ZonedDateTime effectiveDate, String officeId); + ZonedDateTime effectiveDate, String officeId, ZonedDateTime start, ZonedDateTime end); String getLocationLevels(String format, String names, String office, String unit, String datum, String begin, diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java index 470e89000..119372bf6 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java @@ -52,6 +52,7 @@ import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -62,7 +63,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.TimeZone; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -75,6 +75,7 @@ import org.jooq.DSLContext; import org.jooq.Record; import org.jooq.Record1; +import org.jooq.Result; import org.jooq.SelectLimitPercentAfterOffsetStep; import org.jooq.TableField; import org.jooq.conf.ParamType; @@ -242,13 +243,12 @@ private static SEASONAL_VALUE_TAB_T getSeasonalValues(LocationLevel locationLeve List seasonalValues = locationLevel.getSeasonalValues(); SEASONAL_VALUE_TAB_T pSeasonalValues = null; - if(seasonalValues != null && !seasonalValues.isEmpty()) { + if (seasonalValues != null && !seasonalValues.isEmpty()) { pSeasonalValues = new SEASONAL_VALUE_TAB_T(); - for(SeasonalValueBean seasonalValue : seasonalValues) - { + for (SeasonalValueBean seasonalValue : seasonalValues) { SEASONAL_VALUE_T seasonalValueT = new SEASONAL_VALUE_T(); seasonalValueT.setOFFSET_MINUTES(toBigDecimal(seasonalValue.getOffsetMinutes())); - if(seasonalValue.getOffsetMonths() != null) { + if (seasonalValue.getOffsetMonths() != null) { seasonalValueT.setOFFSET_MONTHS(seasonalValue.getOffsetMonths().byteValue()); } seasonalValueT.setVALUE(toBigDecimal(seasonalValue.getValue())); @@ -325,41 +325,101 @@ public void renameLocationLevel(String oldLocationLevelName, String newLocationL @Override public LocationLevel retrieveLocationLevel(String locationLevelName, String pUnits, - ZonedDateTime effectiveDate, String officeId) { + ZonedDateTime effectiveDate, String officeId, ZonedDateTime start, ZonedDateTime end) { Timestamp date = Timestamp.from(effectiveDate.toInstant()); + Timestamp startDate = start == null ? null : Timestamp.from(start.toInstant()); + Timestamp endDate = end == null ? null : Timestamp.from(end.toInstant()); return connectionResult(dsl, c -> { String units = pUnits; Configuration configuration = getDslContext(c, officeId).configuration(); - RETRIEVE_LOCATION_LEVEL3 level = CWMS_LEVEL_PACKAGE.call_RETRIEVE_LOCATION_LEVEL3( - configuration, locationLevelName, units, date, - "UTC", null, null, units, - "F", officeId); - List seasonalValues = buildSeasonalValues(level); - if (units == null) { - String parameter = locationLevelName.split("\\.")[1]; - logger.info("Getting default units for " + parameter); - String defaultUnits = CWMS_UTIL_PACKAGE.call_GET_DEFAULT_UNITS( - configuration, parameter, UnitSystem.SI.getValue()); - logger.info("Default units are " + defaultUnits); - units = defaultUnits; + + if (start != null && end != null) { + + ZoneId tz = start.getZone(); + if (units == null) { + String parameter = locationLevelName.split("\\.")[1]; + logger.info("Getting default units for " + parameter); + String defaultUnits = CWMS_UTIL_PACKAGE.call_GET_DEFAULT_UNITS( + configuration, parameter, UnitSystem.SI.getValue()); + logger.info("Default units are " + defaultUnits); + units = defaultUnits; + } + + Result result = dsl.select(AV_LOCATION_LEVEL.LOCATION_LEVEL_ID, + AV_LOCATION_LEVEL.OFFICE_ID, AV_LOCATION_LEVEL.LEVEL_DATE, + AV_LOCATION_LEVEL.CONSTANT_LEVEL, AV_LOCATION_LEVEL.LEVEL_UNIT) + .from(AV_LOCATION_LEVEL) + .where(AV_LOCATION_LEVEL.LOCATION_LEVEL_ID.eq(locationLevelName)) + .and(AV_LOCATION_LEVEL.OFFICE_ID.eq(officeId)) + .and(AV_LOCATION_LEVEL.LEVEL_DATE.ge(startDate)) + .and(AV_LOCATION_LEVEL.LEVEL_DATE.le(endDate)) + .and(AV_LOCATION_LEVEL.LEVEL_UNIT.eq(units)) + .fetch(); + + if (result.isEmpty()) { + throw new NotFoundException("No location level found for " + locationLevelName + " at " + date); + } + + boolean parentData = false; + String locLevelId = null; + Timestamp recentDate = null; + Double constantValue = null; + List constantList = new ArrayList<>(); + for (Record r : result) { + if (!parentData) + { + locLevelId = r.get(AV_LOCATION_LEVEL.LOCATION_LEVEL_ID); + } + + if (recentDate == null || recentDate.before(r.get(AV_LOCATION_LEVEL.LEVEL_DATE))) { + recentDate = r.get(AV_LOCATION_LEVEL.LEVEL_DATE); + constantValue = r.get(AV_LOCATION_LEVEL.CONSTANT_LEVEL); + } + constantList.add(new LocationLevel.ConstantValue.Builder() + .withConstantValue(r.get(AV_LOCATION_LEVEL.CONSTANT_LEVEL)) + .withLevelDate(ZonedDateTime.of(r.get(AV_LOCATION_LEVEL.LEVEL_DATE).toLocalDateTime(), + tz)) + .build()); + } + + return new LocationLevel.Builder(locLevelId, + ZonedDateTime.of(recentDate.toLocalDateTime(), tz)) + .withConstantValueList(constantList).withConstantValue(constantValue) + .withOfficeId(officeId).withAttributeUnitsId(units) + .build(); + + } else { + RETRIEVE_LOCATION_LEVEL3 level = CWMS_LEVEL_PACKAGE.call_RETRIEVE_LOCATION_LEVEL3( + configuration, locationLevelName, units, date, + "UTC", null, null, units, + "F", officeId); + List seasonalValues = buildSeasonalValues(level); + if (units == null) { + String parameter = locationLevelName.split("\\.")[1]; + logger.info("Getting default units for " + parameter); + String defaultUnits = CWMS_UTIL_PACKAGE.call_GET_DEFAULT_UNITS( + configuration, parameter, UnitSystem.SI.getValue()); + logger.info("Default units are " + defaultUnits); + units = defaultUnits; + } + return new LocationLevel.Builder(locationLevelName, effectiveDate) + .withLevelUnitsId(units) + .withAttributeUnitsId(units) + .withInterpolateString(level.getP_INTERPOLATE()) + .withIntervalMinutes(Optional.ofNullable(level.getP_INTERVAL_MINUTES()) + .map(BigInteger::intValue).orElse(null)) + .withIntervalMonths(Optional.ofNullable(level.getP_INTERVAL_MONTHS()) + .map(BigInteger::intValue).orElse(null)) + .withIntervalOrigin(level.getP_INTERVAL_ORIGIN(), effectiveDate) + .withLevelComment(level.getP_LEVEL_COMMENT()) + .withOfficeId(officeId) + .withAttributeParameterId(level.get(RETRIEVE_LOCATION_LEVEL3.P_ATTRIBUTE_ID)) + .withSeasonalTimeSeriesId(level.get(RETRIEVE_LOCATION_LEVEL3.P_TSID)) + .withSeasonalValues(seasonalValues) + .withConstantValue(Optional.ofNullable(level.getP_LEVEL_VALUE()) + .map(BigDecimal::doubleValue).orElse(null)) + .build(); } - return new LocationLevel.Builder(locationLevelName, effectiveDate) - .withLevelUnitsId(units) - .withAttributeUnitsId(units) - .withInterpolateString(level.getP_INTERPOLATE()) - .withIntervalMinutes(Optional.ofNullable(level.getP_INTERVAL_MINUTES()) - .map(BigInteger::intValue).orElse(null)) - .withIntervalMonths(Optional.ofNullable(level.getP_INTERVAL_MONTHS()) - .map(BigInteger::intValue).orElse(null)) - .withIntervalOrigin(level.getP_INTERVAL_ORIGIN(), effectiveDate) - .withLevelComment(level.getP_LEVEL_COMMENT()) - .withOfficeId(officeId) - .withAttributeParameterId(level.get(RETRIEVE_LOCATION_LEVEL3.P_ATTRIBUTE_ID)) - .withSeasonalTimeSeriesId(level.get(RETRIEVE_LOCATION_LEVEL3.P_TSID)) - .withSeasonalValues(seasonalValues) - .withConstantValue(Optional.ofNullable(level.getP_LEVEL_VALUE()) - .map(BigDecimal::doubleValue).orElse(null)) - .build(); }); } diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/LocationLevel.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/LocationLevel.java index 953eaf40d..73086f9e9 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dto/LocationLevel.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/LocationLevel.java @@ -67,6 +67,10 @@ public final class LocationLevel extends CwmsDTO { + "seasonableTimeSeriesId and seasonValues.") private final Double constantValue; + @Schema(description = "List of constant values for this location level.") + @JsonFormat(shape = JsonFormat.Shape.ARRAY) + + private final List constantValueList; @Schema(description = "Units the provided levels are in") private final String levelUnitsId; @@ -121,6 +125,7 @@ private LocationLevel(Builder builder) { parameterTypeId = builder.parameterTypeId; parameterId = builder.parameterId; constantValue = builder.constantValue; + constantValueList = builder.constantValueList; levelUnitsId = builder.levelUnitsId; levelDate = builder.levelDate; levelComment = builder.levelComment; @@ -162,6 +167,10 @@ public Double getConstantValue() { return constantValue; } + public List getConstantValueList() { + return constantValueList; + } + public String getLevelUnitsId() { return levelUnitsId; } @@ -231,6 +240,7 @@ public static class Builder { private String parameterTypeId; private String parameterId; private Double constantValue; + private List constantValueList; private String levelUnitsId; private ZonedDateTime levelDate; private String levelComment; @@ -470,6 +480,11 @@ public Builder withConstantValue(Double value) { return this; } + public Builder withConstantValueList(List constantValueList) { + this.constantValueList = constantValueList; + return this; + } + public Builder withLevelUnitsId(String levelUnitsId) { this.levelUnitsId = levelUnitsId; return this; @@ -576,14 +591,54 @@ protected void validateInternal(CwmsDTOValidator validator) { super.validateInternal(validator); validator.required(getOfficeId(), "office-id"); validator.required(getLocationLevelId(), "location-level-id"); - if(getConstantValue() == null && getSeasonalTimeSeriesId() == null) { + if (getConstantValue() == null && getSeasonalTimeSeriesId() == null) { validator.required(getSeasonalValues(), "seasonal-values"); - } else if(getSeasonalValues() == null && getSeasonalTimeSeriesId() == null) { + } else if (getSeasonalValues() == null && getSeasonalTimeSeriesId() == null) { validator.required(getConstantValue(), "constant-value"); - } else if(getConstantValue() == null && getSeasonalValues() == null) { + } else if (getConstantValue() == null && getSeasonalValues() == null) { validator.required(getSeasonalTimeSeriesId(), "seasonable-time-series-id"); } - validator.mutuallyExclusive("Only one of the following can be defined for location levels: constant-value, seasonal-values, seasonable-time-series-id", + validator.mutuallyExclusive("Only one of the following can be defined for location levels: " + + "constant-value, seasonal-values, seasonable-time-series-id", getConstantValue(), getSeasonalValues(), getSeasonalTimeSeriesId()); } + + @JsonFormat(shape = JsonFormat.Shape.ARRAY) + public static class ConstantValue { + @JsonFormat(shape = JsonFormat.Shape.STRING) + private final ZonedDateTime levelDate; + private final double value; + + private ConstantValue(Builder builder) { + levelDate = builder.levelDate; + value = builder.constantValue; + } + + public ZonedDateTime getLevelDate() { + return levelDate; + } + + public double getValue() { + return value; + } + + public static class Builder { + private ZonedDateTime levelDate; + private double constantValue; + + public Builder withConstantValue(double constantValue) { + this.constantValue = constantValue; + return this; + } + + public Builder withLevelDate(ZonedDateTime levelDate) { + this.levelDate = levelDate; + return this; + } + + public ConstantValue build() { + return new ConstantValue(this); + } + } + } } diff --git a/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java index e0a37eddc..579b5da38 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java @@ -180,6 +180,81 @@ void test_level_as_timeseries() throws Exception { } } + @Test + void test_get_constants_over_time() throws Exception { + String locId = "level_get_constants_test"; + String levelId = locId + ".Stor.Ave.1Day.Regulating"; + createLocation(locId, true, OFFICE); + final ZonedDateTime time = ZonedDateTime.of(2023, 6, 1, 0, 0, 0, 0, ZoneId.of("America" + + "/Los_Angeles")); + CwmsDataApiSetupCallback.getDatabaseLink().connection(c -> { + LocationLevel level = new LocationLevel.Builder(levelId, time) + .withOfficeId(OFFICE) + .withConstantValue(1.0) + .withLevelUnitsId("ac-ft") + .build(); + LocationLevel level2 = new LocationLevel.Builder(levelId, time.plusDays(1)) + .withOfficeId(OFFICE) + .withConstantValue(2.0) + .withLevelUnitsId("ac-ft") + .build(); + DSLContext dsl = dslContext(c, OFFICE); + LocationLevelsDaoImpl dao = new LocationLevelsDaoImpl(dsl); + dao.storeLocationLevel(level); + dao.storeLocationLevel(level2); + }); + + Instant startTime = Instant.parse("2023-06-01T00:00:00Z"); + Instant endTime = Instant.parse("2023-06-02T12:00:00Z"); + + // get location level constants over time + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam(Controllers.OFFICE, OFFICE) + .queryParam(START, startTime.toEpochMilli()) + .queryParam(END, endTime.toEpochMilli()) + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .queryParam(UNIT, "ac-ft") + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/" + levelId) + .then() + .assertThat() + .log().ifValidationFails(LogDetail.ALL, true) + .statusCode(is(HttpServletResponse.SC_OK)) + .body("constant-value-list.size()", is(2)) + .body("constant-value-list[0].toString()",equalTo("[2023-06-01T00:00:00Z, 1.0]")) + .body("constant-value-list[1].toString()",equalTo("[2023-06-02T00:00:00Z, 2.0]")) + ; + + // get location level constants over time with specified timezone + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam(Controllers.OFFICE, OFFICE) + .queryParam(START, startTime.toEpochMilli()) + .queryParam(END, endTime.toEpochMilli()) + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .queryParam(UNIT, "ac-ft") + .queryParam(TIMEZONE, "America/Phoenix") + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/" + levelId) + .then() + .assertThat() + .log().ifValidationFails(LogDetail.ALL, true) + .statusCode(is(HttpServletResponse.SC_OK)) + .body("constant-value-list.size()", is(2)) + .body("constant-value-list[0].toString()",equalTo("[2023-06-01T00:00:00-07:00, 1.0]")) + .body("constant-value-list[1].toString()",equalTo("[2023-06-02T00:00:00-07:00, 2.0]")) + ; + } + @Test void test_get_all_location_level() throws Exception { @@ -347,7 +422,7 @@ void test_get_all_location_level() throws Exception { @ParameterizedTest @EnumSource(GetAllTestNewAliases.class) - void test_get_all_aliases_new(GetAllTestNewAliases test) throws Exception + void test_get_all_aliases_new(GetAllTestNewAliases test) { given() .log().ifValidationFails(LogDetail.ALL, true) @@ -367,7 +442,7 @@ void test_get_all_aliases_new(GetAllTestNewAliases test) throws Exception @ParameterizedTest @EnumSource(GetAllTestLegacy.class) - void test_get_all_aliases_legacy(GetAllTestLegacy test) throws Exception + void test_get_all_aliases_legacy(GetAllTestLegacy test) { given() .log().ifValidationFails(LogDetail.ALL, true)