diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/DatabaseItemNotFoundException.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/DatabaseItemNotFoundException.java index 7b66e8f97..3678c77ce 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/DatabaseItemNotFoundException.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/DatabaseItemNotFoundException.java @@ -19,31 +19,31 @@ public final class DatabaseItemNotFoundException extends WebAppException { - /** detailed error msg */ - private String errMessage = ""; - - public DatabaseItemNotFoundException(String errMessage) - { - super(HttpServletResponse.SC_NOT_FOUND, errMessage); - this.errMessage = errMessage; - } - - public DatabaseItemNotFoundException(String errMessage, Throwable cause) - { - super(HttpServletResponse.SC_NOT_FOUND, errMessage, cause); - this.errMessage = errMessage; - } - - @Override - public int getStatus() - { - return HttpServletResponse.SC_NOT_FOUND; - } - - @Override - public String getErrMessage() - { - return errMessage; - } + /** detailed error msg */ + private String errMessage = ""; + + public DatabaseItemNotFoundException(String errMessage) + { + super(HttpServletResponse.SC_NOT_FOUND, errMessage); + this.errMessage = errMessage; + } + + public DatabaseItemNotFoundException(String errMessage, Throwable cause) + { + super(HttpServletResponse.SC_NOT_FOUND, errMessage, cause); + this.errMessage = errMessage; + } + + @Override + public int getStatus() + { + return HttpServletResponse.SC_NOT_FOUND; + } + + @Override + public String getErrMessage() + { + return errMessage; + } } \ No newline at end of file diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/MissingParameterException.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/MissingParameterException.java index 7f8f4c533..90590c6b1 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/MissingParameterException.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/errorhandling/MissingParameterException.java @@ -19,25 +19,25 @@ public final class MissingParameterException extends WebAppException { - /** detailed error msg */ - private String errMessage = ""; + /** detailed error msg */ + private String errMessage = ""; - public MissingParameterException(String errMessage) - { - super(HttpServletResponse.SC_BAD_REQUEST, errMessage); - this.errMessage = errMessage; - } + public MissingParameterException(String errMessage) + { + super(HttpServletResponse.SC_BAD_REQUEST, errMessage); + this.errMessage = errMessage; + } - @Override - public int getStatus() - { - return HttpServletResponse.SC_BAD_REQUEST; - } + @Override + public int getStatus() + { + return HttpServletResponse.SC_BAD_REQUEST; + } - @Override - public String getErrMessage() - { - return errMessage; - } + @Override + public String getErrMessage() + { + return errMessage; + } -} +} \ No newline at end of file diff --git a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/RoutingResources.java b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/RoutingResources.java index 0a734b044..b2981d682 100644 --- a/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/RoutingResources.java +++ b/opendcs-rest-api/src/main/java/org/opendcs/odcsapi/res/RoutingResources.java @@ -15,10 +15,17 @@ package org.opendcs.odcsapi.res; -import java.sql.SQLException; -import java.util.logging.Logger; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; +import java.util.Vector; +import java.util.stream.Collectors; + import javax.annotation.security.RolesAllowed; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -32,19 +39,42 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import decodes.db.DataSource; +import decodes.db.DatabaseException; +import decodes.db.DatabaseIO; +import decodes.db.RoutingSpec; +import decodes.db.RoutingSpecList; +import decodes.db.RoutingStatus; +import decodes.db.ScheduleEntry; +import decodes.db.ScheduleEntryStatus; +import decodes.db.ValueNotFoundException; +import decodes.polling.DacqEvent; +import decodes.sql.DbKey; +import decodes.tsdb.DbIoException; +import decodes.tsdb.IntervalCodes; +import ilex.util.Logger; +import opendcs.dai.DacqEventDAI; +import opendcs.dai.IntervalDAI; +import opendcs.dai.ScheduleEntryDAI; +import opendcs.opentsdb.Interval; +import org.opendcs.odcsapi.beans.ApiDacqEvent; import org.opendcs.odcsapi.beans.ApiRouting; +import org.opendcs.odcsapi.beans.ApiRoutingExecStatus; +import org.opendcs.odcsapi.beans.ApiRoutingRef; +import org.opendcs.odcsapi.beans.ApiRoutingStatus; import org.opendcs.odcsapi.beans.ApiScheduleEntry; -import org.opendcs.odcsapi.dao.ApiRoutingDAO; +import org.opendcs.odcsapi.beans.ApiScheduleEntryRef; import org.opendcs.odcsapi.dao.DbException; -import org.opendcs.odcsapi.errorhandling.ErrorCodes; +import org.opendcs.odcsapi.errorhandling.DatabaseItemNotFoundException; +import org.opendcs.odcsapi.errorhandling.MissingParameterException; import org.opendcs.odcsapi.errorhandling.WebAppException; -import org.opendcs.odcsapi.hydrojson.DbInterface; import org.opendcs.odcsapi.util.ApiConstants; -import org.opendcs.odcsapi.util.ApiHttpUtil; @Path("/") -public final class RoutingResources +public final class RoutingResources extends OpenDcsResource { + private static final String LAST_DACQ_ATTRIBUTE = "last-dacq-event-id"; + @Context private HttpServletRequest request; @Context private HttpHeaders httpHeaders; @@ -54,32 +84,125 @@ public final class RoutingResources @RolesAllowed({ApiConstants.ODCS_API_GUEST}) public Response getRoutingRefs() throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("getRoutingRefs"); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + DatabaseIO dbIo = null; + try + { + dbIo = getLegacyDatabase(); + RoutingSpecList rsList = new RoutingSpecList(); + dbIo.readRoutingSpecList(rsList); + return Response.status(HttpServletResponse.SC_OK) + .entity(map(rsList)).build(); + } + catch(DatabaseException e) { - return ApiHttpUtil.createResponse(dao.getRoutingRefs()); + throw new DbException("Unable to retrieve routing reference list", e); + } + finally + { + if (dbIo != null) + { + dbIo.close(); + } } } + static List map(RoutingSpecList rsList) + { + List refs = new ArrayList<>(); + rsList.getList().forEach(rs -> { + ApiRoutingRef ref = new ApiRoutingRef(); + if (rs.getId() != null) + { + ref.setRoutingId(rs.getId().getValue()); + } + else + { + ref.setRoutingId(DbKey.NullKey.getValue()); + } + ref.setName(rs.getName()); + ref.setDestination(rs.consumerArg); + if (rs.dataSource != null) + { + ref.setDataSourceName(rs.dataSource.getName()); + } + ref.setLastModified(rs.lastModifyTime); + refs.add(ref); + }); + return refs; + } + @GET @Path("routing") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_GUEST}) public Response getRouting(@QueryParam("routingid") Long routingId) - throws WebAppException, DbException, SQLException + throws WebAppException, DbException { - + if (routingId == null) - throw new WebAppException(ErrorCodes.MISSING_ID, - "Missing required routingid parameter."); - - Logger.getLogger(ApiConstants.loggerName).fine("getRouting id=" + routingId); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) { - return ApiHttpUtil.createResponse(dao.getRouting(routingId)); + throw new MissingParameterException("Missing required routingid parameter."); + } + + DatabaseIO dbIo = null; + try + { + dbIo = getLegacyDatabase(); + RoutingSpec spec = new RoutingSpec(); + spec.setId(DbKey.createDbKey(routingId)); + dbIo.readRoutingSpec(spec); + return Response.status(HttpServletResponse.SC_OK) + .entity(map(spec)).build(); + } + catch(DatabaseException e) + { + if (e.getCause() instanceof ValueNotFoundException) + { + throw new DatabaseItemNotFoundException("RoutingSpec with ID " + routingId + " not found"); + } + throw new DbException("Unable to retrieve routing spec by ID", e); } + finally + { + if (dbIo != null) + { + dbIo.close(); + } + } + } + + static ApiRouting map(RoutingSpec spec) { + ApiRouting routing = new ApiRouting(); + if (spec.getId() != null) + { + routing.setRoutingId(spec.getId().getValue()); + } + else + { + routing.setRoutingId(DbKey.NullKey.getValue()); + } + routing.setName(spec.getName()); + routing.setLastModified(spec.lastModifyTime); + if (spec.outputTimeZoneAbbr != null) + { + routing.setOutputTZ(spec.outputTimeZoneAbbr); + } + routing.setNetlistNames(new ArrayList<>(spec.networkListNames)); + routing.setOutputFormat(spec.outputFormat); + routing.setEnableEquations(spec.enableEquations); + if (spec.dataSource != null) + { + routing.setDataSourceId(spec.dataSource.getId().getValue()); + routing.setDataSourceName(spec.dataSource.getName()); + } + routing.setSince(spec.sinceTime); + routing.setUntil(spec.untilTime); + routing.setProperties(spec.getProperties()); + routing.setPresGroupName(spec.presentationGroupName); + routing.setProduction(spec.isProduction); + routing.setDestinationArg(spec.consumerArg); + routing.setDestinationType(spec.consumerType); + return routing; } @POST @@ -88,35 +211,123 @@ public Response getRouting(@QueryParam("routingid") Long routingId) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_ADMIN, ApiConstants.ODCS_API_USER}) public Response postRouting(ApiRouting routing) - throws WebAppException, DbException, SQLException + throws DbException + { + DatabaseIO dbIo = null; + try + { + dbIo = getLegacyDatabase(); + RoutingSpec spec = map(routing); + dbIo.writeRoutingSpec(spec); + return Response.status(HttpServletResponse.SC_CREATED).entity(map(spec)).build(); + } + catch(DatabaseException e) + { + throw new DbException("Unable to store routing spec", e); + } + finally + { + if (dbIo != null) + { + dbIo.close(); + } + } + } + + static RoutingSpec map(ApiRouting routing) throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("post routing received routing " + routing.getName() - + " with ID=" + routing.getRoutingId()); - - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + try { - dao.writeRouting(routing); - return ApiHttpUtil.createResponse(routing); + RoutingSpec spec = new RoutingSpec(); + if (routing.getRoutingId() != null) + { + spec.setId(DbKey.createDbKey(routing.getRoutingId())); + } + else + { + spec.setId(DbKey.NullKey); + } + spec.setName(routing.getName()); + spec.usePerformanceMeasurements = false; + spec.lastModifyTime = routing.getLastModified(); + if (routing.getOutputTZ() != null) + { + spec.outputTimeZoneAbbr = routing.getOutputTZ(); + spec.outputTimeZone = TimeZone.getTimeZone(ZoneId.of(routing.getOutputTZ())); + } + routing.getNetlistNames().forEach(spec::addNetworkListName); + spec.outputFormat = routing.getOutputFormat(); + spec.enableEquations = routing.isEnableEquations(); + spec.presentationGroupName = routing.getPresGroupName(); + spec.isProduction = routing.isProduction(); + spec.consumerArg = routing.getDestinationArg(); + spec.consumerType = routing.getDestinationType(); + if (routing.getSince() != null) + { + spec.sinceTime = routing.getSince(); + } + if (routing.getUntil() != null) + { + spec.untilTime = routing.getUntil(); + } + spec.setProperties(routing.getProperties()); + if (routing.getDataSourceId() != null) + { + DataSource dataSource = new DataSource(); + if (routing.getDataSourceId() != null) + { + dataSource.setId(DbKey.createDbKey(routing.getDataSourceId())); + } + else + { + dataSource.setId(DbKey.NullKey); + } + dataSource.setName(routing.getDataSourceName()); + spec.dataSource = dataSource; + } + spec.networkListNames = new Vector<>(routing.getNetlistNames()); + return spec; } + catch(DatabaseException e) + { + throw new DbException("Unable to map routing spec", e); + } + } @DELETE @Path("routing") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) + @RolesAllowed({ApiConstants.ODCS_API_ADMIN, ApiConstants.ODCS_API_USER}) public Response deleteRouting(@QueryParam("routingid") Long routingId) - throws WebAppException, DbException, SQLException + throws DbException, WebAppException { - Logger.getLogger(ApiConstants.loggerName) - .fine("DELETE routing received routingId=" + routingId); - - // Use username and password to attempt to connect to the database - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + if (routingId == null) + { + throw new MissingParameterException("Missing required routingid parameter."); + } + + DatabaseIO dbIo = null; + try { - dao.deleteRouting(routingId); - return ApiHttpUtil.createResponse("RoutingSpec with ID " + routingId + " deleted"); + dbIo = getLegacyDatabase(); + RoutingSpec spec = new RoutingSpec(); + spec.setId(DbKey.createDbKey(routingId)); + dbIo.deleteRoutingSpec(spec); + return Response.status(HttpServletResponse.SC_NO_CONTENT) + .entity("RoutingSpec with ID " + routingId + " deleted").build(); + } + catch(DatabaseException e) + { + throw new DbException("Unable to delete routing spec", e); + } + finally + { + if (dbIo != null) + { + dbIo.close(); + } } } @@ -125,32 +336,69 @@ public Response deleteRouting(@QueryParam("routingid") Long routingId) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_GUEST}) public Response getScheduleRefs() - throws DbException + throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("getScheduleRefs"); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + try (ScheduleEntryDAI dai = getLegacyDatabase().makeScheduleEntryDAO()) + { + List entries = dai.listScheduleEntries(null); + return Response.status(HttpServletResponse.SC_OK) + .entity(entryMap(entries)).build(); + } + catch(DbIoException e) { - return ApiHttpUtil.createResponse(dao.getScheduleRefs()); + throw new DbException("Unable to retrieve schedule entry ref list", e); } } + static List entryMap(List entries) + { + List refs = new ArrayList<>(); + entries.forEach(entry -> { + ApiScheduleEntryRef ref = new ApiScheduleEntryRef(); + if (entry.getId() != null) + { + ref.setSchedEntryId(entry.getId().getValue()); + } + else + { + ref.setSchedEntryId(DbKey.NullKey.getValue()); + } + ref.setEnabled(entry.isEnabled()); + ref.setAppName(entry.getLoadingAppName()); + ref.setName(entry.getName()); + ref.setLastModified(entry.getLastModified()); + ref.setRoutingSpecName(entry.getRoutingSpecName()); + refs.add(ref); + }); + return refs; + } + @GET @Path("schedule") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_GUEST}) - public Response getSchedule(@QueryParam("scheduleid") Long scheduleId) - throws WebAppException, DbException, SQLException + public Response getSchedule(@QueryParam("scheduleid") Long scheduleId) + throws WebAppException, DbException { if (scheduleId == null) - throw new WebAppException(ErrorCodes.MISSING_ID, - "Missing required scheduleid parameter."); - - Logger.getLogger(ApiConstants.loggerName).fine("getSchedule id=" + scheduleId); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) { - return ApiHttpUtil.createResponse(dao.getSchedule(scheduleId)); + throw new MissingParameterException("Missing required scheduleid parameter."); + } + + try (ScheduleEntryDAI dai = getLegacyDatabase().makeScheduleEntryDAO()) + { + ScheduleEntry entry = dai.readScheduleEntry(DbKey.createDbKey(scheduleId)); + if (entry == null) + { + throw new DatabaseItemNotFoundException("ScheduleEntry with ID " + scheduleId + " not found"); + } + return Response.status(HttpServletResponse.SC_OK) + .entity(map(entry)) + .build(); + } + catch(DbIoException e) + { + throw new DbException("Unable to retrieve schedule entry by ID", e); } } @@ -160,36 +408,109 @@ public Response getSchedule(@QueryParam("scheduleid") Long scheduleId) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_ADMIN, ApiConstants.ODCS_API_USER}) public Response postSchedule(ApiScheduleEntry schedule) - throws WebAppException, DbException, SQLException + throws DbException { - Logger.getLogger(ApiConstants.loggerName).fine("post schedule received sched " + schedule.getName() - + " with ID=" + schedule.getSchedEntryId()); - - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + try (ScheduleEntryDAI dai = getLegacyDatabase().makeScheduleEntryDAO()) + { + ScheduleEntry entry = map(schedule); + dai.writeScheduleEntry(entry); + return Response.status(HttpServletResponse.SC_CREATED) + .entity(map(entry)) + .build(); + } + catch (DbIoException e) { - dao.writeSchedule(schedule); - return ApiHttpUtil.createResponse(schedule); + throw new DbException("Unable to store schedule entry", e); } } + static ScheduleEntry map(ApiScheduleEntry schedule) throws DbException + { + try + { + ScheduleEntry entry = new ScheduleEntry(schedule.getName()); + if (schedule.getSchedEntryId() != null) + { + entry.setId(DbKey.createDbKey(schedule.getSchedEntryId())); + } + else + { + entry.setId(DbKey.NullKey); + } + entry.setStartTime(schedule.getStartTime()); + entry.setTimezone(schedule.getTimeZone()); + if (schedule.getAppId() != null) + { + entry.setLoadingAppId(DbKey.createDbKey(schedule.getAppId())); + entry.setLoadingAppName(schedule.getAppName()); + } + if (schedule.getRoutingSpecId() != null) + { + entry.setRoutingSpecId(DbKey.createDbKey(schedule.getRoutingSpecId())); + entry.setRoutingSpecName(schedule.getRoutingSpecName()); + } + entry.setRunInterval(schedule.getRunInterval()); + entry.setLastModified(schedule.getLastModified()); + return entry; + } + catch (DatabaseException e) + { + throw new DbException("Unable to map schedule entry", e); + } + } + + static ApiScheduleEntry map(ScheduleEntry entry) + { + ApiScheduleEntry schedule = new ApiScheduleEntry(); + if (entry.getId() != null) + { + schedule.setSchedEntryId(entry.getId().getValue()); + } + else + { + schedule.setSchedEntryId(DbKey.NullKey.getValue()); + } + schedule.setName(entry.getName()); + schedule.setStartTime(entry.getStartTime()); + schedule.setTimeZone(entry.getTimezone()); + schedule.setEnabled(entry.isEnabled()); + if (entry.getLoadingAppId() != null) + { + schedule.setAppId(entry.getLoadingAppId().getValue()); + schedule.setAppName(entry.getLoadingAppName()); + } + if (entry.getRoutingSpecId() != null) + { + schedule.setRoutingSpecId(entry.getRoutingSpecId().getValue()); + schedule.setRoutingSpecName(entry.getRoutingSpecName()); + } + schedule.setRunInterval(entry.getRunInterval()); + schedule.setLastModified(entry.getLastModified()); + return schedule; + } + @DELETE @Path("schedule") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_ADMIN, ApiConstants.ODCS_API_USER}) public Response deleteSchedule(@QueryParam("scheduleid") Long scheduleId) - throws WebAppException, DbException + throws DbException, WebAppException { - Logger.getLogger(ApiConstants.loggerName) - .fine("DELETE schedule received scheduleId=" + scheduleId); - - // Use username and password to attempt to connect to the database - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + if (scheduleId == null) { - dao.deleteSchedule(scheduleId); - return ApiHttpUtil.createResponse("schedulec with ID " + scheduleId + " deleted"); + throw new MissingParameterException("missing required scheduleid argument."); + } + try (ScheduleEntryDAI dai = getLegacyDatabase().makeScheduleEntryDAO()) + { + ScheduleEntry entry = new ScheduleEntry(DbKey.createDbKey(scheduleId)); + dai.deleteScheduleEntry(entry); + return Response.status(HttpServletResponse.SC_NO_CONTENT) + .entity("Schedule entry with ID " + scheduleId + " deleted").build(); + } + catch (DbIoException e) + { + throw new DbException(String.format("Unable to delete schedule entry by ID: %s", scheduleId), e); } } @@ -199,14 +520,67 @@ public Response deleteSchedule(@QueryParam("scheduleid") Long scheduleId) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_GUEST}) public Response getRoutingStats() - throws WebAppException, DbException + throws DbException + { + DatabaseIO dbIo = null; + try + { + dbIo = getLegacyDatabase(); + return Response.status(HttpServletResponse.SC_OK) + .entity(map(dbIo.readRoutingSpecStatus())).build(); + } + catch (DatabaseException e) + { + throw new DbException("Unable to retrieve routing status", e); + } + finally + { + if (dbIo != null) + { + dbIo.close(); + } + } + } + + static List map(List entries) { - Logger.getLogger(ApiConstants.loggerName).fine("getRoutingStats"); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + List refs = new ArrayList<>(); + for (RoutingStatus entry : entries) { - return ApiHttpUtil.createResponse(dao.getRsStatus()); + ApiRoutingStatus status = new ApiRoutingStatus(); + status.setEnabled(entry.isEnabled()); + status.setName(entry.getName()); + if (entry.getRoutingSpecId() != null) + { + status.setRoutingSpecId(entry.getRoutingSpecId().getValue()); + } + else + { + status.setRoutingSpecId(DbKey.NullKey.getValue()); + } + status.setLastActivity(entry.getLastActivityTime()); + status.setRunInterval(entry.getRunInterval()); + if (entry.getAppId() != null) + { + status.setAppId(entry.getAppId().getValue()); + } + status.setAppName(entry.getAppName()); + status.setManual(entry.isManual()); + status.setLastMsgTime(entry.getLastMessageTime()); + status.setNumErrors(entry.getNumDecodesErrors()); + status.setNumMessages(entry.getNumMessages()); + if (entry.getScheduleEntryId() != null) + { + status.setScheduleEntryId(entry.getScheduleEntryId().getValue()); + } + else + { + status.setScheduleEntryId(DbKey.NullKey.getValue()); + } + refs.add(status); } + + return refs; } @GET @@ -214,33 +588,170 @@ public Response getRoutingStats() @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_GUEST}) public Response getRoutingExecStatus(@QueryParam("scheduleentryid") Long scheduleEntryId) - throws WebAppException, DbException + throws WebAppException, DbException { if (scheduleEntryId == null) - throw new WebAppException(ErrorCodes.MISSING_ID, "missing required scheduleentryid argument."); - - Logger.getLogger(ApiConstants.loggerName).fine("getRoutingExecStatus"); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) { - return ApiHttpUtil.createResponse(dao.getRoutingExecStatus(scheduleEntryId)); + throw new MissingParameterException("Missing required scheduleentryid argument."); + } + + try (ScheduleEntryDAI dai = getLegacyDatabase().makeScheduleEntryDAO()) + { + ScheduleEntry entry = new ScheduleEntry(DbKey.createDbKey(scheduleEntryId)); + return Response.status(HttpServletResponse.SC_OK) + .entity(statusMap(dai.readScheduleStatus(entry))).build(); + } + catch (DbIoException e) + { + throw new DbException("Unable to retrieve routing exec status", e); } } + static ArrayList statusMap(ArrayList statuses) + { + // Note: Routing spec id is not mapped here! + ArrayList execStatuses = new ArrayList<>(); + for (ScheduleEntryStatus status : statuses) + { + ApiRoutingExecStatus execStatus = new ApiRoutingExecStatus(); + if (status.getScheduleEntryId() != null) + { + execStatus.setScheduleEntryId(status.getScheduleEntryId().getValue()); + } + else + { + execStatus.setScheduleEntryId(DbKey.NullKey.getValue()); + } + execStatus.setHostname(status.getHostname()); + execStatus.setNumErrors(status.getNumDecodesErrors()); + execStatus.setRunStatus(status.getRunStatus()); + execStatus.setRunStop(status.getRunStop()); + execStatus.setLastMsgTime(status.getLastMessageTime()); + execStatus.setRunStart(status.getRunStart()); + execStatus.setNumPlatforms(status.getNumPlatforms()); + execStatus.setNumMessages(status.getNumMessages()); + execStatus.setLastActivity(status.getLastModified()); + if (status.getId() != null) + { + execStatus.setRoutingExecId(status.getId().getValue()); + } + else + { + execStatus.setRoutingExecId(DbKey.NullKey.getValue()); + } + execStatuses.add(execStatus); + } + return execStatuses; + } + @GET @Path("dacqevents") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ApiConstants.ODCS_API_ADMIN, ApiConstants.ODCS_API_USER}) public Response getDacqEvents(@QueryParam("appid") Long appId, @QueryParam("routingexecid") Long routingExecId, - @QueryParam("platformid") Long platformId, @QueryParam("backlog") String backlog) - throws DbException + @QueryParam("platformid") Long platformId, @QueryParam("backlog") String backlog) + throws DbException, MissingParameterException { - Logger.getLogger(ApiConstants.loggerName).fine("getDacqEvents"); - try (DbInterface dbi = new DbInterface(); - ApiRoutingDAO dao = new ApiRoutingDAO(dbi)) + if (appId == null || routingExecId == null || platformId == null) + { + StringBuilder parameter = new StringBuilder(); + if (appId == null) + { + parameter.append("appid"); + } + if (routingExecId == null) + { + if (parameter.length() > 0) + { + parameter.append(", "); + } + parameter.append("routingexecid"); + } + if (platformId == null) + { + if (parameter.length() > 0) + { + parameter.append(", "); + } + parameter.append("platformid"); + } + throw new MissingParameterException(String.format("Missing required parameter(s): %s", parameter)); + } + + try (DacqEventDAI dai = getLegacyTimeseriesDB().makeDacqEventDAO()) { HttpSession session = request.getSession(true); - return ApiHttpUtil.createResponse(dao.getDacqEvents(appId, routingExecId, platformId, backlog, session)); + ArrayList events = new ArrayList<>(); + Object lastDacqEventId = session.getAttribute(LAST_DACQ_ATTRIBUTE); + boolean backLogValid = false; + Long dacqEventId = null; + Long timeInMillis = null; + if (backlog != null && !backlog.trim().isEmpty()) + { + backLogValid = true; + if (backlog.equalsIgnoreCase("last")) + { + if (lastDacqEventId != null) + { + dacqEventId = (Long) lastDacqEventId; + } + } + else + { + try (IntervalDAI intDai = getLegacyTimeseriesDB().makeIntervalDAO()) + { + intDai.loadAllIntervals(); + String[] intervalCodes = intDai.getValidIntervalCodes(); + for (String intervalCode : intervalCodes) + { + Interval intV = IntervalCodes.getInterval(intervalCode); + if (intV == null) + { + continue; + } + if (backlog.equalsIgnoreCase(intV.getName())) + { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.setTimeInMillis(System.currentTimeMillis()); + int calConstant = intV.getCalConstant(); + if (calConstant != -1) + { + cal.add(calConstant, -intV.getCalMultiplier()); + timeInMillis = cal.getTimeInMillis(); + session.removeAttribute(LAST_DACQ_ATTRIBUTE); + } + break; + } + } + } + } + } + + dai.readEvents(events, DbKey.createDbKey(appId), DbKey.createDbKey(routingExecId), + DbKey.createDbKey(platformId), backLogValid, dacqEventId, timeInMillis); + + return Response.status(HttpServletResponse.SC_OK) + .entity(events.stream().map(RoutingResources::map).collect(Collectors.toList())).build(); + } + catch (DbIoException e) + { + throw new DbException("Unable to retrieve dacq events", e); } } + + static ApiDacqEvent map(DacqEvent event) + { + // The app name is not present in the Toolkit DTO, so it won't be mapped here. + ApiDacqEvent apiEvent = new ApiDacqEvent(); + apiEvent.setEventId(event.getDacqEventId().getValue()); + apiEvent.setAppId(event.getAppId().getValue()); + apiEvent.setPlatformId(event.getPlatformId().getValue()); + apiEvent.setRoutingExecId(event.getScheduleEntryStatusId().getValue()); + apiEvent.setPriority(Logger.priorityName[event.getEventPriority()]); + apiEvent.setEventTime(event.getEventTime()); + apiEvent.setEventText(event.getEventText()); + apiEvent.setSubsystem(event.getSubsystem()); + apiEvent.setMsgRecvTime(event.getMsgRecvTime()); + return apiEvent; + } } diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/RoutingResourcesTest.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/RoutingResourcesTest.java new file mode 100644 index 000000000..34e1cb1da --- /dev/null +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/RoutingResourcesTest.java @@ -0,0 +1,323 @@ +package org.opendcs.odcsapi.res; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import java.util.Vector; + +import decodes.db.DataSource; +import decodes.db.RoutingSpec; +import decodes.db.RoutingSpecList; +import decodes.db.RoutingStatus; +import decodes.db.ScheduleEntry; +import decodes.db.ScheduleEntryStatus; +import decodes.polling.DacqEvent; +import decodes.sql.DbKey; +import ilex.util.Logger; +import org.junit.jupiter.api.Test; +import org.opendcs.odcsapi.beans.ApiDacqEvent; +import org.opendcs.odcsapi.beans.ApiRouting; +import org.opendcs.odcsapi.beans.ApiRoutingExecStatus; +import org.opendcs.odcsapi.beans.ApiRoutingRef; +import org.opendcs.odcsapi.beans.ApiRoutingStatus; +import org.opendcs.odcsapi.beans.ApiScheduleEntry; +import org.opendcs.odcsapi.beans.ApiScheduleEntryRef; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; +import static org.opendcs.odcsapi.res.RoutingResources.map; +import static org.opendcs.odcsapi.res.RoutingResources.statusMap; + +final class RoutingResourcesTest +{ + @Test + void testRoutingRefListMap() throws Exception + { + RoutingSpecList routingSpecList = new RoutingSpecList(); + RoutingSpec routingSpec = buildRoutingSpec(); + routingSpecList.add(routingSpec); + + List apiRoutingRefs = map(routingSpecList); + + ApiRoutingRef apiRoutingRef = apiRoutingRefs.get(0); + assertNotNull(apiRoutingRef); + assertEquals(apiRoutingRef.getRoutingId(), routingSpec.getId().getValue()); + assertEquals(apiRoutingRef.getName(), routingSpec.getName()); + assertEquals(apiRoutingRef.getDestination(), routingSpec.consumerArg); + assertEquals(apiRoutingRef.getDataSourceName(), routingSpec.dataSource.getName()); + assertEquals(apiRoutingRef.getLastModified(), routingSpec.lastModifyTime); + } + + @Test + void testApiRoutingMap() throws Exception + { + RoutingSpec routingSpec = buildRoutingSpec(); + ApiRouting apiRouting = map(routingSpec); + assertNotNull(apiRouting); + assertEquals(apiRouting.getRoutingId(), routingSpec.getId().getValue()); + assertEquals(apiRouting.getName(), routingSpec.getName()); + assertEquals(apiRouting.getOutputTZ(), routingSpec.outputTimeZoneAbbr); + assertEquals(apiRouting.getLastModified(), routingSpec.lastModifyTime); + assertEquals(apiRouting.isEnableEquations(), routingSpec.enableEquations); + assertEquals(new Vector<>(apiRouting.getNetlistNames()), routingSpec.networkListNames); + } + + @Test + void testRoutingSpecStatusMap() + { + List statuses = new ArrayList<>(); + RoutingStatus status = new RoutingStatus(DbKey.createDbKey(1234L)); + status.setLastMessageTime(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + status.setLastActivityTime(Date.from(Instant.parse("2021-02-01T12:00:00Z"))); + status.setNumDecodesErrors(10); + status.setNumMessages(20); + status.setRoutingSpecId(DbKey.createDbKey(5678L)); + status.setEnabled(true); + status.setName("TestRoutingSpec"); + status.setAppId(DbKey.createDbKey(9012L)); + status.setRunInterval("1h"); + status.setAppName("TestAppName"); + status.setManual(true); + status.setScheduleEntryId(DbKey.createDbKey(3456L)); + statuses.add(status); + + List results = map(statuses); + + assertNotNull(results); + assertEquals(1, results.size()); + ApiRoutingStatus result = results.get(0); + assertNotNull(result); + assertEquals(status.getRoutingSpecId().getValue(), result.getRoutingSpecId()); + assertEquals(status.getName(), result.getName()); + assertEquals(status.getAppId().getValue(), result.getAppId()); + assertEquals(status.getAppName(), result.getAppName()); + assertEquals(status.getScheduleEntryId().getValue(), result.getScheduleEntryId()); + assertEquals(status.getRunInterval(), result.getRunInterval()); + assertEquals(status.isEnabled(), result.isEnabled()); + assertEquals(status.isManual(), result.isManual()); + assertEquals(status.getNumMessages(), result.getNumMessages()); + assertEquals(status.getNumDecodesErrors(), result.getNumErrors()); + assertEquals(status.getLastActivityTime(), result.getLastActivity()); + assertEquals(status.getLastMessageTime(), result.getLastMsgTime()); + } + + @Test + void testRoutingSpecMap() throws Exception + { + ApiRouting apiRouting = new ApiRouting(); + apiRouting.setRoutingId(1234L); + apiRouting.setName("TestRoutingSpec"); + RoutingSpec routingSpec = map(apiRouting); + assertNotNull(routingSpec); + assertEquals(routingSpec.getId().getValue(), apiRouting.getRoutingId()); + assertEquals(routingSpec.getName(), apiRouting.getName()); + if (routingSpec.outputTimeZone != null) + { + assertEquals(routingSpec.outputTimeZone.getID(), apiRouting.getOutputTZ()); + } + else if (apiRouting.getOutputTZ() != null) + { + fail("routingSpec.outputTimeZone is null, but apiRouting.getOutputTZ() is not null"); + } + assertEquals(routingSpec.lastModifyTime, apiRouting.getLastModified()); + assertEquals(routingSpec.enableEquations, apiRouting.isEnableEquations()); + assertEquals(routingSpec.networkListNames, new Vector<>(apiRouting.getNetlistNames())); + } + + @Test + void testScheduleEntryRefMap() + { + List scheduleEntries = new ArrayList<>(); + ScheduleEntry scheduleEntry = new ScheduleEntry(DbKey.createDbKey(1234L)); + scheduleEntry.setEnabled(true); + scheduleEntry.setName("TestScheduleEntry"); + scheduleEntry.setRoutingSpecId(DbKey.createDbKey(5678L)); + scheduleEntry.setLastModified(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + scheduleEntry.setLoadingAppName("TestAppName"); + scheduleEntry.setRoutingSpecName("TestRoutingSpec"); + scheduleEntry.setTimezone("UTC"); + scheduleEntry.setStartTime(Date.from(Instant.parse("2021-01-01T00:00:00Z"))); + scheduleEntries.add(scheduleEntry); + List apiScheduleEntryRefs = RoutingResources.entryMap(scheduleEntries); + assertNotNull(apiScheduleEntryRefs); + ApiScheduleEntryRef apiScheduleEntryRef = apiScheduleEntryRefs.get(0); + assertNotNull(apiScheduleEntryRef); + assertEquals(apiScheduleEntryRef.getSchedEntryId(), scheduleEntry.getKey().getValue()); + assertEquals(apiScheduleEntryRef.getName(), scheduleEntry.getName()); + assertEquals(apiScheduleEntryRef.getAppName(), scheduleEntry.getLoadingAppName()); + assertEquals(apiScheduleEntryRef.getRoutingSpecName(), scheduleEntry.getRoutingSpecName()); + assertEquals(apiScheduleEntryRef.getLastModified(), scheduleEntry.getLastModified()); + } + + @Test + void testScheduleEntryMap() throws Exception + { + ApiScheduleEntry apiScheduleEntry = new ApiScheduleEntry(); + apiScheduleEntry.setSchedEntryId(1234L); + apiScheduleEntry.setName("TestScheduleEntry"); + apiScheduleEntry.setAppName("TestAppName"); + apiScheduleEntry.setRoutingSpecName("TestRoutingSpec"); + apiScheduleEntry.setLastModified(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + apiScheduleEntry.setAppId(5678L); + apiScheduleEntry.setRoutingSpecId(9012L); + apiScheduleEntry.setStartTime(Date.from(Instant.parse("2021-01-01T00:00:00Z"))); + apiScheduleEntry.setEnabled(true); + apiScheduleEntry.setTimeZone("UTC"); + apiScheduleEntry.setRunInterval("1h"); + ScheduleEntry scheduleEntry = map(apiScheduleEntry); + assertNotNull(scheduleEntry); + assertEquals(scheduleEntry.getKey().getValue(), apiScheduleEntry.getSchedEntryId()); + assertEquals(scheduleEntry.getName(), apiScheduleEntry.getName()); + assertEquals(scheduleEntry.getLoadingAppName(), apiScheduleEntry.getAppName()); + assertEquals(scheduleEntry.getRoutingSpecName(), apiScheduleEntry.getRoutingSpecName()); + assertEquals(scheduleEntry.getLastModified(), apiScheduleEntry.getLastModified()); + assertEquals(scheduleEntry.getLoadingAppId().getValue(), apiScheduleEntry.getAppId()); + assertEquals(scheduleEntry.getRoutingSpecId().getValue(), apiScheduleEntry.getRoutingSpecId()); + assertEquals(scheduleEntry.getStartTime(), apiScheduleEntry.getStartTime()); + assertEquals(scheduleEntry.isEnabled(), apiScheduleEntry.isEnabled()); + assertEquals(scheduleEntry.getTimezone(), apiScheduleEntry.getTimeZone()); + assertEquals(scheduleEntry.getRunInterval(), apiScheduleEntry.getRunInterval()); + } + + @Test + void testApiScheduleEntryListMap() + { + ArrayList scheduleEntries = new ArrayList<>(); + ScheduleEntry scheduleEntry = new ScheduleEntry(DbKey.createDbKey(1234L)); + scheduleEntry.setName("TestScheduleEntry"); + scheduleEntry.setLoadingAppName("TestAppName"); + scheduleEntry.setRoutingSpecName("TestRoutingSpec"); + scheduleEntry.setLastModified(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + scheduleEntry.setLoadingAppId(DbKey.createDbKey(5678L)); + scheduleEntry.setRoutingSpecId(DbKey.createDbKey(9012L)); + scheduleEntry.setStartTime(Date.from(Instant.parse("2021-01-01T00:00:00Z"))); + scheduleEntry.setEnabled(true); + scheduleEntry.setTimezone("UTC"); + scheduleEntry.setRunInterval("1h"); + scheduleEntries.add(scheduleEntry); + + List results = RoutingResources.entryMap(scheduleEntries); + + assertNotNull(results); + assertEquals(1, results.size()); + ApiScheduleEntryRef result = results.get(0); + assertNotNull(result); + assertEquals(scheduleEntry.getKey().getValue(), result.getSchedEntryId()); + assertEquals(scheduleEntry.getName(), result.getName()); + assertEquals(scheduleEntry.getLoadingAppName(), result.getAppName()); + assertEquals(scheduleEntry.getRoutingSpecName(), result.getRoutingSpecName()); + assertEquals(scheduleEntry.getLastModified(), result.getLastModified()); + } + + @Test + void testRoutingStatusMap() + { + ArrayList scheduleEntries = new ArrayList<>(); + ScheduleEntryStatus scheduleEntry = new ScheduleEntryStatus(DbKey.createDbKey(1234L)); + scheduleEntry.setScheduleEntryName("TestScheduleEntry"); + scheduleEntry.setLastModified(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + scheduleEntry.setHostname("TestHost"); + scheduleEntry.setRunStatus("TestStatus"); + scheduleEntry.setNumDecodesErrors(10); + scheduleEntry.setNumMessages(20); + scheduleEntry.setNumPlatforms(30); + scheduleEntry.setRunStop(Date.from(Instant.parse("2021-03-01T00:00:00Z"))); + scheduleEntry.setRunStart(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + scheduleEntry.setLastModified(Date.from(Instant.parse("2021-04-01T00:00:00Z"))); + scheduleEntries.add(scheduleEntry); + + ArrayList results = statusMap(scheduleEntries); + assertNotNull(results); + assertEquals(1, results.size()); + ApiRoutingExecStatus result = results.get(0); + assertNotNull(result); + assertEquals(scheduleEntry.getScheduleEntryId().getValue(), result.getScheduleEntryId()); + assertEquals(scheduleEntry.getHostname(), result.getHostname()); + assertEquals(scheduleEntry.getRunStatus(), result.getRunStatus()); + assertEquals(scheduleEntry.getNumDecodesErrors(), result.getNumErrors()); + assertEquals(scheduleEntry.getNumMessages(), result.getNumMessages()); + assertEquals(scheduleEntry.getNumPlatforms(), result.getNumPlatforms()); + assertEquals(scheduleEntry.getRunStop(), result.getRunStop()); + assertEquals(scheduleEntry.getRunStart(), result.getRunStart()); + assertEquals(scheduleEntry.getLastModified(), result.getLastActivity()); + } + + @Test + void testApiScheduleEntryMap() + { + ScheduleEntry scheduleEntry = new ScheduleEntry(DbKey.createDbKey(1234L)); + scheduleEntry.setName("TestScheduleEntry"); + scheduleEntry.setLoadingAppName("TestAppName"); + scheduleEntry.setRoutingSpecName("TestRoutingSpec"); + scheduleEntry.setLastModified(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + scheduleEntry.setLoadingAppId(DbKey.createDbKey(5678L)); + scheduleEntry.setRoutingSpecId(DbKey.createDbKey(9012L)); + scheduleEntry.setStartTime(Date.from(Instant.parse("2021-01-01T00:00:00Z"))); + scheduleEntry.setEnabled(true); + scheduleEntry.setTimezone("UTC"); + scheduleEntry.setRunInterval("1h"); + + ApiScheduleEntry apiScheduleEntry = map(scheduleEntry); + assertNotNull(apiScheduleEntry); + assertEquals(apiScheduleEntry.getSchedEntryId(), scheduleEntry.getKey().getValue()); + assertEquals(apiScheduleEntry.getName(), scheduleEntry.getName()); + assertEquals(apiScheduleEntry.getAppName(), scheduleEntry.getLoadingAppName()); + assertEquals(apiScheduleEntry.getRoutingSpecName(), scheduleEntry.getRoutingSpecName()); + assertEquals(apiScheduleEntry.getLastModified(), scheduleEntry.getLastModified()); + assertEquals(apiScheduleEntry.getAppId(), scheduleEntry.getLoadingAppId().getValue()); + assertEquals(apiScheduleEntry.getRoutingSpecId(), scheduleEntry.getRoutingSpecId().getValue()); + assertEquals(apiScheduleEntry.getStartTime(), scheduleEntry.getStartTime()); + assertEquals(apiScheduleEntry.isEnabled(), scheduleEntry.isEnabled()); + assertEquals(apiScheduleEntry.getTimeZone(), scheduleEntry.getTimezone()); + assertEquals(apiScheduleEntry.getRunInterval(), scheduleEntry.getRunInterval()); + } + + @Test + void testDacqEventMap() + { + DacqEvent dacqEvent = new DacqEvent(); + dacqEvent.setAppId(DbKey.createDbKey(1234L)); + dacqEvent.setDacqEventId(DbKey.createDbKey(5678L)); + dacqEvent.setEventText("TestEvent"); + dacqEvent.setEventTime(Date.from(Instant.parse("2021-02-01T00:00:00Z"))); + dacqEvent.setEventPriority(Logger.E_DEBUG1); + dacqEvent.setMsgRecvTime(Date.from(Instant.parse("2021-02-01T12:00:00Z"))); + dacqEvent.setSubsystem("TestSubsystem"); + dacqEvent.setScheduleEntryStatusId(DbKey.createDbKey(9012L)); + dacqEvent.setPlatformId(DbKey.createDbKey(3456L)); + + ApiDacqEvent apiDacqEvent = map(dacqEvent); + + assertNotNull(apiDacqEvent); + assertEquals(apiDacqEvent.getAppId(), dacqEvent.getAppId().getValue()); + assertEquals(apiDacqEvent.getEventId(), dacqEvent.getDacqEventId().getValue()); + assertEquals(apiDacqEvent.getEventText(), dacqEvent.getEventText()); + assertEquals(apiDacqEvent.getEventTime(), dacqEvent.getEventTime()); + assertEquals(apiDacqEvent.getPriority(), Logger.priorityName[dacqEvent.getEventPriority()]); + assertEquals(apiDacqEvent.getMsgRecvTime(), dacqEvent.getMsgRecvTime()); + assertEquals(apiDacqEvent.getSubsystem(), dacqEvent.getSubsystem()); + assertEquals(apiDacqEvent.getRoutingExecId(), dacqEvent.getScheduleEntryStatusId().getValue()); + assertEquals(apiDacqEvent.getPlatformId(), dacqEvent.getPlatformId().getValue()); + } + + private RoutingSpec buildRoutingSpec() throws Exception + { + DataSource dataSource = new DataSource(); + dataSource.setName("TestDataSource"); + dataSource.setId(DbKey.createDbKey(2345L)); + dataSource.setDataSourceArg("TestDataSourceArg"); + RoutingSpec routingSpec = new RoutingSpec(); + routingSpec.setName("TestRoutingSpec"); + routingSpec.setId(DbKey.createDbKey(1234L)); + routingSpec.outputTimeZone = TimeZone.getTimeZone("UTC"); + routingSpec.lastModifyTime = Date.from(Instant.parse("2021-02-01T00:00:00Z")); + routingSpec.enableEquations = true; + routingSpec.networkListNames = new Vector<>(Arrays.asList("TestNet", "TestNet2")); + routingSpec.dataSource = dataSource; + return routingSpec; + } +} 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 1fa10965b..ccf9c3110 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 @@ -29,10 +29,12 @@ import decodes.db.PlatformStatus; import decodes.db.ScheduleEntry; import decodes.db.ScheduleEntryStatus; +import decodes.polling.DacqEvent; import decodes.sql.DbKey; import io.restassured.filter.log.LogDetail; import io.restassured.filter.session.SessionFilter; import io.restassured.path.json.JsonPath; +import opendcs.dai.DacqEventDAI; import opendcs.dai.PlatformStatusDAI; import opendcs.dai.ScheduleEntryDAI; import org.apache.catalina.session.StandardSession; @@ -50,7 +52,7 @@ import static java.util.stream.Collectors.joining; import static org.hamcrest.Matchers.is; -class BaseIT +public class BaseIT { protected static String authHeader = null; @@ -190,23 +192,49 @@ public static void storeScheduleEntryStatus(ScheduleEntryStatus status) throws D { dai.writeScheduleStatus(status); } - catch (Throwable ex) + catch (Throwable e) { - throw new DatabaseException("Error storing schedule entry status", ex); + throw new DatabaseException("Error storing schedule entry status", e); } } - public static void deleteScheduleEntryStatus(DbKey statusId) throws DatabaseException + public static void deleteScheduleEntryStatus(DbKey entryId) throws DatabaseException { Configuration currentConfig = DatabaseSetupExtension.getCurrentConfig(); try (ScheduleEntryDAI dai = currentConfig.getTsdb().makeScheduleEntryDAO()) { - ScheduleEntry entry = new ScheduleEntry(statusId); + ScheduleEntry entry = new ScheduleEntry(entryId); dai.deleteScheduleStatusFor(entry); } - catch (Throwable ex) + catch (Throwable e) { - throw new DatabaseException("Error deleting schedule entry status", ex); + throw new DatabaseException("Error deleting schedule entry status", e); + } + } + + public static void storeDacqEvent(DacqEvent event) throws DatabaseException + { + Configuration currentConfig = DatabaseSetupExtension.getCurrentConfig(); + try (DacqEventDAI dai = currentConfig.getTsdb().makeDacqEventDAO()) + { + dai.writeEvent(event); + } + catch (Throwable e) + { + throw new DatabaseException("Error storing dacq event", e); + } + } + + public static void deleteEventsForPlatform(DbKey platformId) throws DatabaseException + { + Configuration currentConfig = DatabaseSetupExtension.getCurrentConfig(); + try (DacqEventDAI dai = currentConfig.getTsdb().makeDacqEventDAO()) + { + dai.deleteEventsForPlatform(platformId); + } + catch (Throwable e) + { + throw new DatabaseException("Error deleting dacq event for specified platform", e); } } @@ -217,22 +245,22 @@ public static void storePlatformStatus(PlatformStatus status) throws DatabaseExc { dai.writePlatformStatus(status); } - catch (Throwable ex) + catch (Throwable e) { - throw new DatabaseException("Error storing platform status", ex); + throw new DatabaseException("Error storing platform status", e); } } - public static void deletePlatformStatus(DbKey statusId) throws DatabaseException + public static void deletePlatformStatus(DbKey platformId) throws DatabaseException { Configuration currentConfig = DatabaseSetupExtension.getCurrentConfig(); try (PlatformStatusDAI dai = currentConfig.getTsdb().makePlatformStatusDAO()) { - dai.deletePlatformStatus(statusId); + dai.deletePlatformStatus(platformId); } - catch (Throwable ex) + catch (Throwable e) { - throw new DatabaseException("Error deleting platform status", ex); + throw new DatabaseException("Error deleting platform status", e); } } } diff --git a/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/RoutingResourcesIT.java b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/RoutingResourcesIT.java new file mode 100644 index 000000000..2dfa1266d --- /dev/null +++ b/opendcs-rest-api/src/test/java/org/opendcs/odcsapi/res/it/RoutingResourcesIT.java @@ -0,0 +1,980 @@ +package org.opendcs.odcsapi.res.it; + +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.ObjectMapper; +import decodes.db.ScheduleEntryStatus; +import decodes.polling.DacqEvent; +import decodes.sql.DbKey; +import io.restassured.filter.log.LogDetail; +import io.restassured.filter.session.SessionFilter; +import io.restassured.path.json.JsonPath; +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.ApiDacqEvent; +import org.opendcs.odcsapi.beans.ApiDataSource; +import org.opendcs.odcsapi.beans.ApiLoadingApp; +import org.opendcs.odcsapi.beans.ApiRouting; +import org.opendcs.odcsapi.beans.ApiRoutingStatus; +import org.opendcs.odcsapi.beans.ApiScheduleEntry; +import org.opendcs.odcsapi.beans.ApiScheduleEntryRef; +import org.opendcs.odcsapi.fixtures.DatabaseContextProvider; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Tag("integration-opentsdb-only") +@ExtendWith(DatabaseContextProvider.class) +final class RoutingResourcesIT extends BaseIT +{ + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static SessionFilter sessionFilter; + private static Long routingId; + private static Long scheduleId; + private static Long dataSourceId; + private static Long appId; + private static Long siteId; + private static String appName; + private static Long platformId; + private static Long scheduleEntryStatusId; + + @BeforeEach + void setUp() throws Exception + { + setUpCreds(); + sessionFilter = new SessionFilter(); + authenticate(sessionFilter); + + ApiLoadingApp loadingApp = getDtoFromResource("routing_app_insert_data.json", ApiLoadingApp.class); + + appName = loadingApp.getAppName(); + + String loadingAppJson = MAPPER.writeValueAsString(loadingApp); + + // Insert the application data + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(loadingAppJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("app") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + appId = response.body().jsonPath().getLong("appId"); + + ApiRouting route = getDtoFromResource("routing_insert_data.json", ApiRouting.class); + + ApiDataSource dataSource = getDtoFromResource("routing_datasource_insert_data.json", ApiDataSource.class); + + String dataSourceJson = MAPPER.writeValueAsString(dataSource); + + // Insert the data source + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(dataSourceJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("datasource") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + dataSourceId = response.body().jsonPath().getLong("dataSourceId"); + + route.setDataSourceId(dataSourceId); + + String routingJson = MAPPER.writeValueAsString(route); + + // Insert the routing + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(routingJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + routingId = response.body().jsonPath().getLong("routingId"); + + ApiScheduleEntry sched = getDtoFromResource("routing_schedule_insert_data.json", ApiScheduleEntry.class); + + sched.setAppName(appName); + sched.setAppId(appId); + sched.setRoutingSpecId(routingId); + + String scheduleJson = MAPPER.writeValueAsString(sched); + + // Insert the schedule + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(scheduleJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + scheduleId = response.body().jsonPath().getLong("schedEntryId"); + + ScheduleEntryStatus status = new ScheduleEntryStatus(DbKey.NullKey); + status.setScheduleEntryId(DbKey.createDbKey(scheduleId)); + status.setHostname("localhost"); + status.setRunStatus("Running"); + status.setLastMessageTime(Date.from(Instant.parse("2025-01-31T00:00:00Z"))); + status.setNumMessages(10); + status.setNumDecodesErrors(1); + status.setNumPlatforms(1); + status.setRunStart(Date.from(Instant.parse("2025-01-29T00:00:00Z"))); + status.setRunStop(Date.from(Instant.parse("2025-01-30T00:00:00Z"))); + status.setScheduleEntryName("Test schedule"); + + // Insert the schedule entry status + storeScheduleEntryStatus(status); + + siteId = storeSite("routing_site_insert.json"); + + platformId = storePlatform("routing_platform_insert.json", siteId); + + // Retrieve the schedule entry status id + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("scheduleentryid", scheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routingexecstatus") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + scheduleEntryStatusId = DbKey.NullKey.getValue(); + JsonPath responseJson = response.body().jsonPath(); + List> responseList = responseJson.getList(""); + assertFalse(responseList.isEmpty()); + boolean found = false; + for (Map responseMap : responseList) + { + if (((Integer) responseMap.get("scheduleEntryId")).longValue() == scheduleId) + { + scheduleEntryStatusId = ((Integer) responseMap.get("routingExecId")).longValue(); + found = true; + break; + } + } + assertTrue(found); + + // Insert the dacq event + DacqEvent event = new DacqEvent(); + event.setAppId(DbKey.createDbKey(appId)); + event.setEventPriority(1); + event.setEventText("Test event"); + event.setSubsystem("Routing"); + event.setEventTime(Date.from(Instant.parse("2025-01-31T00:00:00Z"))); + event.setMsgRecvTime(Date.from(Instant.parse("2025-01-31T00:30:00Z"))); + event.setPlatformId(DbKey.createDbKey(platformId)); + event.setScheduleEntryStatusId(DbKey.createDbKey(scheduleEntryStatusId)); + + storeDacqEvent(event); + } + + @AfterEach + void tearDown() throws Exception + { + // Delete the dacq event + deleteEventsForPlatform(DbKey.createDbKey(platformId)); + + // Delete the schedule entry status + deleteScheduleEntryStatus(DbKey.createDbKey(scheduleEntryStatusId)); + + if (routingId != null) + { + // Delete the routing + given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("routingid", routingId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + } + + if (scheduleId != null) + { + // Delete the schedule + given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("scheduleid", scheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + } + + // Delete the data source + given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("datasourceid", dataSourceId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("datasource") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + + // Delete the application + given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("appid", appId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("app") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + tearDownPlatform(platformId); + + tearDownSite(siteId); + + logout(sessionFilter); + } + + + @TestTemplate + void testGetRoutingRefs() + { + JsonPath expected = getJsonPathFromResource("routing_insert_data.json"); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routingrefs") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + List> actualList = actual.getList(""); + boolean found = false; + for (Map actualMap : actualList) + { + if (actualMap.get("name").equals(expected.getString("name"))) + { + assertEquals(expected.getString("name"), actualMap.get("name")); + assertEquals(expected.getString("dataSourceName"), actualMap.get("dataSourceName")); + assertEquals(expected.getString("lastModified"), actualMap.get("lastModified")); + found = true; + } + } + assertTrue(found); + } + + @TestTemplate + void testGetRouting() + { + JsonPath expected = getJsonPathFromResource("routing_insert_data.json"); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("routingid", routingId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + assertEquals(expected.getString("name"), actual.getString("name")); + assertEquals(expected.getString("destination"), actual.getString("destination")); + assertEquals(expected.getString("dataSourceName"), actual.getString("dataSourceName")); + assertEquals(expected.getString("lastModified"), actual.getString("lastModified")); + assertEquals(expected.getString("destinationType"), actual.getString("destinationType")); + assertEquals(expected.getString("destinationArg"), actual.getString("destinationArg")); + assertEquals(expected.getString("enableEquations"), actual.getString("enableEquations")); + assertEquals(expected.getString("outputFormat"), actual.getString("outputFormat")); + assertEquals(expected.getString("outputTZ"), actual.getString("outputTZ")); + assertEquals(expected.getString("presGroupName"), actual.getString("presGroupName")); + assertEquals(expected.getString("since"), actual.getString("since")); + assertEquals(expected.getString("until"), actual.getString("until")); + assertEquals(expected.getString("settlingTimeDelay"), actual.getString("settlingTimeDelay")); + assertEquals(expected.getString("applyTimeTo"), actual.getString("applyTimeTo")); + assertEquals(expected.getString("ascendingTime"), actual.getString("ascendingTime")); + assertEquals(expected.getString("platformIds"), actual.getString("platformIds")); + assertEquals(expected.getString("platformNames"), actual.getString("platformNames")); + assertEquals(expected.getString("netlistNames"), actual.getString("netlistNames")); + assertEquals(expected.getString("goesChannels"), actual.getString("goesChannels")); + assertEquals(expected.getString("properties"), actual.getString("properties")); + assertEquals(expected.getString("goesSelfTimed"), actual.getString("goesSelfTimed")); + assertEquals(expected.getString("goesRandom"), actual.getString("goesRandom")); + assertEquals(expected.getString("networkDCP"), actual.getString("networkDCP")); + assertEquals(expected.getString("iridium"), actual.getString("iridium")); + assertEquals(expected.getString("qualityNotifications"), actual.getString("qualityNotifications")); + assertEquals(expected.getString("goesSpacecraftCheck"), actual.getString("goesSpacecraftCheck")); + assertEquals(expected.getString("goesSpacecraftSelection"), actual.getString("goesSpacecraftSelection")); + assertEquals(expected.getString("parityCheck"), actual.getString("parityCheck")); + assertEquals(expected.getString("paritySelection"), actual.getString("paritySelection")); + assertEquals(expected.getString("production"), actual.getString("production")); + } + + @TestTemplate + void testPostAndDeleteRouting() throws Exception + { + ApiRouting routing = getDtoFromResource("routing_post_delete_insert_data.json", ApiRouting.class); + routing.setDataSourceId(dataSourceId); + + String routingJson = MAPPER.writeValueAsString(routing); + + // Insert the routing + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(routingJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + Long newRoutingId = response.body().jsonPath().getLong("routingId"); + + JsonPath expected = getJsonPathFromResource("routing_post_delete_expected.json"); + + // Get the routing and assert it exists + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("routingid", newRoutingId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + + assertEquals(expected.getString("name"), actual.getString("name")); + assertEquals(expected.getString("dataSourceName"), actual.getString("dataSourceName")); + assertEquals(expected.getString("destinationType"), actual.getString("destinationType")); + assertEquals(expected.getString("destinationArg"), actual.getString("destinationArg")); + assertEquals(expected.getString("enableEquations"), actual.getString("enableEquations")); + assertEquals(expected.getString("outputFormat"), actual.getString("outputFormat")); + assertEquals(expected.getString("outputTZ"), actual.getString("outputTZ")); + assertEquals(expected.getString("presGroupName"), actual.getString("presGroupName")); + assertEquals(expected.getString("since"), actual.getString("since")); + assertEquals(expected.getString("until"), actual.getString("until")); + assertEquals(expected.getString("settlingTimeDelay"), actual.getString("settlingTimeDelay")); + assertEquals(expected.getString("applyTimeTo"), actual.getString("applyTimeTo")); + assertEquals(expected.getString("ascendingTime"), actual.getString("ascendingTime")); + assertEquals(expected.getString("platformIds"), actual.getString("platformIds")); + assertEquals(expected.getString("platformNames"), actual.getString("platformNames")); + assertEquals(expected.getString("netlistNames"), actual.getString("netlistNames")); + assertEquals(expected.getString("goesChannels"), actual.getString("goesChannels")); + assertEquals(expected.getString("properties"), actual.getString("properties")); + assertEquals(expected.getString("goesSelfTimed"), actual.getString("goesSelfTimed")); + assertEquals(expected.getString("goesRandom"), actual.getString("goesRandom")); + assertEquals(expected.getString("networkDCP"), actual.getString("networkDCP")); + assertEquals(expected.getString("iridium"), actual.getString("iridium")); + assertEquals(expected.getString("qualityNotifications"), actual.getString("qualityNotifications")); + assertEquals(expected.getString("goesSpacecraftCheck"), actual.getString("goesSpacecraftCheck")); + assertEquals(expected.getString("goesSpacecraftSelection"), actual.getString("goesSpacecraftSelection")); + assertEquals(expected.getString("parityCheck"), actual.getString("parityCheck")); + assertEquals(expected.getString("paritySelection"), actual.getString("paritySelection")); + assertEquals(expected.getString("production"), actual.getString("production")); + assertEquals(expected.getString("lastModified"), actual.getString("lastModified")); + + // Delete the routing + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("routingid", newRoutingId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + + // Get the routing and assert it does not exist + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("routingid", newRoutingId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routing") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NOT_FOUND)) + ; + } + + @TestTemplate + void testGetScheduleRefs() throws Exception + { + ApiScheduleEntryRef schedule = getDtoFromResource("routing_refs_expected.json", + ApiScheduleEntryRef.class); + schedule.setAppName(appName); + JsonPath expected = new JsonPath(MAPPER.writeValueAsString(schedule)); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("schedulerefs") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + List> actualList = actual.getList(""); + boolean found = false; + for (Map actualMap : actualList) + { + if (actualMap.get("name").equals(expected.getString("name"))) + { + assertEquals(expected.getString("name"), actualMap.get("name")); + assertEquals(expected.getString("appName"), actualMap.get("appName")); + assertEquals(expected.getString("routingSpecName"), actualMap.get("routingSpecName")); + assertEquals(expected.get("enabled"), actualMap.get("enabled")); + found = true; + } + } + assertTrue(found); + } + + @TestTemplate + void testGetSchedule() throws Exception + { + ApiScheduleEntry entry = getDtoFromResource("routing_schedule_insert_data.json", ApiScheduleEntry.class); + entry.setAppId(appId); + entry.setAppName(appName); + JsonPath expected = new JsonPath(MAPPER.writeValueAsString(entry)); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("scheduleid", scheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + assertEquals(expected.getString("name"), actual.get("name")); + assertEquals(expected.getString("appName"), actual.get("appName")); + assertEquals(expected.getString("routingSpecName"), actual.get("routingSpecName")); + assertEquals(expected.getBoolean("enabled"), actual.getBoolean("enabled")); + } + + @TestTemplate + void testPostAndDeleteSchedule() throws Exception + { + ApiScheduleEntry schedule = getDtoFromResource("routing_schedule_post_delete_insert_data.json", + ApiScheduleEntry.class); + + schedule.setAppName(appName); + schedule.setAppId(appId); + schedule.setRoutingSpecId(routingId); + String scheduleJson = MAPPER.writeValueAsString(schedule); + + // Insert the schedule + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .filter(sessionFilter) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .body(scheduleJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + Long newScheduleId = response.body().jsonPath().getLong("schedEntryId"); + + ApiScheduleEntry expectedSchedule = getDtoFromResource("routing_schedule_post_delete_expected.json", + ApiScheduleEntry.class); + expectedSchedule.setAppId(appId); + expectedSchedule.setAppName(appName); + JsonPath expected = new JsonPath(MAPPER.writeValueAsString(expectedSchedule)); + + // Get the schedule and assert it exists + response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("scheduleid", newScheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + + assertEquals(expected.getString("name"), actual.getString("name")); + assertEquals(expected.getString("appName"), actual.getString("appName")); + assertEquals(expected.getString("routingSpecName"), actual.getString("routingSpecName")); + assertEquals(expected.getString("enabled"), actual.getString("enabled")); + assertEquals(Instant.ofEpochMilli(expected.getLong("startTime")).toString() + "[UTC]", + actual.getString("startTime")); // This comparison requires some manipulation to match up + assertEquals(expected.getString("timeZone"), actual.getString("timeZone")); + assertEquals(expected.getString("runInterval"), actual.getString("runInterval")); + + // Delete the schedule + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("scheduleid", newScheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + + // Get the schedule and assert it does not exist + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("scheduleid", newScheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("schedule") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NOT_FOUND)) + ; + } + + @TestTemplate + void testGetRoutingStatus() throws Exception + { + ApiRoutingStatus status = getDtoFromResource("routing_status_expected.json", ApiRoutingStatus.class); + status.setAppId(appId); + status.setAppName(appName); + JsonPath expected = new JsonPath(MAPPER.writeValueAsString(status)); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routingstatus") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + List> actualList = response.body().jsonPath().getList(""); + + boolean found = false; + for (Map actualItem : actualList) + { + if (actualItem.get("name").equals(expected.get("name"))) + { + assertEquals(expected.get("name"), actualItem.get("name")); + assertEquals(expected.get("appName"), actualItem.get("appName")); + assertEquals(expected.get("routingSpecName"), actualItem.get("routingSpecName")); + assertEquals(expected.get("enabled"), actualItem.get("enabled")); + found = true; + } + } + assertTrue(found); + } + + @TestTemplate + void testGetRoutingExecStatus() + { + // Note: Routing spec id is not mapped here! + JsonPath expected = getJsonPathFromResource("routing_exec_status_expected.json"); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("scheduleentryid", scheduleId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("routingexecstatus") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + List> actualList = actual.getList(""); + + boolean found = false; + for (Map actualItem : actualList) + { + if (((Integer) actualItem.get("scheduleEntryId")).longValue() == scheduleId) + { + assertEquals(expected.getString("runStart"), actualItem.get("runStart")); + assertEquals(expected.getString("runStop"), actualItem.get("runStop")); + assertEquals(expected.getInt("numMessages"), actualItem.get("numMessages")); + assertEquals(expected.getInt("numErrors"), actualItem.get("numErrors")); + assertEquals(expected.getInt("numPlatforms"), actualItem.get("numPlatforms")); + assertEquals(expected.getString("lastMsgTime"), actualItem.get("lastMsgTime")); + assertEquals(expected.getString("runStatus"), actualItem.get("runStatus")); + assertEquals(expected.getString("hostname"), actualItem.get("hostname")); + assertEquals(expected.getString("lastInput"), actualItem.get("lastInput")); + assertEquals(expected.getString("lastOutput"), actualItem.get("lastOutput")); + + found = true; + } + } + assertTrue(found); + } + + @TestTemplate + void testGetDacqEvents() throws Exception + { + ApiDacqEvent event = getDtoFromResource("routing_dacq_events_expected.json", ApiDacqEvent.class); + event.setAppId(appId); + event.setAppName(appName); + event.setRoutingExecId(scheduleEntryStatusId); + event.setSubsystem("Routing"); + JsonPath expected = new JsonPath(MAPPER.writeValueAsString(event)); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .header("Authorization", authHeader) + .queryParam("routingexecid", scheduleEntryStatusId) + .queryParam("appid", appId) + .queryParam("platformid", platformId) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("dacqevents") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .extract() + ; + + JsonPath actual = response.body().jsonPath(); + List> actualList = actual.getList(""); + assertFalse(actualList.isEmpty()); + + boolean found = false; + for (Map actualItem : actualList) + { + if (((Integer) actualItem.get("platformId")).longValue() == platformId + && ((Integer) actualItem.get("appId")).longValue() == appId + && ((Integer) actualItem.get("routingExecId")).longValue() == scheduleEntryStatusId) + { + // The event time updated based on current time, so we can't compare it directly + // The app name is not present in the Toolkit DTO, so it won't be returned in the response + assertEquals(expected.get("priority").toString(), actualItem.get("priority").toString()); + assertEquals(expected.get("subsystem"), actualItem.get("subsystem")); + String messageRcvTime = actualItem.get("msgRecvTime").toString(); + // substring date text to remove timezone and milliseconds + assertEquals(Instant.ofEpochMilli(expected.get("msgRecvTime")).toString(), + messageRcvTime.substring(0, messageRcvTime.indexOf(".")) + "Z"); + assertEquals(expected.get("eventText").toString(), actualItem.get("eventText").toString()); + found = true; + } + } + assertTrue(found); + } + + private Long storeSite(String jsonPath) throws Exception + { + assertNotNull(jsonPath); + String siteJson = getJsonFromResource(jsonPath); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .contentType(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .body(siteJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("site") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + return response.body().jsonPath().getLong("siteId"); + } + + private void tearDownSite(Long siteId) + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("siteid", siteId) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("site") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("siteid", siteId) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("site") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NOT_FOUND)) + ; + } + + private Long storePlatform(String jsonPath, Long siteId) throws Exception + { + assertNotNull(jsonPath); + String platformJson = getJsonFromResource(jsonPath); + + platformJson = platformJson.replace("[SITE_ID]", siteId.toString()); + + ExtractableResponse response = given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .contentType(MediaType.APPLICATION_JSON) + .filter(sessionFilter) + .body(platformJson) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("platform") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)) + .extract() + ; + + return response.body().jsonPath().getLong("platformId"); + } + + private void tearDownPlatform(Long platformId) + { + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("platformid", platformId) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .delete("platform") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NO_CONTENT)) + ; + + given() + .log().ifValidationFails(LogDetail.ALL, true) + .accept(MediaType.APPLICATION_JSON) + .header("Authorization", authHeader) + .queryParam("platformid", platformId) + .filter(sessionFilter) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("platform") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_NOT_FOUND)) + ; + } +} diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_app_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_app_insert_data.json new file mode 100644 index 000000000..8e5c40baa --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_app_insert_data.json @@ -0,0 +1,16 @@ +{ + "appId" : null, + "appName" : "Computational App", + "appType" : "computation", + "comment" : "Processes input values", + "lastModified" : 1609459200000, + "manualEditingApp" : false, + "properties" : { + "computation" : "average", + "input" : "Buckhorn.Temp-Water.Inst.1Day.0.cda-test", + "output" : "Buckhorn.Temp-Water.Inst.1Day.0.cda-test", + "period" : "1 day", + "start" : 1675335600000, + "end" : 1675422000000 + } +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_dacq_events_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_dacq_events_expected.json new file mode 100644 index 000000000..dd4f2ef04 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_dacq_events_expected.json @@ -0,0 +1,12 @@ +{ + "eventId": 1, + "routingExecId": 1, + "platformId": 1, + "eventTime": "2025-01-31T00:00:00.000Z[UTC]", + "priority": "DBG2 ", + "appId": 8, + "appName": null, + "subsystem": "Routing", + "msgRecvTime": "2025-01-31T00:30:00.000Z[UTC]", + "eventText": "Test event" +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_datasource_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_datasource_insert_data.json new file mode 100644 index 000000000..ff2732005 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_datasource_insert_data.json @@ -0,0 +1,10 @@ +{ + "dataSourceId" : null, + "name" : "Routing Test Data Source", + "type" : "CWMS", + "usedBy" : 1, + "props" : { + "url" : "http://localhost:8080/cwms" + }, + "groupMembers" : [ ] +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_exec_status_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_exec_status_expected.json new file mode 100644 index 000000000..a311861a7 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_exec_status_expected.json @@ -0,0 +1,16 @@ +{ + "routingExecId": 1, + "scheduleEntryId": 1, + "routingSpecId": null, + "runStart": "2025-01-29T00:00:00.000Z[UTC]", + "runStop": "2025-01-30T00:00:00.000Z[UTC]", + "numMessages": 10, + "numErrors": 1, + "numPlatforms": 1, + "lastMsgTime": "2025-01-31T00:00:00.000Z[UTC]", + "lastActivity": "2025-01-31T19:05:06.354Z[UTC]", + "runStatus": "Running", + "hostname": "localhost", + "lastInput": null, + "lastOutput": null +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_insert_data.json new file mode 100644 index 000000000..9b06e0e84 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_insert_data.json @@ -0,0 +1,35 @@ +{ + "routingId" : null, + "name" : "Routing test", + "dataSourceId" : null, + "dataSourceName" : "Routing Test Data Source", + "destinationType" : "Test destination", + "destinationArg" : "Test destination arg", + "enableEquations" : false, + "outputFormat" : null, + "outputTZ" : "UTC", + "presGroupName" : "Group1", + "lastModified" : "2025-01-03T18:57:53.613Z[UTC]", + "since" : "2020-07-15T00:00:00Z", + "until" : "2021-07-16T00:00:00Z", + "settlingTimeDelay" : false, + "applyTimeTo" : "Local Receive Time", + "ascendingTime" : false, + "platformIds" : [ ], + "platformNames" : [ ], + "netlistNames" : [ ], + "goesChannels" : [ ], + "properties" : { + "goesChannel" : "1" + }, + "goesSelfTimed" : false, + "goesRandom" : false, + "networkDCP" : false, + "iridium" : false, + "qualityNotifications" : false, + "goesSpacecraftCheck" : false, + "goesSpacecraftSelection" : "East", + "parityCheck" : false, + "paritySelection" : "Good", + "production" : false +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_platform_insert.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_platform_insert.json new file mode 100644 index 000000000..5847b07f5 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_platform_insert.json @@ -0,0 +1,14 @@ +{ + "platformId" : null, + "name" : "Platform 121", + "siteId" : "[SITE_ID]", + "agency" : "USGS", + "configId" : null, + "description" : "Test platform in Davis, CA", + "designator" : "Platform", + "lastModified" : 1738363604754, + "production" : false, + "properties" : { }, + "platformSensors" : [ ], + "transportMedia" : [ ] +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_expected.json new file mode 100644 index 000000000..df816a965 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_expected.json @@ -0,0 +1,44 @@ +{ + "routingId": null, + "name": "Application Routing", + "dataSourceId": 4, + "dataSourceName": "Routing Test Data Source", + "destinationType": "Test consumer", + "destinationArg": "Test consumer arg", + "enableEquations": true, + "outputFormat": "MM/DD/YYYY HH24:MI:SS", + "outputTZ": "UTC", + "presGroupName": "Group2", + "lastModified": "2024-01-03T18:57:53.613Z[UTC]", + "since": "2020-07-15T00:00:00Z", + "until": "2026-07-16T00:00:00Z", + "settlingTimeDelay": false, + "applyTimeTo": "Local Receive Time", + "ascendingTime": false, + "platformIds": [ + + ], + "platformNames": [ + + ], + "netlistNames": [ + + ], + "goesChannels": [ + + ], + "properties": { + "goesSelfTimed": "false", + "goesChannel": "1" + }, + "goesSelfTimed": false, + "goesRandom": false, + "networkDCP": false, + "iridium": false, + "qualityNotifications": false, + "goesSpacecraftCheck": false, + "goesSpacecraftSelection": "East", + "parityCheck": false, + "paritySelection": "Good", + "production": false +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_insert_data.json new file mode 100644 index 000000000..4e6c29f37 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_post_delete_insert_data.json @@ -0,0 +1,36 @@ +{ + "routingId" : null, + "name" : "Application Routing", + "dataSourceId" : null, + "dataSourceName" : "Routing Test Data Source", + "destinationType" : "Test consumer", + "destinationArg" : "Test consumer arg", + "enableEquations" : true, + "outputFormat" : "MM/DD/YYYY HH24:MI:SS", + "outputTZ" : "UTC", + "presGroupName" : "Group2", + "lastModified" : "2024-01-03T18:57:53.613Z[UTC]", + "since" : "2020-07-15T00:00:00Z", + "until" : "2026-07-16T00:00:00Z", + "settlingTimeDelay" : true, + "applyTimeTo" : "Local Receive Time", + "ascendingTime" : false, + "platformIds" : [ ], + "platformNames" : [ ], + "netlistNames" : [ ], + "goesChannels" : [ ], + "properties" : { + "goesChannel" : "1", + "goesSelfTimed" : false + }, + "goesSelfTimed" : false, + "goesRandom" : true, + "networkDCP" : false, + "iridium" : true, + "qualityNotifications" : false, + "goesSpacecraftCheck" : false, + "goesSpacecraftSelection" : "East", + "parityCheck" : true, + "paritySelection" : "Good", + "production" : false +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_refs_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_refs_expected.json new file mode 100644 index 000000000..a5261d98e --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_refs_expected.json @@ -0,0 +1,8 @@ +{ + "schedEntryId": null, + "name": "Test schedule", + "appName": "Computational App", + "routingSpecName": "Routing test", + "enabled": true, + "lastModified": "2025-01-03T23:57:38.782Z[UTC]" +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_insert_data.json new file mode 100644 index 000000000..24be4336d --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_insert_data.json @@ -0,0 +1,13 @@ +{ + "schedEntryId" : null, + "name" : "Test schedule", + "appId" : null, + "appName" : null, + "routingSpecId" : null, + "routingSpecName" : "Routing test", + "enabled" : true, + "lastModified" : 1735932339051, + "startTime" : 1735932339051, + "timeZone" : "UTC", + "runInterval" : "daily" +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_expected.json new file mode 100644 index 000000000..ed4373531 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_expected.json @@ -0,0 +1,13 @@ +{ + "schedEntryId": null, + "name": "Application Scheduling", + "appId": null, + "appName": null, + "routingSpecId": 6, + "routingSpecName": "Routing test", + "enabled": true, + "lastModified": "2025-01-03T23:03:01.956Z[UTC]", + "startTime": "2025-01-03T19:25:39.051Z[UTC]", + "timeZone": "EST", + "runInterval": "monthly" +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_insert_data.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_insert_data.json new file mode 100644 index 000000000..1590daaea --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_schedule_post_delete_insert_data.json @@ -0,0 +1,13 @@ +{ + "schedEntryId" : null, + "name" : "Application Scheduling", + "appId" : null, + "appName" : null, + "routingSpecId" : null, + "routingSpecName" : "Routing test", + "enabled" : true, + "lastModified" : 1735932339051, + "startTime" : 1735932339051, + "timeZone" : "EST", + "runInterval" : "monthly" +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_site_insert.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_site_insert.json new file mode 100644 index 000000000..2de948aab --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_site_insert.json @@ -0,0 +1,19 @@ +{ + "siteId" : null, + "sitenames" : { }, + "description" : "Test site in Davis, CA", + "latitude" : "38.55", + "longitude" : "-121.75", + "elevation" : 0.0, + "elevUnits" : "ft", + "nearestCity" : "Davis", + "timezone" : "PST", + "state" : "CA", + "country" : "USA", + "region" : null, + "active" : true, + "locationType" : null, + "publicName" : "Platform 12 Test Site", + "properties" : { }, + "lastModified" : 1738363296998 +} \ No newline at end of file diff --git a/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_status_expected.json b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_status_expected.json new file mode 100644 index 000000000..88feff6f9 --- /dev/null +++ b/opendcs-rest-api/src/test/resources/org/opendcs/odcsapi/res/it/OPEN_TSDB/routing_status_expected.json @@ -0,0 +1,14 @@ +{ + "routingSpecId" : null, + "name" : "Test schedule", + "scheduleEntryId" : null, + "appId" : null, + "appName" : null, + "runInterval" : "runInterval", + "lastActivity" : "2025-01-03T21:14:47.937Z[UTC]", + "lastMsgTime" : null, + "numMessages" : 0, + "numErrors" : 0, + "enabled" : true, + "manual" : false +} \ No newline at end of file