From f3c590ceec6b01a3343cd156113d2871fcb585f5 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Wed, 18 Dec 2024 14:16:17 -0800 Subject: [PATCH 1/3] Implemented ConfigResources Controller refactor, ConfigSensor mapping IN PROGRESS --- .../opendcs/odcsapi/res/ConfigResources.java | 267 +++++++++++++--- .../opendcs/odcsapi/res/OpenDcsResource.java | 16 +- .../odcsapi/res/ConfigResourcesTest.java | 196 ++++++++++++ .../org/opendcs/odcsapi/res/it/BaseIT.java | 34 ++ .../odcsapi/res/it/ConfigResourcesIT.java | 302 ++++++++++++++++++ 5 files changed, 767 insertions(+), 48 deletions(-) create mode 100644 opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java create mode 100644 opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java index 22b67a72d..1ef104ded 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java @@ -15,10 +15,13 @@ package org.opendcs.odcsapi.res; -import java.sql.SQLException; -import java.util.logging.Logger; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; import javax.annotation.security.RolesAllowed; +import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -31,20 +34,31 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import decodes.db.ConfigSensor; +import decodes.db.DatabaseException; +import decodes.db.DatabaseIO; +import decodes.db.DecodesScript; +import decodes.db.DecodesScriptException; +import decodes.db.EngineeringUnit; +import decodes.db.PlatformConfig; +import decodes.db.PlatformConfigList; +import decodes.db.Poly5Converter; +import decodes.db.ScriptSensor; +import decodes.db.UnitConverter; +import decodes.sql.DbKey; +import org.opendcs.odcsapi.beans.ApiConfigRef; import org.opendcs.odcsapi.beans.ApiConfigScript; import org.opendcs.odcsapi.beans.ApiConfigScriptSensor; +import org.opendcs.odcsapi.beans.ApiConfigSensor; import org.opendcs.odcsapi.beans.ApiPlatformConfig; -import org.opendcs.odcsapi.dao.ApiConfigDAO; +import org.opendcs.odcsapi.beans.ApiUnitConverter; import org.opendcs.odcsapi.dao.DbException; import org.opendcs.odcsapi.errorhandling.ErrorCodes; import org.opendcs.odcsapi.errorhandling.WebAppException; -import org.opendcs.odcsapi.hydrojson.DbInterface; import org.opendcs.odcsapi.sec.AuthorizationCheck; -import org.opendcs.odcsapi.util.ApiConstants; -import org.opendcs.odcsapi.util.ApiHttpUtil; @Path("/") -public class ConfigResources +public class ConfigResources extends OpenDcsResource { @Context HttpHeaders httpHeaders; @@ -54,30 +68,82 @@ public class ConfigResources @RolesAllowed({AuthorizationCheck.ODCS_API_GUEST}) public Response getConfigRefs() throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("geConfigRefs"); - try (DbInterface dbi = new DbInterface(); - ApiConfigDAO configDAO = new ApiConfigDAO(dbi)) + try { - return ApiHttpUtil.createResponse(configDAO.getConfigRefs()); + DatabaseIO dbIo = getLegacyDatabase(); + PlatformConfigList configList = new PlatformConfigList(); + dbIo.readConfigList(configList); + return Response.status(HttpServletResponse.SC_OK).entity(map(configList)).build(); } + catch (DatabaseException ex) + { + throw new DbException("Error reading config list", ex); + } + } + + static List map(PlatformConfigList configList) + { + List configRefs = new ArrayList<>(); + for (PlatformConfig config : configList.values()) + { + ApiConfigRef configRef = new ApiConfigRef(); + if (config.getId() != null) + { + configRef.setConfigId(config.getId().getValue()); + } + else + { + configRef.setConfigId(DbKey.NullKey.getValue()); + } + configRef.setName(config.getName()); + configRef.setNumPlatforms(config.numPlatformsUsing); + configRef.setDescription(config.description); + configRefs.add(configRef); + } + return configRefs; } @GET @Path("config") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({AuthorizationCheck.ODCS_API_GUEST}) - public Response getConfig(@QueryParam("configid") Long configId) throws WebAppException, DbException, SQLException + public Response getConfig(@QueryParam("configid") Long configId) throws WebAppException, DbException { if (configId == null) - throw new WebAppException(ErrorCodes.MISSING_ID, - "Missing required configid parameter."); - - Logger.getLogger(ApiConstants.loggerName).fine("getConfig id=" + configId); - try (DbInterface dbi = new DbInterface(); - ApiConfigDAO configDAO = new ApiConfigDAO(dbi)) { - return ApiHttpUtil.createResponse(configDAO.getConfig(configId)); + throw new WebAppException(ErrorCodes.MISSING_ID, + "Missing required configid parameter."); + } + + try + { + DatabaseIO dbIo = getLegacyDatabase(); + PlatformConfig config = new PlatformConfig(); + config.setId(DbKey.createDbKey(configId)); + dbIo.readConfig(config); + return Response.status(HttpServletResponse.SC_OK).entity(map(config)).build(); + } + catch (DatabaseException ex) + { + throw new DbException("Error reading config", ex); + } + } + + static ApiPlatformConfig map(PlatformConfig config) + { + ApiPlatformConfig apiConfig = new ApiPlatformConfig(); + if (config.getId() != null) + { + apiConfig.setConfigId(config.getId().getValue()); + } + else + { + apiConfig.setConfigId(DbKey.NullKey.getValue()); } + apiConfig.setName(config.getName()); + apiConfig.setNumPlatforms(config.numPlatformsUsing); + apiConfig.setDescription(config.description); + return apiConfig; } @POST @@ -85,48 +151,155 @@ public Response getConfig(@QueryParam("configid") Long configId) throws WebAppEx @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({AuthorizationCheck.ODCS_API_ADMIN, AuthorizationCheck.ODCS_API_USER}) - public Response postConfig(ApiPlatformConfig config) throws WebAppException, DbException, SQLException + public Response postConfig(ApiPlatformConfig config) throws DbException + { + try + { + DatabaseIO dbIo = getLegacyDatabase(); + PlatformConfig pc = map(config); + dbIo.writeConfig(pc); + return Response.status(HttpServletResponse.SC_OK) + .entity(map(pc)) + .build(); + } + catch (DatabaseException ex) + { + throw new DbException("Error saving config", ex); + } + } + + static PlatformConfig map(ApiPlatformConfig config) throws DbException + { + try + { + PlatformConfig pc = new PlatformConfig(config.getName()); + if (config.getConfigId() != null) + { + pc.setId(DbKey.createDbKey(config.getConfigId())); + } + else + { + pc.setId(DbKey.NullKey); + } + pc.description = config.getDescription(); + pc.numPlatformsUsing = config.getNumPlatforms(); + + pc.configName = config.getName(); + pc.decodesScripts = map(config.getScripts(), pc); + for (ApiConfigSensor sensor : config.getConfigSensors()) + { + ConfigSensor configSensor = new ConfigSensor(null, sensor.getSensorNumber()); + configSensor.sensorName = sensor.getSensorName(); + configSensor.platformConfig = pc; + pc.addSensor(configSensor); + } + + return pc; + } + catch (DatabaseException ex) + { + throw new DbException("Error mapping platform config", ex); + } + } + + static Vector map(List scripts, PlatformConfig config) throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("post config received config " + config.getName() - + " with ID=" + config.getConfigId()); - - Logger.getLogger(ApiConstants.loggerName).fine("POST config script sensors: "); - for(ApiConfigScript acs : config.getScripts()) - { - Logger.getLogger(ApiConstants.loggerName).fine("\tscript " + acs.getName()); - for(ApiConfigScriptSensor acss : acs.getScriptSensors()) + if (scripts == null) + { + return new Vector<>(); + } + + try + { + Vector decodesScripts = new Vector<>(); + for(ApiConfigScript script : scripts) { - Logger.getLogger(ApiConstants.loggerName).fine("\t\t" + acss.prettyPrint()); + DecodesScript.DecodesScriptBuilder dsb = DecodesScript.empty(); + dsb.platformConfig(config); + dsb.scriptName(script.getName()); + DecodesScript ds = dsb.build(); + for (ApiConfigScriptSensor sensor : script.getScriptSensors()) + { + ds.addScriptSensor(map(sensor)); + } + decodesScripts.add(ds); } + return decodesScripts; + } + catch(DecodesScriptException | IOException ex) + { + throw new DbException("Error mapping scripts", ex); + } + } + + static ScriptSensor map(ApiConfigScriptSensor sensor) + { + ScriptSensor scriptSensor = new ScriptSensor(null, sensor.getSensorNumber()); + scriptSensor.execConverter = map(sensor.getUnitConverter()); + if (sensor.getUnitConverter().getUcId() != null) + { + scriptSensor.setUnitConverterId(DbKey.createDbKey(sensor.getUnitConverter().getUcId())); } - try (DbInterface dbi = new DbInterface(); - ApiConfigDAO configDAO = new ApiConfigDAO(dbi)) + else { - configDAO.writeConfig(config); - return ApiHttpUtil.createResponse(config); + scriptSensor.setUnitConverterId(DbKey.NullKey); } + return scriptSensor; + } + + static UnitConverter map(ApiUnitConverter unitConverter) + { + EngineeringUnit from = EngineeringUnit.getEngineeringUnit(unitConverter.getFromAbbr()); + EngineeringUnit to = EngineeringUnit.getEngineeringUnit(unitConverter.getToAbbr()); + Poly5Converter pc = new Poly5Converter(from, to); + double[] coeffs = new double[6]; + coeffs[0] = unitConverter.getA() != null ? unitConverter.getA() : 0.0; + coeffs[1] = unitConverter.getB() != null ? unitConverter.getB() : 0.0; + coeffs[2] = unitConverter.getC() != null ? unitConverter.getC() : 0.0; + coeffs[3] = unitConverter.getD() != null ? unitConverter.getD() : 0.0; + coeffs[4] = unitConverter.getE() != null ? unitConverter.getE() : 0.0; + coeffs[5] = unitConverter.getF() != null ? unitConverter.getF() : 0.0; + pc.setCoefficients(coeffs); + return pc; } - + + @DELETE @Path("config") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({AuthorizationCheck.ODCS_API_ADMIN, AuthorizationCheck.ODCS_API_USER}) - public Response deleteConfig(@QueryParam("configid") Long configId) throws WebAppException, DbException, SQLException + public Response deleteConfig(@QueryParam("configid") Long configId) throws DbException, WebAppException { - Logger.getLogger(ApiConstants.loggerName).fine("DELETE config received configid=" + configId); - - // Use username and password to attempt to connect to the database - try (DbInterface dbi = new DbInterface(); - ApiConfigDAO cfgDao = new ApiConfigDAO(dbi)) - { - if (cfgDao.numPlatformsUsing(configId) > 0) - return ApiHttpUtil.createResponse(" Cannot delete config with ID " + configId + " because it is used by one or more platforms.", ErrorCodes.NOT_ALLOWED); - - cfgDao.deleteConfig(configId); - return ApiHttpUtil.createResponse("Config with ID " + configId + " deleted"); + if (configId == null) + { + throw new WebAppException(HttpServletResponse.SC_BAD_REQUEST, + "Missing required configid parameter."); } - } + try + { + DatabaseIO dbIo = getLegacyDatabase(); + PlatformConfig pc = new PlatformConfig(); + pc.setId(DbKey.createDbKey(configId)); + dbIo.readConfig(pc); + + if (pc.numPlatformsUsing > 0) + { + return Response.status(HttpServletResponse.SC_METHOD_NOT_ALLOWED) + .entity(" Cannot delete config with ID " + + configId + " because it is used by one or more platforms.") + .build(); + } + dbIo.deleteConfig(pc); + return Response.status(HttpServletResponse.SC_OK) + .entity("Config with ID " + configId + " deleted") + .build(); + } + catch (DatabaseException ex) + { + throw new DbException("Error deleting config", ex); + } + } } diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/OpenDcsResource.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/OpenDcsResource.java index d5a931a9d..eeebd1c28 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/OpenDcsResource.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/OpenDcsResource.java @@ -22,7 +22,10 @@ import javax.ws.rs.core.Context; import decodes.cwms.CwmsDatabaseProvider; +import decodes.db.Database; import decodes.db.DatabaseException; +import decodes.db.DatabaseIO; +import decodes.tsdb.TimeSeriesDb; import decodes.util.DecodesSettings; import opendcs.opentsdb.OpenTsdbProvider; import org.opendcs.database.DatabaseService; @@ -81,7 +84,18 @@ final OpenDcsDatabase createDb() { throw new IllegalStateException("Error connecting to the database via JNDI", ex); } -// throw new IllegalStateException("Error connecting to the database via JNDI", e); } } + + DatabaseIO getLegacyDatabase() + { + return createDb().getLegacyDatabase(Database.class).map(Database::getDbIo) + .orElseThrow(() -> new UnsupportedOperationException("Endpoint is unsupported by the OpenDCS REST API.")); + } + + TimeSeriesDb getLegacyTimeseriesDB() + { + return createDb().getLegacyDatabase(TimeSeriesDb.class) + .orElseThrow(() -> new UnsupportedOperationException("Endpoint is unsupported by the OpenDCS REST API.")); + } } diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java new file mode 100644 index 000000000..ae0e31bc1 --- /dev/null +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java @@ -0,0 +1,196 @@ +package org.opendcs.odcsapi.res; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import decodes.db.DecodesScript; +import decodes.db.PlatformConfig; +import decodes.db.PlatformConfigList; +import decodes.db.Poly5Converter; +import decodes.db.ScriptSensor; +import decodes.db.UnitConverter; +import decodes.sql.DbKey; +import org.junit.jupiter.api.Test; +import org.opendcs.odcsapi.beans.ApiConfigRef; +import org.opendcs.odcsapi.beans.ApiConfigScript; +import org.opendcs.odcsapi.beans.ApiConfigScriptSensor; +import org.opendcs.odcsapi.beans.ApiPlatformConfig; +import org.opendcs.odcsapi.beans.ApiUnitConverter; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.opendcs.odcsapi.res.ConfigResources.map; + +final class ConfigResourcesTest +{ + @Test + void testPlatformConfigListMap() throws Exception + { + PlatformConfigList pcl = new PlatformConfigList(); + PlatformConfig config = new PlatformConfig(); + config.numPlatformsUsing = 11; + config.configName = "Test config"; + config.description = "Platform description"; + config.setId(DbKey.createDbKey(5899L)); + pcl.add(config); + + List configRefs = map(pcl); + + assertNotNull(configRefs); + assertEquals(config.numPlatformsUsing, configRefs.get(0).getNumPlatforms()); + assertEquals(config.configName, configRefs.get(0).getName()); + assertEquals(config.description, configRefs.get(0).getDescription()); + assertEquals(config.getId().getValue(), configRefs.get(0).getConfigId()); + } + + @Test + void testPlatformConfigMap() throws Exception + { + PlatformConfig config = new PlatformConfig(); + config.numPlatformsUsing = 11; + config.configName = "Test config"; + config.description = "Platform description"; + config.setId(DbKey.createDbKey(5899L)); + + ApiPlatformConfig apiConfig = map(config); + + assertNotNull(apiConfig); + assertEquals(config.numPlatformsUsing, apiConfig.getNumPlatforms()); + assertEquals(config.configName, apiConfig.getName()); + assertEquals(config.description, apiConfig.getDescription()); + assertEquals(config.getId().getValue(), apiConfig.getConfigId()); + } + + @Test + void testApiPlatformConfigMap() throws Exception + { + ApiPlatformConfig apiConfig = new ApiPlatformConfig(); + apiConfig.setNumPlatforms(11); + apiConfig.setName("Test config"); + apiConfig.setDescription("Platform description"); + apiConfig.setScripts(scriptListBuilder()); + apiConfig.setConfigId(5899L); + + PlatformConfig config = map(apiConfig); + assertNotNull(config); + assertEquals(apiConfig.getNumPlatforms(), config.numPlatformsUsing); + assertEquals(apiConfig.getName(), config.configName); + assertEquals(apiConfig.getDescription(), config.description); + assertEquals(apiConfig.getConfigId(), config.getId().getValue()); + for (Iterator scriptName = config.getScripts(); scriptName.hasNext(); ) + { + DecodesScript script = scriptName.next(); + assertEquals(apiConfig.getScripts().get(0).getName(), script.scriptName); + for (ScriptSensor sensor : script.scriptSensors) + { + assertEquals(apiConfig.getScripts().get(0).getScriptSensors().get(0).getSensorNumber(), sensor.sensorNumber); + assertMatch(apiConfig.getScripts().get(0).getScriptSensors().get(0).getUnitConverter(), (Poly5Converter) sensor.execConverter); + } + } + } + + @Test + void testApiConfigScriptMap() throws Exception + { + List scripts = scriptListBuilder(); + + Vector decodesScripts = map(scripts, new PlatformConfig()); + + assertNotNull(decodesScripts); + assertEquals(scripts.size(), decodesScripts.size()); + assertEquals(scripts.get(0).getName(), decodesScripts.get(0).scriptName); + for (ScriptSensor sensor : decodesScripts.get(0).scriptSensors) + { + assertEquals(scripts.get(0).getScriptSensors().get(0).getSensorNumber(), sensor.sensorNumber); + assertMatch(scripts.get(0).getScriptSensors().get(0).getUnitConverter(), (Poly5Converter) sensor.execConverter); + } + } + + @Test + void testApiConfigScriptSensorMap() + { + ApiConfigScriptSensor sensor = new ApiConfigScriptSensor(); + sensor.setSensorNumber(1); + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setUcId(1234L); + unitConverter.setAlgorithm("None"); + unitConverter.setFromAbbr("ft"); + unitConverter.setToAbbr("m"); + unitConverter.setA(1.0); + unitConverter.setB(2.0); + unitConverter.setC(3.0); + unitConverter.setD(4.0); + unitConverter.setE(5.0); + unitConverter.setF(6.0); + sensor.setUnitConverter(unitConverter); + + ScriptSensor decodesSensor = map(sensor); + + assertNotNull(decodesSensor); + assertEquals(sensor.getSensorNumber(), decodesSensor.sensorNumber); + assertMatch(sensor.getUnitConverter(), (Poly5Converter) decodesSensor.execConverter); + } + + @Test + void testApiUnitConverterMap() throws Exception + { + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setUcId(1234L); + unitConverter.setAlgorithm("None"); + unitConverter.setFromAbbr("ft"); + unitConverter.setToAbbr("m"); + unitConverter.setA(1.0); + unitConverter.setB(2.0); + unitConverter.setC(3.0); + unitConverter.setD(4.0); + unitConverter.setE(5.0); + unitConverter.setF(6.0); + + UnitConverter decodesUc = map(unitConverter); + + assertNotNull(decodesUc); + assertEquals(unitConverter.getFromAbbr(), decodesUc.getFromAbbr()); + assertEquals(unitConverter.getToAbbr(), decodesUc.getToAbbr()); + assertEquals(3545706.0, decodesUc.convert(20.0)); + } + + private static void assertMatch(ApiUnitConverter apiUc, Poly5Converter decodesUc) + { + assertEquals(apiUc.getFromAbbr(), decodesUc.getFromAbbr()); + assertEquals(apiUc.getToAbbr(), decodesUc.getToAbbr()); + assertEquals(123456.0, decodesUc.convert(10.0)); + } + + private static ArrayList scriptListBuilder() + { + ArrayList configScriptList = new ArrayList<>(); + ApiConfigScript script = new ApiConfigScript(); + script.setName("Test script"); + script.setScriptSensors(buildScriptSensorList()); + configScriptList.add(script); + return configScriptList; + } + + private static ArrayList buildScriptSensorList() + { + ArrayList scriptSensorList = new ArrayList<>(); + ApiConfigScriptSensor scriptSensor = new ApiConfigScriptSensor(); + scriptSensor.setSensorNumber(1); + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setUcId(1234L); + unitConverter.setAlgorithm("None"); + unitConverter.setFromAbbr("ft"); + unitConverter.setToAbbr("m"); + unitConverter.setA(1.0); + unitConverter.setB(2.0); + unitConverter.setC(3.0); + unitConverter.setD(4.0); + unitConverter.setE(5.0); + unitConverter.setF(6.0); + scriptSensor.setUnitConverter(unitConverter); + scriptSensorList.add(scriptSensor); + return scriptSensorList; + } +} diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/BaseIT.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/BaseIT.java index 2121b2d15..e07640a48 100644 --- a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/BaseIT.java +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/BaseIT.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; +import java.util.Base64; import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.ObjectMapper; @@ -36,6 +37,8 @@ class BaseIT { + protected static String authHeader = null; + T getDtoFromResource(String filename, Class dtoType) throws Exception { try(InputStream inputStream = getClass().getClassLoader() @@ -121,4 +124,35 @@ void authenticate(SessionFilter sessionFilter) ; } } + + void logout(SessionFilter sessionFilter) + { + if (DatabaseSetupExtension.getCurrentDbType() == DbType.OPEN_TSDB) + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .header("Authorization", authHeader) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("logout") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + } + } + + public static void setUpCreds() + { + String authHeaderPrefix = "Basic "; + Credentials adminCreds = new Credentials(); + adminCreds.setPassword(System.getProperty("DB_PASSWORD")); + adminCreds.setUsername(System.getProperty("DB_USERNAME")); + String credentialsJson = Base64.getEncoder() + .encodeToString(String.format("%s:%s", adminCreds.getUsername(), adminCreds.getPassword()).getBytes()); + authHeader = authHeaderPrefix + credentialsJson; + } } diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java new file mode 100644 index 000000000..f1d8dea4f --- /dev/null +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java @@ -0,0 +1,302 @@ +package org.opendcs.odcsapi.res.it; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.ObjectMapper; +import decodes.sql.DbKey; +import io.restassured.filter.log.LogDetail; +import io.restassured.filter.session.SessionFilter; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.opendcs.odcsapi.beans.ApiConfigScript; +import org.opendcs.odcsapi.beans.ApiConfigScriptSensor; +import org.opendcs.odcsapi.beans.ApiConfigSensor; +import org.opendcs.odcsapi.beans.ApiPlatformConfig; +import org.opendcs.odcsapi.beans.ApiUnitConverter; +import org.opendcs.odcsapi.fixtures.DatabaseContextProvider; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +@Tag("integration") +@ExtendWith(DatabaseContextProvider.class) +final class ConfigResourcesIT extends BaseIT +{ + private static SessionFilter sessionFilter; + private static Long configId; + private static final ObjectMapper mapper = new ObjectMapper(); + + @BeforeEach + void setUp() throws Exception + { + setUpCreds(); + sessionFilter = new SessionFilter(); + + authenticate(sessionFilter); + + ApiPlatformConfig config = new ApiPlatformConfig(); + config.setDescription("Test Platform"); + config.setNumPlatforms(1); + config.setName("Test Platform"); + ArrayList sensors = new ArrayList<>(); + ApiConfigSensor sensor = new ApiConfigSensor(); + sensor.setSensorName("Test Sensor"); + sensor.setAbsoluteMax(100.0); + sensor.setAbsoluteMin(0.0); + sensor.setRecordingInterval(900); + sensor.setTimeOfFirstSample(0); + Properties properties = new Properties(); + properties.setProperty("site", "Test Site"); + sensor.setProperties(properties); + HashMap dataTypes = new HashMap<>(); + dataTypes.put("Test Type", "Test Units"); + sensor.setDataTypes(dataTypes); + sensors.add(sensor); + config.setConfigSensors(sensors); + ArrayList scripts = new ArrayList<>(); + ApiConfigScript script = new ApiConfigScript(); + script.setName("Test Script"); + ArrayList scriptSensors = new ArrayList<>(); + ApiConfigScriptSensor scriptSensor = new ApiConfigScriptSensor(); + // TODO: Tie this into the unit converter endpoint. Causes NPE if converter with ID is not in DB + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setAlgorithm("x * 100 + 32"); + unitConverter.setFromAbbr("C"); + unitConverter.setToAbbr("F"); + unitConverter.setA(100.0); + unitConverter.setB(32.0); + Long convId = storeConverter(unitConverter); + unitConverter.setUcId(convId); + scriptSensor.setUnitConverter(unitConverter); + scriptSensors.add(scriptSensor); + script.setScriptSensors(scriptSensors); + scripts.add(script); + config.setScripts(scripts); + + String configJson = mapper.writeValueAsString(config); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .body(configJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("config") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + configId = response.body().jsonPath().getLong("configId"); + } + + @AfterEach + void tearDown() + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .queryParam("configid", configId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("config") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + ; + + logout(sessionFilter); + } + + @TestTemplate + void testGetConfigRefs() + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("configrefs") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + ; + } + + @TestTemplate + void testGetConfig() + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .queryParam("configid", configId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("config") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + ; + } + + @TestTemplate + void testPostAndDeleteConfig() throws Exception + { + ApiPlatformConfig config = new ApiPlatformConfig(); + config.setDescription("Test Platform 1"); + config.setNumPlatforms(1); + config.setName("Test Platform 2"); + ArrayList sensors = new ArrayList<>(); + ApiConfigSensor sensor = new ApiConfigSensor(); + sensor.setSensorName("Test Sensor 1"); + sensor.setAbsoluteMax(120.0); + sensor.setAbsoluteMin(2.0); + sensor.setRecordingInterval(90); + sensor.setTimeOfFirstSample(10000000); + Properties properties = new Properties(); + properties.setProperty("site", "Test Site 1"); + sensor.setProperties(properties); + HashMap dataTypes = new HashMap<>(); + dataTypes.put("Test Type", "Test Units 1"); + sensor.setDataTypes(dataTypes); + sensors.add(sensor); + config.setConfigSensors(sensors); + ArrayList scripts = new ArrayList<>(); + ApiConfigScript script = new ApiConfigScript(); + script.setName("Test Script"); + ArrayList scriptSensors = new ArrayList<>(); + // TODO: Tie this into the unit converter endpoint. Causes NPE if converter with ID is not in DB + ApiConfigScriptSensor scriptSensor = new ApiConfigScriptSensor(); + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setAlgorithm("x * A"); + unitConverter.setFromAbbr("m"); + unitConverter.setToAbbr("ft"); + unitConverter.setA(3.28084); + Long convId = storeConverter(unitConverter); + unitConverter.setUcId(convId); + scriptSensor.setUnitConverter(unitConverter); + scriptSensor.setSensorNumber(convId.intValue()); + scriptSensors.add(scriptSensor); + script.setScriptSensors(scriptSensors); + scripts.add(script); + config.setScripts(scripts); + + String configJson = mapper.writeValueAsString(config); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .body(configJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("config") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + Long newConfigId = response.body().jsonPath().getLong("configId"); + + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .queryParam("configid", newConfigId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("config") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + ; + } + + private Long storeConverter(ApiUnitConverter unitConverter) throws Exception + { + String converterJson = mapper.writeValueAsString(unitConverter); + + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .body(converterJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("euconv") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + ; + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("euconvlist") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + for (int i = 0; i < response.body().jsonPath().getList("").size(); i++) + { + if (response.body().jsonPath().getString("[" + i + "].fromAbbr").equals(unitConverter.getFromAbbr()) + && response.body().jsonPath().getString("[" + i + "].toAbbr").equals(unitConverter.getToAbbr())) + { + return response.body().jsonPath().getLong("[" + i + "].ucId"); + } + } + + return DbKey.NullKey.getValue(); + } +} From 8ba8cf9e79b5a87c18697f34cd0715f3adf86b9b Mon Sep 17 00:00:00 2001 From: zack-rma Date: Mon, 30 Dec 2024 16:41:12 -0800 Subject: [PATCH 2/3] Updated IT, fixed mapping bugs --- .../opendcs/odcsapi/res/ConfigResources.java | 28 +++++++-- .../odcsapi/res/ConfigResourcesTest.java | 34 ++++++++++- .../odcsapi/res/it/ConfigResourcesIT.java | 57 ------------------- 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java index 1ef104ded..4c7369d35 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java @@ -45,6 +45,7 @@ import decodes.db.Poly5Converter; import decodes.db.ScriptSensor; import decodes.db.UnitConverter; +import decodes.db.UnitConverterDb; import decodes.sql.DbKey; import org.opendcs.odcsapi.beans.ApiConfigRef; import org.opendcs.odcsapi.beans.ApiConfigScript; @@ -226,16 +227,30 @@ static Vector map(List scripts, PlatformConfig c } return decodesScripts; } - catch(DecodesScriptException | IOException ex) + catch(DecodesScriptException | IOException | DatabaseException ex) { throw new DbException("Error mapping scripts", ex); } } - static ScriptSensor map(ApiConfigScriptSensor sensor) + static ScriptSensor map(ApiConfigScriptSensor sensor) throws DatabaseException { ScriptSensor scriptSensor = new ScriptSensor(null, sensor.getSensorNumber()); scriptSensor.execConverter = map(sensor.getUnitConverter()); + UnitConverterDb rawConv = new UnitConverterDb(sensor.getUnitConverter().getFromAbbr(), + sensor.getUnitConverter().getToAbbr()); + rawConv.algorithm = sensor.getUnitConverter().getAlgorithm(); + if (sensor.getUnitConverter().getUcId() != null) + { + rawConv.setId(DbKey.createDbKey(sensor.getUnitConverter().getUcId())); + } + else + { + rawConv.setId(DbKey.NullKey); + } + ApiUnitConverter uc = sensor.getUnitConverter(); + rawConv.coefficients = coefficientMap(uc); + scriptSensor.rawConverter = rawConv; if (sensor.getUnitConverter().getUcId() != null) { scriptSensor.setUnitConverterId(DbKey.createDbKey(sensor.getUnitConverter().getUcId())); @@ -252,6 +267,12 @@ static UnitConverter map(ApiUnitConverter unitConverter) EngineeringUnit from = EngineeringUnit.getEngineeringUnit(unitConverter.getFromAbbr()); EngineeringUnit to = EngineeringUnit.getEngineeringUnit(unitConverter.getToAbbr()); Poly5Converter pc = new Poly5Converter(from, to); + pc.setCoefficients(coefficientMap(unitConverter)); + return pc; + } + + static double[] coefficientMap(ApiUnitConverter unitConverter) + { double[] coeffs = new double[6]; coeffs[0] = unitConverter.getA() != null ? unitConverter.getA() : 0.0; coeffs[1] = unitConverter.getB() != null ? unitConverter.getB() : 0.0; @@ -259,8 +280,7 @@ static UnitConverter map(ApiUnitConverter unitConverter) coeffs[3] = unitConverter.getD() != null ? unitConverter.getD() : 0.0; coeffs[4] = unitConverter.getE() != null ? unitConverter.getE() : 0.0; coeffs[5] = unitConverter.getF() != null ? unitConverter.getF() : 0.0; - pc.setCoefficients(coeffs); - return pc; + return coeffs; } diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java index ae0e31bc1..59507194c 100644 --- a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/ConfigResourcesTest.java @@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.opendcs.odcsapi.res.ConfigResources.coefficientMap; import static org.opendcs.odcsapi.res.ConfigResources.map; final class ConfigResourcesTest @@ -109,7 +110,7 @@ void testApiConfigScriptMap() throws Exception } @Test - void testApiConfigScriptSensorMap() + void testApiConfigScriptSensorMap() throws Exception { ApiConfigScriptSensor sensor = new ApiConfigScriptSensor(); sensor.setSensorNumber(1); @@ -131,6 +132,16 @@ void testApiConfigScriptSensorMap() assertNotNull(decodesSensor); assertEquals(sensor.getSensorNumber(), decodesSensor.sensorNumber); assertMatch(sensor.getUnitConverter(), (Poly5Converter) decodesSensor.execConverter); + assertEquals(sensor.getUnitConverter().getFromAbbr(), decodesSensor.rawConverter.fromAbbr); + assertEquals(sensor.getUnitConverter().getToAbbr(), decodesSensor.rawConverter.toAbbr); + assertEquals(sensor.getUnitConverter().getA(), decodesSensor.rawConverter.coefficients[0]); + assertEquals(sensor.getUnitConverter().getB(), decodesSensor.rawConverter.coefficients[1]); + assertEquals(sensor.getUnitConverter().getC(), decodesSensor.rawConverter.coefficients[2]); + assertEquals(sensor.getUnitConverter().getD(), decodesSensor.rawConverter.coefficients[3]); + assertEquals(sensor.getUnitConverter().getE(), decodesSensor.rawConverter.coefficients[4]); + assertEquals(sensor.getUnitConverter().getF(), decodesSensor.rawConverter.coefficients[5]); + assertEquals(sensor.getUnitConverter().getUcId(), decodesSensor.rawConverter.getId().getValue()); + assertEquals(sensor.getUnitConverter().getAlgorithm(), decodesSensor.rawConverter.algorithm); } @Test @@ -156,6 +167,27 @@ void testApiUnitConverterMap() throws Exception assertEquals(3545706.0, decodesUc.convert(20.0)); } + @Test + void testCoefficientMap() + { + ApiUnitConverter unitConverter = new ApiUnitConverter(); + unitConverter.setA(1.0); + unitConverter.setB(2.0); + unitConverter.setC(3.0); + unitConverter.setD(4.0); + unitConverter.setE(5.0); + unitConverter.setF(6.0); + + double[] coefficients = coefficientMap(unitConverter); + + assertEquals(unitConverter.getA(), coefficients[0]); + assertEquals(unitConverter.getB(), coefficients[1]); + assertEquals(unitConverter.getC(), coefficients[2]); + assertEquals(unitConverter.getD(), coefficients[3]); + assertEquals(unitConverter.getE(), coefficients[4]); + assertEquals(unitConverter.getF(), coefficients[5]); + } + private static void assertMatch(ApiUnitConverter apiUc, Poly5Converter decodesUc) { assertEquals(apiUc.getFromAbbr(), decodesUc.getFromAbbr()); diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java index f1d8dea4f..0bc765413 100644 --- a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/ConfigResourcesIT.java @@ -7,7 +7,6 @@ import javax.ws.rs.core.MediaType; import com.fasterxml.jackson.databind.ObjectMapper; -import decodes.sql.DbKey; import io.restassured.filter.log.LogDetail; import io.restassured.filter.session.SessionFilter; import io.restassured.response.ExtractableResponse; @@ -67,15 +66,12 @@ void setUp() throws Exception script.setName("Test Script"); ArrayList scriptSensors = new ArrayList<>(); ApiConfigScriptSensor scriptSensor = new ApiConfigScriptSensor(); - // TODO: Tie this into the unit converter endpoint. Causes NPE if converter with ID is not in DB ApiUnitConverter unitConverter = new ApiUnitConverter(); unitConverter.setAlgorithm("x * 100 + 32"); unitConverter.setFromAbbr("C"); unitConverter.setToAbbr("F"); unitConverter.setA(100.0); unitConverter.setB(32.0); - Long convId = storeConverter(unitConverter); - unitConverter.setUcId(convId); scriptSensor.setUnitConverter(unitConverter); scriptSensors.add(scriptSensor); script.setScriptSensors(scriptSensors); @@ -195,17 +191,13 @@ void testPostAndDeleteConfig() throws Exception ApiConfigScript script = new ApiConfigScript(); script.setName("Test Script"); ArrayList scriptSensors = new ArrayList<>(); - // TODO: Tie this into the unit converter endpoint. Causes NPE if converter with ID is not in DB ApiConfigScriptSensor scriptSensor = new ApiConfigScriptSensor(); ApiUnitConverter unitConverter = new ApiUnitConverter(); unitConverter.setAlgorithm("x * A"); unitConverter.setFromAbbr("m"); unitConverter.setToAbbr("ft"); unitConverter.setA(3.28084); - Long convId = storeConverter(unitConverter); - unitConverter.setUcId(convId); scriptSensor.setUnitConverter(unitConverter); - scriptSensor.setSensorNumber(convId.intValue()); scriptSensors.add(scriptSensor); script.setScriptSensors(scriptSensors); scripts.add(script); @@ -250,53 +242,4 @@ void testPostAndDeleteConfig() throws Exception .statusCode(is(HttpServletResponse.SC_OK)) ; } - - private Long storeConverter(ApiUnitConverter unitConverter) throws Exception - { - String converterJson = mapper.writeValueAsString(unitConverter); - - given() - .log().ifValidationFails(LogDetail.ALL, true) - .accept(MediaType.APPLICATION_JSON) - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", authHeader) - .filter(sessionFilter) - .body(converterJson) - .when() - .redirects().follow(true) - .redirects().max(3) - .post("euconv") - .then() - .log().ifValidationFails(LogDetail.ALL, true) - .assertThat() - .statusCode(is(HttpServletResponse.SC_OK)) - ; - - ExtractableResponse response = given() - .log().ifValidationFails(LogDetail.ALL, true) - .accept(MediaType.APPLICATION_JSON) - .header("Authorization", authHeader) - .filter(sessionFilter) - .when() - .redirects().follow(true) - .redirects().max(3) - .get("euconvlist") - .then() - .log().ifValidationFails(LogDetail.ALL, true) - .assertThat() - .statusCode(is(HttpServletResponse.SC_OK)) - .extract() - ; - - for (int i = 0; i < response.body().jsonPath().getList("").size(); i++) - { - if (response.body().jsonPath().getString("[" + i + "].fromAbbr").equals(unitConverter.getFromAbbr()) - && response.body().jsonPath().getString("[" + i + "].toAbbr").equals(unitConverter.getToAbbr())) - { - return response.body().jsonPath().getLong("[" + i + "].ucId"); - } - } - - return DbKey.NullKey.getValue(); - } } From d08250176c78e33f68a79dc3d2e302aa4ad09eb9 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Tue, 31 Dec 2024 16:23:43 -0800 Subject: [PATCH 3/3] Added TODO item for broken method implementation --- .../src/main/java/org/opendcs/odcsapi/res/ConfigResources.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java index 4c7369d35..29afd5782 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/ConfigResources.java @@ -121,7 +121,7 @@ public Response getConfig(@QueryParam("configid") Long configId) throws WebAppEx DatabaseIO dbIo = getLegacyDatabase(); PlatformConfig config = new PlatformConfig(); config.setId(DbKey.createDbKey(configId)); - dbIo.readConfig(config); + dbIo.readConfig(config); // TODO: This method does not return any data. Investigate why. return Response.status(HttpServletResponse.SC_OK).entity(map(config)).build(); } catch (DatabaseException ex)