From e775967a38510afdb34172e50edd655a32a2de25 Mon Sep 17 00:00:00 2001 From: jcschaff Date: Thu, 21 Nov 2024 01:21:14 -0500 Subject: [PATCH] new BiosimulationsLog to read/write biosimulations JSON log files --- .../org/vcell/sedml/log/BiosimulationLog.java | 98 ++++++ .../vcell/sedml/log/BiosimulationLogTest.java | 299 ++++++++++++++++++ 2 files changed, 397 insertions(+) create mode 100644 vcell-core/src/main/java/org/vcell/sedml/log/BiosimulationLog.java create mode 100644 vcell-core/src/test/java/org/vcell/sedml/log/BiosimulationLogTest.java diff --git a/vcell-core/src/main/java/org/vcell/sedml/log/BiosimulationLog.java b/vcell-core/src/main/java/org/vcell/sedml/log/BiosimulationLog.java new file mode 100644 index 0000000000..0e3755cc2d --- /dev/null +++ b/vcell-core/src/main/java/org/vcell/sedml/log/BiosimulationLog.java @@ -0,0 +1,98 @@ +package org.vcell.sedml.log; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class BiosimulationLog { + + public enum Status { + QUEUED, + SUCCEEDED, + FAILED, + SKIPPED + } + public static class ExceptionLog { + public String type; + public String message; + } + public static class DataSetLog { + public String id; + public Status status; + } + public static class CurveLog { + public String id; + public Status status; + } + public static class SkipReason { + public String type; + public String message; + } + public static class OutputLog { + public String id; + public Status status; + public ExceptionLog exception; + public SkipReason skipReason; + public String output; + public BigDecimal duration; + @JsonInclude(JsonInclude.Include.NON_NULL) public List dataSets; + @JsonInclude(JsonInclude.Include.NON_NULL) public List curves; + } + public static class TaskLog { + public String id; + public Status status; + public ExceptionLog exception; + public SkipReason skipReason; + public String output; + public BigDecimal duration; + public String algorithm; + public String simulatorDetails; + } + public static class SedDocumentLog { + public String location; + public Status status; + public ExceptionLog exception; + public SkipReason skipReason; + public String output; + public BigDecimal duration; + public List tasks = new ArrayList<>(); + public List outputs = new ArrayList<>(); + } + public static class ArchiveLog { + public Status status; + public ExceptionLog exception; + public SkipReason skipReason; + public String output; + public BigDecimal duration; + public List sedDocuments = new ArrayList<>(); + } + + public static ArchiveLog readArchiveLogFromJsonFile(Path path) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(path.toFile(), ArchiveLog.class); + } + + public static ArchiveLog readArchiveLogFromJson(String json) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(json.getBytes(StandardCharsets.UTF_8), ArchiveLog.class); + } + + public static void writeArchiveLogToJsonFile(ArchiveLog archiveLog, Path path) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.writeValue(path.toFile(), archiveLog); + } + + public static String writeArchiveLogToJson(ArchiveLog archiveLog) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + return objectMapper.writeValueAsString(archiveLog); + } +} diff --git a/vcell-core/src/test/java/org/vcell/sedml/log/BiosimulationLogTest.java b/vcell-core/src/test/java/org/vcell/sedml/log/BiosimulationLogTest.java new file mode 100644 index 0000000000..c3e49f2178 --- /dev/null +++ b/vcell-core/src/test/java/org/vcell/sedml/log/BiosimulationLogTest.java @@ -0,0 +1,299 @@ +package org.vcell.sedml.log; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Tag("Fast") +public class BiosimulationLogTest { + static String json_element_beginning = """ + { + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "sedDocuments": [ + { + "location": "doc_1.sedml", + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "tasks": [ + { + "id": "task_1_ss", + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "algorithm": null, + "simulatorDetails": null + }, + { + "id": "task_2_time_course", + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "algorithm": null, + "simulatorDetails": null + } + ], + "outputs": [ + { + "id": "report_1", + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "dataSets": [ + { + "id": "dataset_1", + "status": "QUEUED" + }, + { + "id": "dataset_2", + "status": "QUEUED" + } + ] + }, + { + "id": "plot_1", + "status": "QUEUED", + "exception": null, + "skipReason": null, + "output": null, + "duration": null, + "curves": [ + { + "id": "curve_1", + "status": "QUEUED" + } + ] + } + ] + } + ] + } + """; + static String json_element_success = """ + { + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 6, + "sedDocuments": [ + { + "location": "doc_1.sedml", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 5, + "tasks": [ + { + "id": "task_1_ss", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": "Reading model ... done\\nInitializing simulation ... done\\nExecuting simulation ... done\\n", + "duration": 2, + "algorithm": null, + "simulatorDetails": null + }, + { + "id": "task_2_time_course", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": "Reading model ... done\\nInitializing simulation ... done\\nExecuting simulation ... done\\n", + "duration": 1, + "algorithm": null, + "simulatorDetails": null + } + ], + "outputs": [ + { + "id": "report_1", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 0.1, + "dataSets": [ + { + "id": "dataset_1", + "status": "SUCCEEDED" + }, + { + "id": "dataset_2", + "status": "SUCCEEDED" + } + ] + }, + { + "id": "plot_1", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 0.01, + "curves": [ + { + "id": "curve_1", + "status": "SUCCEEDED" + } + ] + } + ] + } + ] + } + """; + static String json_element_failure = """ + { + "status": "FAILED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 6, + "sedDocuments": [ + { + "location": "doc_1.sedml", + "status": "FAILED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 5, + "tasks": [ + { + "id": "task_1_ss", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": "Reading model ... done\\nInitializing simulation ... done\\nExecuting simulation ... done\\n", + "duration": 2, + "algorithm": null, + "simulatorDetails": null + }, + { + "id": "task_2_time_course", + "status": "FAILED", + "exception": { + "type": "FileNotFoundError", + "message": "Model `model2.xml` does not exist." + }, + "skipReason": null, + "output": null, + "duration": 1, + "algorithm": null, + "simulatorDetails": null + } + ], + "outputs": [ + { + "id": "report_1", + "status": "SUCCEEDED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 0.1, + "dataSets": [ + { + "id": "dataset_1", + "status": "SUCCEEDED" + }, + { + "id": "dataset_2", + "status": "SUCCEEDED" + } + ] + }, + { + "id": "plot_1", + "status": "SKIPPED", + "exception": null, + "skipReason": { + "type": "2DPlotNotImplemented", + "message": "Output skipped because the simulator cannot generate plots." + }, + "output": null, + "duration": 0.01, + "curves": [ + { + "id": "curve_1", + "status": "SKIPPED" + } + ] + } + ] + } + ] + } + """; + static String json_document_failed = """ + { + "status": "FAILED", + "exception": null, + "skipReason": null, + "output": null, + "duration": 6, + "sedDocuments": [ + { + "location": "doc_1.sedml", + "status": "FAILED", + "exception": { + "type": "FileNotFoundError", + "message": "Model `model2.xml` does not exist." + }, + "skipReason": null, + "output": "Reading model ... done\\nInitializing simulation ... done\\nExecuting simulation ... done\\n", + "duration": 5, + "tasks": null, + "outputs": null + } + ] + } + """; + + public static Collection testCases() { + return List.of(json_element_beginning, json_element_success, json_element_failure, json_document_failed); + } + + @ParameterizedTest + @MethodSource("testCases") + public void testArchiveLogRead(String expectedJson) throws IOException { + // create ArchiveLog from given JSON + BiosimulationLog.ArchiveLog archiveLog = BiosimulationLog.readArchiveLogFromJson(expectedJson); + + // generate new JSON string from ArchiveLog + String newJson = BiosimulationLog.writeArchiveLogToJson(archiveLog); + + // compare the original JSON string with the new JSON string - normalize by pretty printing + assertEquals(prettyPrintJson(expectedJson), prettyPrintJson(newJson)); + } + + + public static String prettyPrintJson(String jsonString) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(jsonString); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + return objectMapper.writeValueAsString(jsonNode); + } + +}