diff --git a/docs/Release_notes.md b/docs/Release_notes.md index 5b41b87ef..90bd4b89b 100644 --- a/docs/Release_notes.md +++ b/docs/Release_notes.md @@ -63,6 +63,7 @@ Enhancements in this release: - [CDOT PR 154](https://github.com/CDOT-CV/jpo-ode/pull/154): Fix: Use odeKafkaProperties env vars to drive producer retries - [USDOT PR 559](https://github.com/usdot-jpo-ode/jpo-ode/pull/559): Update GitHub Actions Third-Party Action Versions - [USDOT PR 561](https://github.com/usdot-jpo-ode/jpo-ode/pull/561): Bump ch.qos.logback:logback-core from 1.4.14 to 1.5.13 in /jpo-ode-plugins +- [CDOT PR 158](https://github.com/CDOT-CV/jpo-ode/pull/158): Release/PSM schema fix Breaking changes: - The major version was incremented due to breaking changes in the 2024 revision of J2735. diff --git a/jpo-ode-core/src/main/resources/schemas/schema-psm.json b/jpo-ode-core/src/main/resources/schemas/schema-psm.json index 08f3cf469..3cfe8ce95 100644 --- a/jpo-ode-core/src/main/resources/schemas/schema-psm.json +++ b/jpo-ode-core/src/main/resources/schemas/schema-psm.json @@ -101,7 +101,19 @@ "type": "string" }, "recordGeneratedBy": { - "type": "null" + "type": [ + "string", + "null" + ], + "enum": [ + "TMC", + "OBU", + "RSU", + "TMC_VIA_SAT", + "TMC_VIA_SNMP", + "UNKNOWN", + null + ] }, "sanitized": { "type": "boolean" diff --git a/jpo-ode-core/src/test/java/us/dot/its/jpo/ode/model/OdePsmDataTest.java b/jpo-ode-core/src/test/java/us/dot/its/jpo/ode/model/OdePsmDataTest.java index 80e2231db..d7662c7d9 100644 --- a/jpo-ode-core/src/test/java/us/dot/its/jpo/ode/model/OdePsmDataTest.java +++ b/jpo-ode-core/src/test/java/us/dot/its/jpo/ode/model/OdePsmDataTest.java @@ -1,49 +1,59 @@ package us.dot.its.jpo.ode.model; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Set; - import org.junit.Test; -import static org.junit.Assert.*; - import us.dot.its.jpo.ode.util.JsonUtils; +/** + * Unit test class for OdePsmData. + */ public class OdePsmDataTest { - private static final String SCHEMA_VERSION = "8"; - private static final String ASN1_STRING = "011d0000201a0000021bd86891de75f84da101c13f042e2214141fff00022c2000270000000163b2cc7986010000"; - - final String json = String.format("{\"metadata\":{\"logFileName\":\"\",\"maxDurationTime\":0,\"odePacketID\":\"\",\"odeReceivedAt\":\"2023-09-21T15:30:14.926500Z\",\"odeTimStartDateTime\":\"\",\"originIp\":\"192.168.16.1\",\"payloadType\":\"us.dot.its.jpo.ode.model.OdePsmPayload\",\"psmSource\":\"RSU\",\"receivedMessageDetails\":{\"rxSource\":\"NA\"},\"recordGeneratedAt\":\"\",\"recordType\":\"psmTx\",\"sanitized\":false,\"schemaVersion\":%s,\"securityResultCode\":\"success\",\"serialId\":{\"bundleId\":0,\"bundleSize\":1,\"recordId\":0,\"serialNumber\":0,\"streamId\":\"06cc1c17-e331-4806-a8ee-456b98c6517b\"},\"asn1\":\"%s\"},\"payload\":{\"data\":{\"accuracy\":{\"orientation\":44.9951935489,\"semiMajor\":1.0,\"semiMinor\":1.0},\"basicType\":\"aPEDESTRIAN\",\"heading\":8898,\"id\":\"24779D7E\",\"msgCnt\":26,\"position\":{\"latitude\":40.2397377,\"longitude\":-74.2761437},\"secMark\":3564,\"speed\":0},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735PSM\"}}", SCHEMA_VERSION, ASN1_STRING); - - @Test - public void shouldDeserializeJson() { - final var deserialized = (OdePsmData)JsonUtils.fromJson(json, OdePsmData.class); - assertNotNull(deserialized); - assertTrue(deserialized.getMetadata() instanceof OdePsmMetadata); - assertTrue(deserialized.getPayload() instanceof OdePsmPayload); - - } - - @Test - public void serializationShouldNotAddClassProperty() { - final var deserialized = (OdePsmData)JsonUtils.fromJson(json, OdePsmData.class); - final String serialized = deserialized.toJson(false); - assertFalse(serialized.contains("@class")); - } - - @Test - public void shouldValidateJson() throws Exception { - final var deserialized = (OdePsmData)JsonUtils.fromJson(json, OdePsmData.class); - final String serialized = deserialized.toJson(false); - - // Load json schema from resource - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); - final JsonSchema schema = factory.getSchema(getClass().getClassLoader().getResource("schemas/schema-psm.json").toURI()); - final JsonNode node = (JsonNode)JsonUtils.fromJson(serialized, JsonNode.class); - Set validationMessages = schema.validate(node); - assertEquals(String.format("Json validation errors: %s", validationMessages), 0, validationMessages.size()); - } + private String loadTestJson() throws IOException { + return new String(getClass().getClassLoader() + .getResourceAsStream("json/sample-psm.json") + .readAllBytes(), StandardCharsets.UTF_8); + } + + @Test + public void shouldDeserializeJson() throws IOException { + final var deserialized = (OdePsmData) JsonUtils.fromJson(loadTestJson(), OdePsmData.class); + assertNotNull(deserialized); + assertTrue(deserialized.getMetadata() instanceof OdePsmMetadata); + assertTrue(deserialized.getPayload() instanceof OdePsmPayload); + + } + + @Test + public void serializationShouldNotAddClassProperty() throws IOException { + final var deserialized = (OdePsmData) JsonUtils.fromJson(loadTestJson(), OdePsmData.class); + final String serialized = deserialized.toJson(false); + assertFalse(serialized.contains("@class")); + } + + @Test + public void shouldValidateJson() throws Exception { + final var deserialized = (OdePsmData) JsonUtils.fromJson(loadTestJson(), OdePsmData.class); + final String serialized = deserialized.toJson(false); + + // Load json schema from resource + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + final JsonSchema schema = + factory.getSchema(getClass().getClassLoader().getResource("schemas/schema-psm.json").toURI()); + final JsonNode node = (JsonNode) JsonUtils.fromJson(serialized, JsonNode.class); + Set validationMessages = schema.validate(node); + assertEquals(String.format("Json validation errors: %s", validationMessages), 0, validationMessages.size()); + } + } diff --git a/jpo-ode-core/src/test/resources/json/sample-psm.json b/jpo-ode-core/src/test/resources/json/sample-psm.json new file mode 100644 index 000000000..c49303d90 --- /dev/null +++ b/jpo-ode-core/src/test/resources/json/sample-psm.json @@ -0,0 +1,49 @@ +{ + "metadata": { + "logFileName": "", + "maxDurationTime": 0, + "odePacketID": "", + "odeReceivedAt": "2023-09-21T15:30:14.926500Z", + "odeTimStartDateTime": "", + "originIp": "192.168.16.1", + "payloadType": "us.dot.its.jpo.ode.model.OdePsmPayload", + "psmSource": "RSU", + "receivedMessageDetails": { + "rxSource": "NA" + }, + "recordGeneratedAt": "", + "recordGeneratedBy": "UNKNOWN", + "recordType": "psmTx", + "sanitized": false, + "schemaVersion": 8, + "securityResultCode": "success", + "serialId": { + "bundleId": 0, + "bundleSize": 1, + "recordId": 0, + "serialNumber": 0, + "streamId": "06cc1c17-e331-4806-a8ee-456b98c6517b" + }, + "asn1": "011d0000201a0000021bd86891de75f84da101c13f042e2214141fff00022c2000270000000163b2cc7986010000" + }, + "payload": { + "data": { + "accuracy": { + "orientation": 44.9951935489, + "semiMajor": 1.0, + "semiMinor": 1.0 + }, + "basicType": "aPEDESTRIAN", + "heading": 8898, + "id": "24779D7E", + "msgCnt": 26, + "position": { + "latitude": 40.2397377, + "longitude": -74.2761437 + }, + "secMark": 3564, + "speed": 0 + }, + "dataType": "us.dot.its.jpo.ode.plugin.j2735.J2735PSM" + } +} \ No newline at end of file