From 2decf09d00fdb7395034ab99d31519bdbdfe8a37 Mon Sep 17 00:00:00 2001 From: Michael Schnell Date: Sun, 17 Nov 2019 10:53:54 +0100 Subject: [PATCH] Added first command --- spring-boot/shared/pom.xml | 6 + .../spring/shared/CreatePersonCommand.java | 88 ++++++++++++ .../shared/CreatePersonCommandTest.java | 108 ++++++++++++++ .../spring/shared/PersonCreatedEventTest.java | 18 ++- .../example/spring/shared/PersonIdTest.java | 74 ++++++++++ .../example/spring/shared/PersonNameTest.java | 134 ++++++++++++++++++ .../commands/CreatePersonCommand.json | 6 + 7 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java create mode 100644 spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java create mode 100644 spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java create mode 100644 spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java create mode 100644 spring-boot/shared/src/test/resources/commands/CreatePersonCommand.json diff --git a/spring-boot/shared/pom.xml b/spring-boot/shared/pom.xml index 1a06a25..4ac3c45 100644 --- a/spring-boot/shared/pom.xml +++ b/spring-boot/shared/pom.xml @@ -28,6 +28,12 @@ 0.2.1-SNAPSHOT + + org.fuin + cqrs-4-java + 0.2.1-SNAPSHOT + + org.fuin objects4j diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java new file mode 100644 index 0000000..9bfb9b6 --- /dev/null +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2015 Michael Schnell. All rights reserved. + * http://www.fuin.org/ + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see http://www.gnu.org/licenses/. + */ +package org.fuin.cqrs4j.example.spring.shared; + +import javax.annotation.concurrent.Immutable; +import javax.json.bind.annotation.JsonbProperty; +import javax.validation.constraints.NotNull; + +import org.fuin.cqrs4j.AbstractAggregateCommand; +import org.fuin.ddd4j.ddd.DomainEventExpectedEntityIdPath; +import org.fuin.ddd4j.ddd.EventType; +import org.fuin.esc.spi.SerializedDataType; +import org.fuin.objects4j.common.Contract; + +/** + * A new person should be created in the system. + */ +@Immutable +@DomainEventExpectedEntityIdPath(PersonId.class) +public final class CreatePersonCommand extends AbstractAggregateCommand { + + private static final long serialVersionUID = 1000L; + + /** Never changing unique event type name. */ + public static final EventType TYPE = new EventType("CreatePersonCommand"); + + /** Unique name used for marshalling/unmarshalling the event. */ + public static final SerializedDataType SER_TYPE = new SerializedDataType(CreatePersonCommand.TYPE.asBaseType()); + + @NotNull + @JsonbProperty("name") + private PersonName name; + + /** + * Protected default constructor for deserialization. + */ + protected CreatePersonCommand() { + super(); + } + + /** + * A new person was created in the system. + * + * @param id Identifies uniquely a person. + * @param name Name of a person. + */ + public CreatePersonCommand(@NotNull final PersonId id, @NotNull final PersonName name) { + super(id, null); + Contract.requireArgNotNull("name", name); + this.name = name; + } + + @Override + public final EventType getEventType() { + return CreatePersonCommand.TYPE; + } + + /** + * Returns: Name of a person. + * + * @return Current value. + */ + @NotNull + public final PersonName getName() { + return name; + } + + @Override + public final String toString() { + return "Create person '" + name + "' with identifier '" + getAggregateRootId() + "'"; + } + +} \ No newline at end of file diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java new file mode 100644 index 0000000..1d4ee4b --- /dev/null +++ b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2015 Michael Schnell. All rights reserved. + * http://www.fuin.org/ + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see http://www.gnu.org/licenses/. + */ +package org.fuin.cqrs4j.example.spring.shared; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.time.ZonedDateTime; +import java.util.UUID; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.json.bind.JsonbConfig; + +import org.apache.commons.io.IOUtils; +import org.eclipse.yasson.FieldAccessStrategy; +import org.fuin.utils4j.Utils4J; +import org.junit.Test; + +// CHECKSTYLE:OFF +public final class CreatePersonCommandTest { + + private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; + + + @Test + public final void testSerializeDeserialize() { + + // PREPARE + final CreatePersonCommand original = createTestee(); + + // TEST + final CreatePersonCommand copy = Utils4J.deserialize(Utils4J.serialize(original)); + + // VERIFY + assertThat(copy).isEqualTo(original); + assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); + assertThat(copy.getName()).isEqualTo(original.getName()); + + } + + @Test + public final void testMarshalUnmarshalJson() { + + // PREPARE + final CreatePersonCommand original = createTestee(); + + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); + + // TEST + final String json = jsonb.toJson(original, CreatePersonCommand.class); + final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); + + // VERIFY + assertThat(copy).isEqualTo(original); + assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); + assertThat(copy.getName()).isEqualTo(original.getName()); + + } + + @Test + public final void testUnmarshalJsonFromFile() throws IOException { + + // PREPARE + final String json = IOUtils.toString(this.getClass().getResourceAsStream("/commands/CreatePersonCommand.json"), + Charset.forName("utf-8")); + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); + + + // TEST + final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); + + // VERIFY + assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552")); + assertThat(copy.getTimestamp()).isEqualTo(ZonedDateTime.parse("2019-11-17T10:27:13.183+01:00[Europe/Berlin]")); + assertThat(copy.getAggregateRootId().asString()).isEqualTo(PERSON_UUID); + assertThat(copy.getName().asString()).isEqualTo("Peter Parker"); + + } + + private CreatePersonCommand createTestee() { + final PersonId personId = new PersonId(UUID.fromString(PERSON_UUID)); + final PersonName personName = new PersonName("Peter Parker"); + return new CreatePersonCommand(personId, personName); + } + +} +// CHECKSTYLE:ON diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java index fb683ca..6244547 100644 --- a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java +++ b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java @@ -1,10 +1,26 @@ +/** + * Copyright (C) 2015 Michael Schnell. All rights reserved. + * http://www.fuin.org/ + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see http://www.gnu.org/licenses/. + */ package org.fuin.cqrs4j.example.spring.shared; import static org.assertj.core.api.Assertions.assertThat; import static org.fuin.utils4j.Utils4J.deserialize; import static org.fuin.utils4j.Utils4J.serialize; -import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.UUID; diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java new file mode 100644 index 0000000..cd8c793 --- /dev/null +++ b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java @@ -0,0 +1,74 @@ +package org.fuin.cqrs4j.example.spring.shared; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +import java.util.UUID; + +import org.fuin.ddd4j.ddd.EntityType; +import org.fuin.ddd4j.ddd.StringBasedEntityType; +import org.fuin.objects4j.common.ConstraintViolationException; +import org.junit.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +/** + * Test for {@link PersonId}. + */ +public final class PersonIdTest { + + private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; + + @Test + public void testEquals() { + EqualsVerifier.forClass(PersonId.class).suppress(Warning.NONFINAL_FIELDS) + .withNonnullFields("entityType", "uuid") + .withPrefabValues(EntityType.class, new StringBasedEntityType("A"), new StringBasedEntityType("B")) + .verify(); + } + + @Test + public void testValueOf() { + final PersonId personId = PersonId.valueOf(PERSON_UUID); + + assertThat(personId.asString()).isEqualTo(PERSON_UUID); + + } + + @Test + public void testValueOfIllegalArgumentCharacter() { + try { + PersonId.valueOf("abc"); + fail(); + } catch (final ConstraintViolationException ex) { + assertThat(ex.getMessage()).isEqualTo("The argument 'value' is not valid: 'abc'"); + } + } + + @Test + public final void testConverterUnmarshal() throws Exception { + + // PREPARE + final String personIdValue = PERSON_UUID; + + // TEST + final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID)); + + // VERIFY + assertThat(personId.asString()).isEqualTo(personIdValue); + } + + @Test + public void testConverterMarshal() throws Exception { + + final PersonId personId = PersonId.valueOf(PERSON_UUID); + + // TEST + final UUID uuid = new PersonId.Converter().adaptToJson(personId); + + // VERIFY + assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID)); + } + +} diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java new file mode 100644 index 0000000..d9ea349 --- /dev/null +++ b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java @@ -0,0 +1,134 @@ +/** + * Copyright (C) 2015 Michael Schnell. All rights reserved. + * http://www.fuin.org/ + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see http://www.gnu.org/licenses/. + */ +package org.fuin.cqrs4j.example.spring.shared; + + +import static org.assertj.core.api.Assertions.assertThat; + +import org.fuin.objects4j.common.ConstraintViolationException; +import org.fuin.utils4j.Utils4J; +import org.junit.Assert; +import org.junit.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +// CHECKSTYLE:OFF +public final class PersonNameTest { + + @Test + public void testSerialize() { + final PersonName original = new PersonName("Peter Parker"); + final PersonName copy = Utils4J.deserialize(Utils4J.serialize(original)); + assertThat(original).isEqualTo(copy); + } + + @Test + public void testHashCodeEquals() { + EqualsVerifier.forClass(PersonName.class).suppress(Warning.NULL_FIELDS).withRedefinedSuperclass().verify(); + } + + @Test + public void testMarshalJson() throws Exception { + + // PREPARE + final String str = "Peter Parker"; + final PersonName testee = new PersonName(str); + + // TEST & VERIFY + assertThat(new PersonName.Converter().adaptToJson(testee)).isEqualTo(str); + assertThat(new PersonName.Converter().adaptToJson(null)).isNull(); + + } + + @Test + public void testUnmarshalJson() throws Exception { + + // PREPARE + final String str = "Peter Parker"; + final PersonName testee = new PersonName(str); + + // TEST & VERIFY + assertThat(new PersonName.Converter().adaptFromJson(str)).isEqualTo(testee); + assertThat(new PersonName.Converter().adaptFromJson(null)).isNull(); + + } + + @Test + public void testIsValid() { + + assertThat(PersonName.isValid(null)).isTrue(); + assertThat(PersonName.isValid("Peter Parker")).isTrue(); + + assertThat(PersonName.isValid("")).isFalse(); + assertThat(PersonName.isValid("123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse(); + + } + + @Test + public void testRequireArgValid() { + + PersonName.requireArgValid("a", "Peter Parker"); + PersonName.requireArgValid("b", null); + + try { + PersonName.requireArgValid("c", ""); + Assert.fail(); + } catch (final ConstraintViolationException ex) { + assertThat(ex.getMessage()).isEqualTo("The argument 'c' is not valid: ''"); + } + + try { + PersonName.requireArgValid("d", "123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345"); + Assert.fail(); + } catch (final ConstraintViolationException ex) { + assertThat(ex.getMessage()) + .isEqualTo("The argument 'd' is not valid: '" + "123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345" + "'"); + } + + } + + @Test + public void testValidator() { + + assertThat(new PersonName.Validator().isValid(null, null)).isTrue(); + assertThat(new PersonName.Validator().isValid("Peter Parker", null)).isTrue(); + + assertThat(new PersonName.Validator().isValid("", null)).isFalse(); + assertThat(new PersonName.Validator().isValid("123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345", null)).isFalse(); + + } + + @Test + public void testValueObjectConverter() { + + assertThat(new PersonName.Converter().getBaseTypeClass()).isEqualTo(String.class); + assertThat(new PersonName.Converter().getValueObjectClass()).isEqualTo(PersonName.class); + assertThat(new PersonName.Converter().isValid(null)).isTrue(); + assertThat(new PersonName.Converter().isValid("Peter Parker")).isTrue(); + + assertThat(new PersonName.Converter().isValid("123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse(); + + } + +} diff --git a/spring-boot/shared/src/test/resources/commands/CreatePersonCommand.json b/spring-boot/shared/src/test/resources/commands/CreatePersonCommand.json new file mode 100644 index 0000000..92ceb71 --- /dev/null +++ b/spring-boot/shared/src/test/resources/commands/CreatePersonCommand.json @@ -0,0 +1,6 @@ +{ + "event-id": "109a77b2-1de2-46fc-aee1-97fa7740a552", + "event-timestamp": "2019-11-17T10:27:13.183+01:00[Europe/Berlin]", + "entity-id-path": "PERSON 84565d62-115e-4502-b7c9-38ad69c64b05", + "name": "Peter Parker" +} \ No newline at end of file