Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/PSM schema fix #158

Merged
merged 5 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 13 additions & 1 deletion jpo-ode-core/src/main/resources/schemas/schema-psm.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ValidationMessage> 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<ValidationMessage> validationMessages = schema.validate(node);
assertEquals(String.format("Json validation errors: %s", validationMessages), 0, validationMessages.size());
}

}
49 changes: 49 additions & 0 deletions jpo-ode-core/src/test/resources/json/sample-psm.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
Loading