diff --git a/src/main/java/dev/cdevents/CDEvents.java b/src/main/java/dev/cdevents/CDEvents.java index 1d837f0..167743d 100644 --- a/src/main/java/dev/cdevents/CDEvents.java +++ b/src/main/java/dev/cdevents/CDEvents.java @@ -74,8 +74,6 @@ public static CloudEvent cdEventAsCloudEvent(CDEvent cdEvent) { * @return valid cdEvent */ public static boolean validateCDEvent(CDEvent cdEvent) { - String cdEventJson = cdEventAsJson(cdEvent); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); JsonSchema jsonSchema = factory.getSchema(cdEvent.eventSchema()); diff --git a/src/main/java/dev/cdevents/config/CustomObjectMapper.java b/src/main/java/dev/cdevents/config/CustomObjectMapper.java index a436bc3..965b359 100644 --- a/src/main/java/dev/cdevents/config/CustomObjectMapper.java +++ b/src/main/java/dev/cdevents/config/CustomObjectMapper.java @@ -1,5 +1,6 @@ package dev.cdevents.config; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -15,6 +16,7 @@ public ObjectMapper customConfiguration() { .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING) .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) .registerModule(new JavaTimeModule()); } } diff --git a/src/test/java/dev/cdevents/CDEventsTest.java b/src/test/java/dev/cdevents/CDEventsTest.java index d5e1ded..930e111 100644 --- a/src/test/java/dev/cdevents/CDEventsTest.java +++ b/src/test/java/dev/cdevents/CDEventsTest.java @@ -1,25 +1,31 @@ package dev.cdevents; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; +import dev.cdevents.config.CustomObjectMapper; import dev.cdevents.constants.CDEventConstants; import dev.cdevents.events.*; import dev.cdevents.exception.CDEventsException; import io.cloudevents.CloudEvent; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; public class CDEventsTest { - @Test - void createPipelineRunFinishedEventAsCloudEvent() { + private static ObjectMapper objectMapper = new CustomObjectMapper().customConfiguration(); + @Test + void createPipelineRunFinishedEventAsCloudEvent() throws IOException { PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); cdEvent.setSource(URI.create("http://dev.cdevents")); @@ -42,6 +48,42 @@ void createPipelineRunFinishedEventAsCloudEvent() { } + @Test + void createPipelineRunFinishedEventOptionalFieldsUnset() throws IOException { + InputStream inputStream = getClass().getResourceAsStream("/pipelinerun_finished_optional.json"); + + JsonNode expectedJsonNode = objectMapper.readTree(inputStream); + JsonNode expectedContextNode = expectedJsonNode.get("context"); + JsonNode expectedSubjectNode = expectedJsonNode.get("subject"); + + PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); + cdEvent.setSource(URI.create(expectedContextNode.get("source").asText())); + cdEvent.setSubjectId(expectedSubjectNode.get("id").asText()); + + String cdEventJson = CDEvents.cdEventAsJson(cdEvent); + JsonNode cdEventJsonNode = objectMapper.readTree(cdEventJson); + JsonNode cdEventContextNode = cdEventJsonNode.get("context"); + JsonNode cdEventSubjectNode = cdEventJsonNode.get("subject"); + + //validates CDEvent against schema + assertTrue(CDEvents.validateCDEvent(cdEvent)); + + //assert context and subject mandatory fields + assertThat(cdEventContextNode.get("type").asText()).isEqualTo(expectedContextNode.get("type").asText()); + assertThat(cdEventContextNode.get("source").asText()).isEqualTo(expectedContextNode.get("source").asText()); + assertEquals(expectedSubjectNode, cdEventSubjectNode); + assertThat(cdEventSubjectNode.get("id").asText()).isEqualTo(expectedSubjectNode.get("id").asText()); + assertThat(cdEventSubjectNode.get("type").asText()).isEqualTo(expectedSubjectNode.get("type").asText()); + + //assert Optional field Subject Source, Content pipelineName, url, outcome, errors are set to null + assertThat(cdEventSubjectNode.get("source")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("pipelineName")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("url")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("outcome")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("errors")).isEqualTo(null); + + } + @Test void testInvalidPipelineRunFinishedEventWithNoSubject() { PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent(); @@ -90,6 +132,41 @@ void testInvalidPipelineRunQueuedEventWithNoSubject() { assertThat(exception.getMessage()).isEqualTo(expectedError); } + @Test + void createPipelineRunQueuedEventWithOptionalFieldsUnset() throws IOException { + InputStream inputStream = getClass().getResourceAsStream("/pipelinerun_queued_optional.json"); + + JsonNode expectedJsonNode = objectMapper.readTree(inputStream); + JsonNode expectedContextNode = expectedJsonNode.get("context"); + JsonNode expectedSubjectNode = expectedJsonNode.get("subject"); + + PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); + cdEvent.setSource(URI.create(expectedContextNode.get("source").asText())); + cdEvent.setSubjectId(expectedSubjectNode.get("id").asText()); + + String cdEventJson = CDEvents.cdEventAsJson(cdEvent); + JsonNode cdEventJsonNode = objectMapper.readTree(cdEventJson); + JsonNode cdEventContextNode = cdEventJsonNode.get("context"); + JsonNode cdEventSubjectNode = cdEventJsonNode.get("subject"); + + //validates CDEvent against schema + assertTrue(CDEvents.validateCDEvent(cdEvent)); + + //assert context and subject mandatory fields + assertThat(cdEventContextNode.get("type").asText()).isEqualTo(expectedContextNode.get("type").asText()); + assertThat(cdEventContextNode.get("source").asText()).isEqualTo(expectedContextNode.get("source").asText()); + assertEquals(expectedSubjectNode, cdEventSubjectNode); + assertThat(cdEventSubjectNode.get("id").asText()).isEqualTo(expectedSubjectNode.get("id").asText()); + assertThat(cdEventSubjectNode.get("type").asText()).isEqualTo(expectedSubjectNode.get("type").asText()); + + //assert Optional field Subject Source, pipelineName, url is set to null + assertThat(cdEventSubjectNode.get("source")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("pipelineName")).isEqualTo(null); + assertThat(expectedSubjectNode.get("content").get("url")).isEqualTo(null); + + + } + @Test void testPipelineRunQueuedEventWithCustomData() throws JsonProcessingException { PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent(); @@ -151,6 +228,44 @@ void testInvalidPipelineRunStartedEventWithNoSubject() { assertThat(exception.getMessage()).isEqualTo(expectedError); } + @Test + void createPipelineRunStartedJsonEventWithOptionalFieldsUnset() throws IOException { + + InputStream inputStream = getClass().getResourceAsStream("/pipelinerun_started_optional.json"); + + JsonNode expectedJsonNode = objectMapper.readTree(inputStream); + JsonNode expectedContextNode = expectedJsonNode.get("context"); + JsonNode expectedSubjectNode = expectedJsonNode.get("subject"); + + PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent(); + cdEvent.setSource(URI.create(expectedContextNode.get("source").asText())); + + cdEvent.setSubjectId(expectedSubjectNode.get("id").asText()); + cdEvent.setSubjectPipelineName(expectedSubjectNode.get("content").get("pipelineName").asText()); + cdEvent.setSubjectUrl(URI.create(expectedSubjectNode.get("content").get("url").asText())); + + String cdEventJson = CDEvents.cdEventAsJson(cdEvent); + JsonNode cdEventJsonNode = objectMapper.readTree(cdEventJson); + JsonNode cdEventContextNode = cdEventJsonNode.get("context"); + JsonNode cdEventSubjectNode = cdEventJsonNode.get("subject"); + + //validates CDEvent against schema + assertTrue(CDEvents.validateCDEvent(cdEvent)); + + //assert context and subject mandatory fields + assertThat(cdEventContextNode.get("type").asText()).isEqualTo(expectedContextNode.get("type").asText()); + assertThat(cdEventContextNode.get("source").asText()).isEqualTo(expectedContextNode.get("source").asText()); + assertEquals(expectedSubjectNode, cdEventSubjectNode); + assertThat(cdEventSubjectNode.get("id").asText()).isEqualTo(expectedSubjectNode.get("id").asText()); + assertThat(cdEventSubjectNode.get("type").asText()).isEqualTo(expectedSubjectNode.get("type").asText()); + assertThat(cdEventSubjectNode.get("content").get("pipelineName").asText()).isEqualTo(expectedSubjectNode.get("content").get("pipelineName").asText()); + assertThat(cdEventSubjectNode.get("content").get("url").asText()).isEqualTo(expectedSubjectNode.get("content").get("url").asText()); + + //assert Optional field Subject Source is set to null + assertThat(cdEventSubjectNode.get("source")).isEqualTo(null); + + } + @Test void createTaskRunStartedEventAsCloudEvent() { @@ -189,6 +304,44 @@ void testInvalidTaskRunStartedEventWithNoSubject() { assertThat(exception.getMessage()).isEqualTo(expectedError); } + @Test + void createTaskRunStartedEventJsonWithOptionalFieldsUnset() throws IOException { + InputStream inputStream = getClass().getResourceAsStream("/taskrun_started_optional.json"); + + JsonNode expectedJsonNode = objectMapper.readTree(inputStream); + JsonNode expectedContextNode = expectedJsonNode.get("context"); + JsonNode expectedSubjectNode = expectedJsonNode.get("subject"); + + TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent(); + cdEvent.setSource(URI.create(expectedContextNode.get("source").asText())); + + cdEvent.setSubjectId(expectedSubjectNode.get("id").asText()); + cdEvent.setSubjectPipelineRunId(expectedSubjectNode.get("content").get("pipelineRun").get("id").asText()); + + String cdEventJson = CDEvents.cdEventAsJson(cdEvent); + JsonNode cdEventJsonNode = objectMapper.readTree(cdEventJson); + JsonNode cdEventContextNode = cdEventJsonNode.get("context"); + JsonNode cdEventSubjectNode = cdEventJsonNode.get("subject"); + + //validates CDEvent against schema + assertTrue(CDEvents.validateCDEvent(cdEvent)); + + //assert context and subject mandatory fields + assertThat(cdEventContextNode.get("type").asText()).isEqualTo(expectedContextNode.get("type").asText()); + assertThat(cdEventContextNode.get("source").asText()).isEqualTo(expectedContextNode.get("source").asText()); + assertEquals(expectedSubjectNode, cdEventSubjectNode); + assertThat(cdEventSubjectNode.get("id").asText()).isEqualTo(expectedSubjectNode.get("id").asText()); + assertThat(cdEventSubjectNode.get("type").asText()).isEqualTo(expectedSubjectNode.get("type").asText()); + assertThat(cdEventSubjectNode.get("content").get("pipelineRun").get("id").asText()).isEqualTo(expectedSubjectNode.get("content").get("pipelineRun").get("id").asText()); + + //assert Optional fields Subject Source, Content taskName, URL and pipelineRun Source are set to null + assertThat(cdEventSubjectNode.get("source")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("taskName")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("url")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("pipelineRun").get("source")).isEqualTo(null); + + } + @Test void createTaskRunFinishedEventAsCloudEvent() { @@ -215,6 +368,45 @@ void createTaskRunFinishedEventAsCloudEvent() { assertThat(ceDataJson).isEqualTo(cdEventJson); } + @Test + void createTaskRunFinishedEventJsonWithOptionalFieldsUnset() throws IOException { + + InputStream inputStream = getClass().getResourceAsStream("/taskrun_finished_optional.json"); + + JsonNode expectedJsonNode = objectMapper.readTree(inputStream); + JsonNode expectedContextNode = expectedJsonNode.get("context"); + JsonNode expectedSubjectNode = expectedJsonNode.get("subject"); + + TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); + cdEvent.setSource(URI.create(expectedContextNode.get("source").asText())); + cdEvent.setSubjectId(expectedSubjectNode.get("id").asText()); + cdEvent.setSubjectPipelineRunId(expectedSubjectNode.get("content").get("pipelineRun").get("id").asText()); + + String cdEventJson = CDEvents.cdEventAsJson(cdEvent); + JsonNode cdEventJsonNode = objectMapper.readTree(cdEventJson); + JsonNode cdEventContextNode = cdEventJsonNode.get("context"); + JsonNode cdEventSubjectNode = cdEventJsonNode.get("subject"); + + //validates CDEvent against schema + assertTrue(CDEvents.validateCDEvent(cdEvent)); + + //assert context and subject mandatory fields + assertThat(cdEventContextNode.get("type").asText()).isEqualTo(expectedContextNode.get("type").asText()); + assertThat(cdEventContextNode.get("source").asText()).isEqualTo(expectedContextNode.get("source").asText()); + assertEquals(expectedSubjectNode, cdEventSubjectNode); + assertThat(cdEventSubjectNode.get("id").asText()).isEqualTo(expectedSubjectNode.get("id").asText()); + assertThat(cdEventSubjectNode.get("type").asText()).isEqualTo(expectedSubjectNode.get("type").asText()); + assertThat(cdEventSubjectNode.get("content").get("pipelineRun").get("id").asText()).isEqualTo(expectedSubjectNode.get("content").get("pipelineRun").get("id").asText()); + + //assert Optional fields Subject Source, Content taskName, URL, outcome, errors and pipelineRun Source are set to null + assertThat(cdEventSubjectNode.get("source")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("taskName")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("url")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("outcome")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("errors")).isEqualTo(null); + assertThat(cdEventSubjectNode.get("content").get("pipelineRun").get("source")).isEqualTo(null); + } + @Test void testInvalidTaskRunFinishedEventWithNoSubject() { TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent(); diff --git a/src/test/resources/pipelinerun_finished_optional.json b/src/test/resources/pipelinerun_finished_optional.json new file mode 100644 index 0000000..e63f64d --- /dev/null +++ b/src/test/resources/pipelinerun_finished_optional.json @@ -0,0 +1,18 @@ +{ + "context": { + "id": "123456789", + "type": "dev.cdevents.pipelinerun.finished.0.1.0", + "source": "http://dev.cdevents", + "version": "0.1.2", + "timestamp": "2023-05-24T11:17:06Z" + }, + "customData": { + }, + "customDataContentType": "application/json", + "subject": { + "id": "/dev/pipeline/run/subject", + "type": "PIPELINERUN", + "content": { + } + } +} \ No newline at end of file diff --git a/src/test/resources/pipelinerun_queued_optional.json b/src/test/resources/pipelinerun_queued_optional.json new file mode 100644 index 0000000..8a659bc --- /dev/null +++ b/src/test/resources/pipelinerun_queued_optional.json @@ -0,0 +1,18 @@ +{ + "context": { + "id": "dc0bf5f5-f2e4-44c3-b9a6-1f0cf51b050b", + "type": "dev.cdevents.pipelinerun.queued.0.1.0", + "source": "http://dev.cdevents", + "version": "0.1.2", + "timestamp": "2023-05-24T18:34:41Z" + }, + "customData": { + }, + "customDataContentType": "application/json", + "subject": { + "id": "/dev/pipeline/run/subject", + "type": "PIPELINERUN", + "content": { + } + } +} \ No newline at end of file diff --git a/src/test/resources/pipelinerun_started_optional.json b/src/test/resources/pipelinerun_started_optional.json new file mode 100644 index 0000000..a54cd77 --- /dev/null +++ b/src/test/resources/pipelinerun_started_optional.json @@ -0,0 +1,20 @@ +{ + "context": { + "id": "cbde772c-17ad-490d-aea0-41fb060d1483", + "type": "dev.cdevents.pipelinerun.started.0.1.0", + "source": "http://dev.cdevents", + "version": "0.1.2", + "timestamp": "2023-05-24T18:48:12Z" + }, + "customData": { + }, + "customDataContentType": "application/json", + "subject": { + "id": "/dev/pipeline/run/subject", + "type": "PIPELINERUN", + "content": { + "pipelineName": "test-pipeline-started", + "url": "http://dev/pipeline/url" + } + } +} \ No newline at end of file diff --git a/src/test/resources/taskrun_finished_optional.json b/src/test/resources/taskrun_finished_optional.json new file mode 100644 index 0000000..dffd9f1 --- /dev/null +++ b/src/test/resources/taskrun_finished_optional.json @@ -0,0 +1,21 @@ +{ + "context": { + "id": "49e16403-c5b5-4e2a-9540-160787459a21", + "type": "dev.cdevents.taskrun.finished.0.1.0", + "source": "http://dev.cdevents", + "version": "0.1.2", + "timestamp": "2023-05-24T19:20:57Z" + }, + "customData": { + }, + "customDataContentType": "application/json", + "subject": { + "id": "/dev/task/run/subject", + "type": "TASKRUN", + "content": { + "pipelineRun": { + "id": "/dev/pipeline/run/subject" + } + } + } +} \ No newline at end of file diff --git a/src/test/resources/taskrun_started_optional.json b/src/test/resources/taskrun_started_optional.json new file mode 100644 index 0000000..d5f568d --- /dev/null +++ b/src/test/resources/taskrun_started_optional.json @@ -0,0 +1,21 @@ +{ + "context": { + "id": "f75eb164-947c-4827-9036-9ec7fda38873", + "type": "dev.cdevents.taskrun.started.0.1.0", + "source": "http://dev.cdevents", + "version": "0.1.2", + "timestamp": "2023-05-24T19:16:11Z" + }, + "customData": { + }, + "customDataContentType": "application/json", + "subject": { + "id": "/dev/task/run/subject", + "type": "TASKRUN", + "content": { + "pipelineRun": { + "id": "/dev/pipeline/run/subject" + } + } + } +} \ No newline at end of file