├── .gitignore
├── LICENSE.txt
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── co
│ └── vaughnvernon
│ └── mockroservices
│ ├── exchange
│ └── InformationExchangeReader.java
│ ├── fn
│ ├── Tuple2.java
│ └── Tuple3.java
│ ├── journal
│ ├── EntryBatch.java
│ ├── EntryStream.java
│ ├── EntryStreamReader.java
│ ├── EntryValue.java
│ ├── Journal.java
│ ├── JournalPublisher.java
│ ├── JournalReader.java
│ ├── Repository.java
│ ├── StoredSource.java
│ └── StreamNameBuilder.java
│ ├── kvstore
│ └── KVStore.java
│ ├── messagebus
│ ├── Message.java
│ ├── MessageBus.java
│ ├── MessageExchangeReader.java
│ ├── Subscriber.java
│ └── Topic.java
│ ├── model
│ ├── Command.java
│ ├── DomainEvent.java
│ ├── Id.java
│ ├── ProcessManager.java
│ ├── SourceType.java
│ └── SourcedEntity.java
│ └── serialization
│ └── Serialization.java
└── test
└── java
└── co
└── vaughnvernon
├── SomeEventTypeName.java
├── SomeOtherEventTypeName.java
└── mockroservices
├── Person.java
├── Product.java
├── journal
├── IntegrationTest.java
├── JournalPublisherTest.java
├── JournalTest.java
├── ProductRepository.java
├── RepositoryTest.java
├── SomeEventTypeName.java
└── StreamNameBuilderTest.java
├── kvstore
└── KVStoreTest.java
├── messagebus
├── MessageBusTest.java
└── MessageExchangeReaderTest.java
├── model
├── EventSourcedRootEntityTest.java
└── TestableDomainEvent.java
└── serialization
└── SerializationTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | target/
3 | .metadata/
4 | .classpath
5 | .project
6 | .settings
7 | .DS_Store
8 | *.log
9 | /.idea/
10 | /mockroservices.iml
11 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/LICENSE.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mockroservices-java
2 | Toolkit for creating microservices in a multi-project test environment using mock distributed mechanisms.
3 |
4 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | co.vaughnvernon
4 | mockroservices
5 | 1.2.0
6 |
7 | 1.8
8 | 1.8
9 |
10 |
11 |
12 | junit
13 | junit
14 | 4.13.1
15 | test
16 |
17 |
18 | com.google.code.gson
19 | gson
20 | 2.8.9
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/exchange/InformationExchangeReader.java:
--------------------------------------------------------------------------------
1 | // Copyright � 2017-2022 Vaughn Vernon. All rights reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package co.vaughnvernon.mockroservices.exchange;
16 |
17 | import java.math.BigDecimal;
18 | import java.util.Date;
19 |
20 | import com.google.gson.JsonArray;
21 | import com.google.gson.JsonElement;
22 | import com.google.gson.JsonObject;
23 | import com.google.gson.JsonParser;
24 |
25 | public abstract class InformationExchangeReader {
26 | private JsonObject representation;
27 |
28 | public InformationExchangeReader(final String jsonRepresentation) {
29 | representation = parse(jsonRepresentation);
30 | }
31 |
32 | public InformationExchangeReader(final JsonObject jsonRepresentation) {
33 | this.representation = jsonRepresentation;
34 | }
35 |
36 | public JsonArray array(final String... keys) {
37 | JsonArray array = null;
38 |
39 | JsonElement element = navigateTo(representation(), keys);
40 |
41 | if (element != null) {
42 | array = element.getAsJsonArray();
43 | }
44 |
45 | return array;
46 | }
47 |
48 | public BigDecimal bigDecimalValue(final String... keys) {
49 | final String stringValue = stringValue(keys);
50 |
51 | return stringValue == null ? null : new BigDecimal(stringValue);
52 | }
53 |
54 | public Boolean booleanValue(final String... keys) {
55 | final String stringValue = stringValue(keys);
56 |
57 | return stringValue == null ? null : Boolean.parseBoolean(stringValue);
58 | }
59 |
60 | public Date dateValue(final String... keys) {
61 | final String stringValue = stringValue(keys);
62 |
63 | return stringValue == null ? null : new Date(Long.parseLong(stringValue));
64 | }
65 |
66 | public Double doubleValue(final String... keys) {
67 | final String stringValue = stringValue(keys);
68 |
69 | return stringValue == null ? null : Double.parseDouble(stringValue);
70 | }
71 |
72 | public Float floatValue(final String... keys) {
73 | final String stringValue = stringValue(keys);
74 |
75 | return stringValue == null ? null : Float.parseFloat(stringValue);
76 | }
77 |
78 | public Integer integerValue(final String... keys) {
79 | final String stringValue = stringValue(keys);
80 |
81 | return stringValue == null ? null : Integer.parseInt(stringValue);
82 | }
83 |
84 | public Long longValue(final String... keys) {
85 | final String stringValue = stringValue(keys);
86 |
87 | return stringValue == null ? null : Long.parseLong(stringValue);
88 | }
89 |
90 | public String stringValue(final String... keys) {
91 | return stringValue(representation(), keys);
92 | }
93 |
94 | public String[] stringArrayValue(final String... keys) {
95 | final JsonArray array = array(keys);
96 |
97 | if (array != null) {
98 | final int size = array.size();
99 | final String[] stringArray = new String[size];
100 | for (int idx = 0; idx < size; ++idx) {
101 | stringArray[idx] = array.get(idx).getAsString();
102 | }
103 | return stringArray;
104 | }
105 | return new String[0];
106 | }
107 |
108 | //==============================================
109 | // internal implementation
110 | //==============================================
111 |
112 | protected JsonElement elementFrom(final JsonObject jsonObject, final String key) {
113 | JsonElement element = jsonObject.get(key);
114 |
115 | if (element == null) {
116 | element = jsonObject.get("@" + key);
117 | }
118 |
119 | return element;
120 | }
121 |
122 | protected JsonElement navigateTo(final JsonObject startingJsonObject, final String... keys) {
123 | if (keys.length == 0) {
124 | throw new IllegalArgumentException("Must specify one or more keys.");
125 | }
126 |
127 | int keyIndex = 1;
128 |
129 | JsonElement element = elementFrom(startingJsonObject, keys[0]);
130 |
131 | if (!element.isJsonNull() && !element.isJsonPrimitive() && !element.isJsonArray()) {
132 | JsonObject object = element.getAsJsonObject();
133 |
134 | for ( ; element != null && !element.isJsonPrimitive() && keyIndex < keys.length; ++keyIndex) {
135 |
136 | element = elementFrom(object, keys[keyIndex]);
137 |
138 | if (!element.isJsonPrimitive()) {
139 |
140 | element = elementFrom(object, keys[keyIndex]);
141 |
142 | if (element.isJsonNull()) {
143 | element = null;
144 | } else {
145 | object = element.getAsJsonObject();
146 | }
147 | }
148 | }
149 | }
150 |
151 | if (element != null) {
152 | if (!element.isJsonNull()) {
153 | if (keyIndex != keys.length) {
154 | throw new IllegalArgumentException("Last name must reference a simple value.");
155 | }
156 | } else {
157 | element = null;
158 | }
159 | }
160 |
161 | return element;
162 | }
163 |
164 | protected JsonObject parse(final String jsonRepresentation) {
165 | try {
166 | return JsonParser.parseString(jsonRepresentation).getAsJsonObject();
167 | } catch (Exception e) {
168 | e.printStackTrace();
169 | throw new RuntimeException(e);
170 | }
171 | }
172 |
173 | protected JsonObject representation() {
174 | return representation;
175 | }
176 |
177 | protected String stringValue(final JsonObject startingJsonObject, final String... keys) {
178 | String value = null;
179 |
180 | JsonElement element = navigateTo(startingJsonObject, keys);
181 |
182 | if (element != null) {
183 | value = element.getAsString();
184 | }
185 |
186 | return value;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/fn/Tuple2.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/fn/Tuple2.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/fn/Tuple3.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/fn/Tuple3.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/EntryBatch.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/EntryBatch.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/EntryStream.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/EntryStream.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/EntryStreamReader.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/EntryStreamReader.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/EntryValue.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/EntryValue.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/Journal.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/Journal.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/JournalPublisher.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/JournalPublisher.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/JournalReader.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/JournalReader.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/Repository.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/Repository.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/StoredSource.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/journal/StoredSource.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/journal/StreamNameBuilder.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.journal;
2 |
3 | public final class StreamNameBuilder {
4 | public static String buildStreamNameFor(final Class streamClass, final String value) {
5 | return streamClass.getSimpleName().toLowerCase() + '_' + value;
6 | }
7 | public static String buildStreamNameFor(final Class streamClass) {
8 | return "cat-" + streamClass.getSimpleName().toLowerCase();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/kvstore/KVStore.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/kvstore/KVStore.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/messagebus/Message.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/messagebus/Message.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/messagebus/MessageBus.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/messagebus/MessageBus.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/messagebus/MessageExchangeReader.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/messagebus/MessageExchangeReader.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/messagebus/Subscriber.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/messagebus/Subscriber.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/messagebus/Topic.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/messagebus/Topic.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/Command.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/model/Command.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/DomainEvent.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/model/DomainEvent.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/Id.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.model;
2 |
3 | import java.util.UUID;
4 |
5 | public final class Id {
6 | public final String value;
7 |
8 | public static Id fromExisting(final String referencedId) {
9 | return new Id(referencedId);
10 | }
11 |
12 | public static Id unique() {
13 | return new Id();
14 | }
15 |
16 | @Override
17 | public int hashCode() {
18 | return value.hashCode();
19 | }
20 |
21 | @Override
22 | public boolean equals(final Object other) {
23 | if (other == this) {
24 | return true;
25 | }
26 | if (other == null || other.getClass() != Id.class) {
27 | return false;
28 | }
29 |
30 | final Id otherId = (Id) other;
31 |
32 | return this.value.equals(otherId.value);
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Id[value=" + value + "]";
38 | }
39 |
40 | private Id() {
41 | this.value = UUID.randomUUID().toString();
42 | }
43 |
44 | private Id(final String referencedId) {
45 | this.value = referencedId;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/ProcessManager.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/model/ProcessManager.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/SourceType.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.model;
2 |
3 | public interface SourceType { }
4 |
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/model/SourcedEntity.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/model/SourcedEntity.java
--------------------------------------------------------------------------------
/src/main/java/co/vaughnvernon/mockroservices/serialization/Serialization.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/main/java/co/vaughnvernon/mockroservices/serialization/Serialization.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/SomeEventTypeName.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/SomeEventTypeName.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/SomeOtherEventTypeName.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/SomeOtherEventTypeName.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/Person.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices;
2 |
3 | import java.util.Date;
4 | import java.util.List;
5 | import java.util.UUID;
6 |
7 | import co.vaughnvernon.mockroservices.model.DomainEvent;
8 | import co.vaughnvernon.mockroservices.model.SourcedEntity;
9 |
10 | public class Person {
11 | public final Date birthDate;
12 | public final String name;
13 |
14 | @Override
15 | public boolean equals(final Object other) {
16 | if (other == null || other.getClass() != Person.class) {
17 | return false;
18 | }
19 |
20 | final Person otherPerson = (Person) other;
21 |
22 | return this.name.equals(otherPerson.name) && this.birthDate.equals(otherPerson.birthDate);
23 | }
24 |
25 | public Person(final String name, final Date birthDate) {
26 | this.name = name;
27 | this.birthDate = birthDate;
28 | }
29 |
30 | public static class ClientPerson {
31 | public String name;
32 | public Date birthDate;
33 | }
34 |
35 | public static class ClientPersonWithPrivateSetter {
36 | public String name;
37 | public Date birthDate;
38 |
39 | public ClientPersonWithPrivateSetter() { }
40 |
41 | public static ClientPersonWithPrivateSetter instance(String name, Date birthDate) {
42 | return new ClientPersonWithPrivateSetter(name, birthDate);
43 | }
44 | private ClientPersonWithPrivateSetter(String name, Date birthDate) {
45 | this.name = name;
46 | this.birthDate = birthDate;
47 | }
48 | }
49 |
50 | public static class PersonES extends SourcedEntity {
51 | // [JsonConstructor]
52 | public PersonES(String name, int age, Date birthDate) {
53 | apply(new PersonNamed(UUID.randomUUID().toString(), name, age, birthDate));
54 | }
55 |
56 | public PersonES(List stream, int streamVersion) {
57 | super(stream, streamVersion);
58 | }
59 |
60 | public String id;
61 | public String name;
62 | public int age;
63 | public Date birthDate;
64 |
65 | public void when(PersonNamed personNamed)
66 | {
67 | id = personNamed.id;
68 | name = personNamed.name;
69 | age = personNamed.age;
70 | }
71 |
72 | @Override
73 | public boolean equals(final Object other) {
74 | if (other == null || other.getClass() != PersonES.class) {
75 | return false;
76 | }
77 |
78 | final PersonES otherPerson = (PersonES) other;
79 |
80 | return this.id.equals(otherPerson.id) && this.name.equals(otherPerson.name) && this.age == otherPerson.age;
81 | }
82 | // public override int GetHashCode() => 31 * Id.GetHashCode() * Name.GetHashCode() * Age.GetHashCode();
83 | // public override string ToString() => $"PersonES [Id={Id} Name={Name} Age={Age}]";
84 | }
85 | public static class PersonNamed extends DomainEvent {
86 | public String id;
87 | public String name;
88 | public int age;
89 | public Date birthDate;
90 |
91 | public PersonNamed(String id, String name, int age, Date birthDate)
92 | {
93 | this.id = id;
94 | this.name = name;
95 | this.age = age;
96 | this.birthDate = birthDate;
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/Product.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices;
2 |
3 | import java.util.List;
4 |
5 | import co.vaughnvernon.mockroservices.model.DomainEvent;
6 | import co.vaughnvernon.mockroservices.model.SourcedEntity;
7 |
8 | public class Product extends SourcedEntity {
9 | public String id;
10 | public String name;
11 | public String description;
12 | public long price;
13 |
14 | public Product(final String id, final String name, final String description, final long price) {
15 | apply(new ProductDefined(id, name, description, price));
16 | }
17 |
18 | public Product(final String id, final String name, final String description, final long price, final long validOn) {
19 | apply(new ProductDefined(id, name, description, price, validOn));
20 | }
21 |
22 | public Product(final List eventStream, final int streamVersion) {
23 | super(eventStream, streamVersion);
24 | }
25 |
26 | public void changeDescription(final String description) {
27 | apply(new ProductDescriptionChanged(description));
28 | }
29 |
30 | public void changeDescription(final String description, final long validOn) {
31 | apply(new ProductDescriptionChanged(description, validOn));
32 | }
33 |
34 | public void changeName(final String name) {
35 | apply(new ProductNameChanged(name));
36 | }
37 |
38 | public void changeName(final String name, final long validOn) {
39 | apply(new ProductNameChanged(name, validOn));
40 | }
41 |
42 | public void changePrice(final long price) {
43 | apply(new ProductPriceChanged(price));
44 | }
45 |
46 | public void changePrice(final long price, final long validOn) {
47 | apply(new ProductPriceChanged(price, validOn));
48 | }
49 |
50 | @Override
51 | public boolean equals(Object other) {
52 | if (other == null || other.getClass() != Product.class) {
53 | return false;
54 | }
55 |
56 | final Product otherProduct = (Product) other;
57 |
58 | return this.name.equals(otherProduct.name) &&
59 | this.description.equals(otherProduct.description) &&
60 | this.price == otherProduct.price;
61 | }
62 |
63 | public void when(final ProductDefined event) {
64 | this.id = event.id;
65 | this.name = event.name;
66 | this.description = event.description;
67 | this.price = event.price;
68 | }
69 |
70 | public void when(final ProductDescriptionChanged event) {
71 | this.description = event.description;
72 | }
73 |
74 | public void when(final ProductNameChanged event) {
75 | this.name = event.name;
76 | }
77 |
78 | public void when(final ProductPriceChanged event) {
79 | this.price = event.price;
80 | }
81 |
82 | public static class ProductDefined extends DomainEvent {
83 | public final String id;
84 | public final String description;
85 | public final String name;
86 | public final long price;
87 |
88 | public ProductDefined(final String id, final String name, final String description, final long price) {
89 | this(id, name, description, price, System.currentTimeMillis());
90 | }
91 | ProductDefined(final String id, final String name, final String description, final long price, final long validOn) {
92 | super(validOn, 0);
93 | this.id = id;
94 | this.name = name;
95 | this.description = description;
96 | this.price = price;
97 | }
98 |
99 | @Override
100 | public boolean equals(Object other) {
101 | if (other == null || other.getClass() != ProductDefined.class) {
102 | return false;
103 | }
104 |
105 | final ProductDefined otherProductDefined = (ProductDefined) other;
106 |
107 | return this.id.equals(otherProductDefined.id) &&
108 | this.name.equals(otherProductDefined.name) &&
109 | this.description.equals(otherProductDefined.description) &&
110 | this.price == otherProductDefined.price &&
111 | eventVersion == otherProductDefined.eventVersion;
112 | }
113 | }
114 |
115 | public static class ProductDescriptionChanged extends DomainEvent {
116 | public final String description;
117 |
118 | public ProductDescriptionChanged(final String description) {
119 | this(description, System.currentTimeMillis());
120 | }
121 |
122 | ProductDescriptionChanged(final String description, final long validOn) {
123 | super(validOn, 0);
124 | this.description = description;
125 | }
126 |
127 | @Override
128 | public boolean equals(Object other) {
129 | if (other == null || other.getClass() != ProductDescriptionChanged.class) {
130 | return false;
131 | }
132 |
133 | final ProductDescriptionChanged otherProductDescriptionChanged = (ProductDescriptionChanged) other;
134 |
135 | return this.description.equals(otherProductDescriptionChanged.description) &&
136 | eventVersion == otherProductDescriptionChanged.eventVersion;
137 | }
138 | }
139 |
140 | public static class ProductNameChanged extends DomainEvent {
141 | public final String name;
142 |
143 | public ProductNameChanged(final String name) {
144 | this(name, System.currentTimeMillis());
145 | }
146 |
147 | ProductNameChanged(final String name, final long validOn) {
148 | super(validOn, 0);
149 | this.name = name;
150 | }
151 |
152 | @Override
153 | public boolean equals(Object other) {
154 | if (other == null || other.getClass() != ProductNameChanged.class) {
155 | return false;
156 | }
157 |
158 | final ProductNameChanged otherProductNameChanged = (ProductNameChanged) other;
159 |
160 | return this.name.equals(otherProductNameChanged.name) &&
161 | eventVersion == otherProductNameChanged.eventVersion;
162 | }
163 | }
164 |
165 | public static class ProductPriceChanged extends DomainEvent {
166 | public final long price;
167 |
168 | public ProductPriceChanged(final long price) {
169 | this(price, System.currentTimeMillis());
170 | }
171 |
172 | ProductPriceChanged(final long price, final long validOn) {
173 | super(validOn, 0);
174 | this.price = price;
175 | }
176 |
177 | @Override
178 | public boolean equals(Object other) {
179 | if (other == null || other.getClass() != ProductPriceChanged.class) {
180 | return false;
181 | }
182 |
183 | final ProductPriceChanged otherProductPriceChanged = (ProductPriceChanged) other;
184 |
185 | return this.price == otherProductPriceChanged.price &&
186 | eventVersion == otherProductPriceChanged.eventVersion;
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/IntegrationTest.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.journal;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.util.Date;
6 | import java.util.UUID;
7 |
8 | import org.junit.Test;
9 |
10 | import co.vaughnvernon.mockroservices.Product;
11 | import co.vaughnvernon.mockroservices.journal.JournalPublisherTest.TestSubscriber;
12 | import co.vaughnvernon.mockroservices.messagebus.MessageBus;
13 | import co.vaughnvernon.mockroservices.messagebus.Topic;
14 |
15 | public class IntegrationTest {
16 |
17 | @Test
18 | public void writeReadBiTemporalEvents() {
19 | ProductRepository repository = new ProductRepository("bi-product-journal");
20 | long y2018 = new Date(1000000l).getTime(); //var y2018 = new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero);
21 | long y2019 = new Date(2000000l).getTime(); //var y2019 = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero);
22 | long y2020 = new Date(3000000l).getTime(); //var y2020 = new DateTimeOffset(2020, 1, 1, 0, 0, 0, TimeSpan.Zero);
23 |
24 | String id = UUID.randomUUID().toString();
25 | Product product = new Product(id, "dice-fuz-1", "Fuzzy dice.", 999, y2018);
26 | product.changeName("dice-fuzzy-1", y2020);
27 | product.changeDescription("Fuzzy dice, and all.", y2020);
28 | product.changePrice(995, y2019);
29 | product.changeName("dice-fizzy-1", y2019);
30 | repository.save(Product.class, product);
31 |
32 | Product productAt2018 = repository.productOfId(Product.class, id, y2018);
33 | assertEquals(5, productAt2018.currentVersion);
34 | assertEquals("dice-fuz-1", productAt2018.name);
35 | assertEquals("Fuzzy dice.", productAt2018.description);
36 | assertEquals(999, productAt2018.price);
37 |
38 | Product productAt2019 = repository.productOfId(Product.class, id, y2019);
39 | assertEquals(5, productAt2019.currentVersion);
40 | assertEquals("dice-fizzy-1", productAt2019.name);
41 | assertEquals("Fuzzy dice.", productAt2019.description);
42 | assertEquals(995, productAt2019.price);
43 |
44 | Product productAt2020 = repository.productOfId(Product.class, id, y2020);
45 | assertEquals(5, productAt2020.currentVersion);
46 | assertEquals("dice-fuzzy-1", productAt2020.name);
47 | assertEquals("Fuzzy dice, and all.", productAt2020.description);
48 | assertEquals(995, productAt2020.price);
49 | }
50 |
51 | @Test
52 | public void fromRepositoryToProjection() throws Exception {
53 | MessageBus messageBus = MessageBus.start("test-bus-product");
54 | Topic topic = messageBus.openTopic("cat-product");
55 | String journalName = "product-journal";
56 | JournalPublisher journalPublisher = JournalPublisher.using(journalName, messageBus.name, topic.name);
57 | TestSubscriber subscriber = new JournalPublisherTest.TestSubscriber();
58 | topic.subscribe(subscriber);
59 |
60 | ProductRepository repository = new ProductRepository(journalName);
61 |
62 | Product product1 = new Product(UUID.randomUUID().toString(), "dice-fuz-1", "Fuzzy dice.", 999);
63 | product1.changeName("dice-fuzzy-1");
64 | product1.changeDescription("Fuzzy dice, and all.");
65 | product1.changePrice(995);
66 | repository.save(Product.class, product1);
67 |
68 | Product product2 = new Product(UUID.randomUUID().toString(), "dice-fuz-2", "Fuzzy dice.", 999);
69 | product2.changeName("dice-fuzzy-2");
70 | product2.changeDescription("Fuzzy dice, and all 2.");
71 | product2.changePrice(1000);
72 | repository.save(Product.class, product2);
73 |
74 | subscriber.waitForExpectedMessages(8);
75 | topic.close();
76 | journalPublisher.close();
77 |
78 | assertEquals(8, subscriber.handledMessages.size());
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/JournalPublisherTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/journal/JournalPublisherTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/JournalTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/journal/JournalTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.journal;
2 |
3 | import co.vaughnvernon.mockroservices.Product;
4 |
5 | public class ProductRepository extends Repository {
6 | // readonly
7 | private Journal journal;
8 | // readonly
9 | private EntryStreamReader reader;
10 |
11 | public Product productOfId(String id) {
12 | EntryStream stream = reader.streamFor(id);
13 | return new Product(toSourceStream(stream.stream), stream.streamVersion);
14 | }
15 |
16 | // public Product productOfId(final Class streamClass, String id) {
17 | // EntryStream stream = reader.streamFor(streamClass, id);
18 | // return new Product(toSourceStream(stream.stream), stream.streamVersion);
19 | // }
20 |
21 | public Product productOfId(final Class streamClass, String id, long validOn) {
22 | EntryStream stream = reader.streamFor(streamClass, id);
23 | return new Product(toSourceStream(stream.stream, validOn), stream.streamVersion);
24 | }
25 |
26 | public void save(Product product) {
27 | journal.write(product.id, product.nextVersion(), toBatch(product.applied));
28 | }
29 |
30 | public void save(final Class streamClass, T product) {
31 | journal.write(streamClass, product.id, product.nextVersion(), toBatch(product.applied));
32 | }
33 |
34 | //internal
35 | public ProductRepository(String journalName)
36 | {
37 | journal = Journal.open(journalName);
38 | reader = journal.streamReader();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/RepositoryTest.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.journal;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.time.Instant;
6 | import java.util.Date;
7 |
8 | import org.junit.Test;
9 |
10 | import co.vaughnvernon.mockroservices.Person;
11 | import co.vaughnvernon.mockroservices.Person.PersonES;
12 |
13 | public class RepositoryTest {
14 | @Test
15 | public void testSaveFind()
16 | {
17 | PersonRepository repository = new PersonRepository();
18 | Person.PersonES person = new Person.PersonES("Joe", 40, Date.from(Instant.now()));
19 | repository.save(person);
20 | Person.PersonES joe = repository.personOfId(person.id);
21 | assertEquals(person, joe);
22 | }
23 |
24 | @Test
25 | public void testSaveWithStreamPrefixAndFind()
26 | {
27 | PersonRepository repository = new PersonRepository();
28 | Person.PersonES person = new Person.PersonES("Joe", 40, Date.from(Instant.now()));
29 | repository.save(PersonES.class, person);
30 | Person.PersonES joe = repository.personOfId(StreamNameBuilder.buildStreamNameFor(PersonES.class, person.id));
31 | assertEquals(person, joe);
32 | }
33 |
34 | @Test
35 | public void testSaveFindWithStreamPrefix()
36 | {
37 | PersonRepository repository = new PersonRepository();
38 | Person.PersonES person = new Person.PersonES("Joe", 40, Date.from(Instant.now()));
39 | repository.save(PersonES.class, person);
40 | Person.PersonES joe = repository.personOfId(PersonES.class, person.id);
41 | assertEquals(person, joe);
42 | }
43 |
44 | public class PersonRepository extends Repository {
45 | // readonly
46 | private Journal journal;
47 | // readonly
48 | private EntryStreamReader reader;
49 |
50 | public PersonES personOfId(String id)
51 | {
52 | EntryStream stream = reader.streamFor(id);
53 | return new PersonES(toSourceStream(stream.stream), stream.streamVersion);
54 | }
55 |
56 | public PersonES personOfId(final Class streamClass, String id)
57 | {
58 | EntryStream stream = reader.streamFor(streamClass, id);
59 | return new PersonES(toSourceStream(stream.stream), stream.streamVersion);
60 | }
61 |
62 | public void save(PersonES person) {
63 | journal.write(person.id, person.nextVersion(), toBatch(person.applied));
64 | }
65 |
66 | public void save(final Class streamClass, T person) {
67 | journal.write(streamClass, person.id, person.nextVersion(), toBatch(person.applied));
68 | }
69 | //internal
70 | private PersonRepository()
71 | {
72 | journal = Journal.open("repo-test");
73 | reader = journal.streamReader();
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/SomeEventTypeName.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/journal/SomeEventTypeName.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/journal/StreamNameBuilderTest.java:
--------------------------------------------------------------------------------
1 | package co.vaughnvernon.mockroservices.journal;
2 |
3 | import co.vaughnvernon.mockroservices.Person;
4 | import org.junit.Test;
5 |
6 | import static org.junit.Assert.assertEquals;
7 |
8 | public class StreamNameBuilderTest {
9 |
10 | @Test
11 | public void testThatStreamNameBuilderBuildsCorrectStream() {
12 | assertEquals("person_1234", StreamNameBuilder.buildStreamNameFor(Person.class, "1234"));
13 | }
14 |
15 | @Test
16 | public void TestThatStreamNameBuilderBuildsCorrectCategoryStream() {
17 | assertEquals("cat-person", StreamNameBuilder.buildStreamNameFor(Person.class));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/kvstore/KVStoreTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/kvstore/KVStoreTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/messagebus/MessageBusTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/messagebus/MessageBusTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/messagebus/MessageExchangeReaderTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/messagebus/MessageExchangeReaderTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/model/EventSourcedRootEntityTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/model/EventSourcedRootEntityTest.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/model/TestableDomainEvent.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/model/TestableDomainEvent.java
--------------------------------------------------------------------------------
/src/test/java/co/vaughnvernon/mockroservices/serialization/SerializationTest.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaughnVernon/mockroservices-java/137ab500d76653cc83ff13db1fcf7e2090d5c6ac/src/test/java/co/vaughnvernon/mockroservices/serialization/SerializationTest.java
--------------------------------------------------------------------------------