diff --git a/ext.gradle b/ext.gradle
index b897e14c5f9..44c1a90ae60 100644
--- a/ext.gradle
+++ b/ext.gradle
@@ -25,7 +25,7 @@
* as we want to manage the versions in a single source.
*/
-def final SPINE_VERSION = '0.9.65-SNAPSHOT'
+def final SPINE_VERSION = '0.9.66-SNAPSHOT'
ext {
// The version of the modules in this project.
diff --git a/server/src/main/java/io/spine/server/event/EEntity.java b/server/src/main/java/io/spine/server/event/EEntity.java
index 0a84ea22122..ff285dd2145 100644
--- a/server/src/main/java/io/spine/server/event/EEntity.java
+++ b/server/src/main/java/io/spine/server/event/EEntity.java
@@ -23,6 +23,7 @@
import com.google.protobuf.Timestamp;
import io.spine.annotation.Internal;
import io.spine.core.Event;
+import io.spine.core.EventContext;
import io.spine.core.EventEnvelope;
import io.spine.core.EventId;
import io.spine.core.Events;
@@ -33,6 +34,8 @@
import javax.annotation.Nullable;
import java.util.Comparator;
+import static io.spine.util.Exceptions.newIllegalStateException;
+
/**
* Stores an event.
*
@@ -84,7 +87,8 @@ public int compare(EEntity e1, EEntity e2) {
EEntity(Event event) {
this(event.getId());
- updateState(event);
+ final Event compactedEvent = compact(event);
+ updateState(compactedEvent);
}
/**
@@ -124,4 +128,49 @@ public String getType() {
}
return typeName.value();
}
+
+ /**
+ * Obtains the compacted version of the event.
+ *
+ *
A compacted version doesn't contain:
+ *
+ * - the enrichment from the event context
+ * - the enrichment from the origin
+ * - nested origins if the origin is {@link EventContext}
+ *
+ *
+ * @param event the event to compact
+ * @return the compacted event
+ */
+ private static Event compact(Event event) {
+ final EventContext context = event.getContext();
+ final EventContext.Builder resultContext = context.toBuilder()
+ .clearEnrichment();
+ final EventContext.OriginCase originCase = resultContext.getOriginCase();
+ switch (originCase) {
+ case EVENT_CONTEXT:
+ resultContext.setEventContext(context.getEventContext()
+ .toBuilder()
+ .clearOrigin()
+ .clearEnrichment());
+ break;
+ case REJECTION_CONTEXT:
+ resultContext.setRejectionContext(context.getRejectionContext()
+ .toBuilder()
+ .clearEnrichment());
+ break;
+ case COMMAND_CONTEXT:
+ // Does nothing.
+ break;
+ case ORIGIN_NOT_SET:
+ // Does nothing because there is no origin for this event.
+ break;
+ default:
+ throw newIllegalStateException("Unsupported origin case encountered: %s",
+ originCase);
+ }
+ return event.toBuilder()
+ .setContext(resultContext)
+ .build();
+ }
}
diff --git a/server/src/test/java/io/spine/server/event/EventStoreShould.java b/server/src/test/java/io/spine/server/event/EventStoreShould.java
index 708dcdab688..031a4d43d58 100644
--- a/server/src/test/java/io/spine/server/event/EventStoreShould.java
+++ b/server/src/test/java/io/spine/server/event/EventStoreShould.java
@@ -22,20 +22,26 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.MoreExecutors;
+import com.google.protobuf.Any;
import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;
import io.grpc.stub.StreamObserver;
import io.spine.core.ActorContext;
import io.spine.core.CommandContext;
+import io.spine.core.Enrichment;
+import io.spine.core.Enrichment.Container;
import io.spine.core.Event;
import io.spine.core.EventContext;
+import io.spine.core.RejectionContext;
import io.spine.core.TenantId;
+import io.spine.grpc.MemoizingObserver;
import io.spine.server.BoundedContext;
import io.spine.server.command.TestEventFactory;
import io.spine.test.event.ProjectCreated;
import io.spine.test.event.TaskAdded;
import io.spine.testdata.Sample;
import io.spine.time.Durations2;
+import io.spine.time.Time;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -45,14 +51,19 @@
import java.util.concurrent.atomic.AtomicBoolean;
import static com.google.common.collect.Sets.newConcurrentHashSet;
+import static com.google.protobuf.Any.pack;
import static com.google.protobuf.util.Timestamps.add;
import static com.google.protobuf.util.Timestamps.subtract;
+import static io.spine.grpc.StreamObservers.memoizingObserver;
+import static io.spine.protobuf.TypeConverter.toMessage;
import static io.spine.test.Verify.assertContainsAll;
import static io.spine.test.Verify.assertSize;
import static io.spine.time.Time.getCurrentTime;
import static io.spine.type.TypeName.of;
+import static io.spine.validate.Validate.isDefault;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
@@ -210,21 +221,102 @@ public void fail_to_store_events_of_different_tenants_in_a_single_operation() {
.setActorContext(secondTenantActor)
.build();
final EventContext firstTenantContext = EventContext.newBuilder()
- .setCommandContext(firstTenantCommand)
- .build();
+ .setCommandContext(firstTenantCommand)
+ .build();
final EventContext secondTenantContext = EventContext.newBuilder()
- .setCommandContext(secondTenantCommand)
- .build();
+ .setCommandContext(secondTenantCommand)
+ .build();
final Event firstTenantEvent = Event.newBuilder()
.setContext(firstTenantContext)
.build();
final Event secondTenantEvent = Event.newBuilder()
- .setContext(secondTenantContext)
- .build();
+ .setContext(secondTenantContext)
+ .build();
final Collection event = ImmutableSet.of(firstTenantEvent, secondTenantEvent);
eventStore.appendAll(event);
}
+ @Test
+ public void not_store_enrichment_for_EventContext() {
+ final Event event = projectCreated(Time.getCurrentTime());
+ final Event enriched = event.toBuilder()
+ .setContext(event.getContext()
+ .toBuilder()
+ .setEnrichment(newEnrichment()))
+ .build();
+ eventStore.append(enriched);
+ final MemoizingObserver observer = memoizingObserver();
+ eventStore.read(EventStreamQuery.getDefaultInstance(), observer);
+ final EventContext context = observer.responses()
+ .get(0)
+ .getContext();
+ assertTrue(isDefault(context.getEnrichment()));
+ }
+
+ @Test
+ public void not_store_enrichment_for_origin_of_RejectionContext_type() {
+ final RejectionContext originContext = RejectionContext.newBuilder()
+ .setEnrichment(newEnrichment())
+ .build();
+ final Event event = projectCreated(Time.getCurrentTime());
+ final Event enriched = event.toBuilder()
+ .setContext(event.getContext()
+ .toBuilder()
+ .setRejectionContext(originContext))
+ .build();
+ eventStore.append(enriched);
+ final MemoizingObserver observer = memoizingObserver();
+ eventStore.read(EventStreamQuery.getDefaultInstance(), observer);
+ final RejectionContext loadedOriginContext = observer.responses()
+ .get(0)
+ .getContext()
+ .getRejectionContext();
+ assertTrue(isDefault(loadedOriginContext.getEnrichment()));
+ }
+
+ @Test
+ public void not_store_enrichment_for_origin_of_EventContext_type() {
+ final EventContext.Builder originContext = EventContext.newBuilder()
+ .setEnrichment(newEnrichment());
+ final Event event = projectCreated(Time.getCurrentTime());
+ final Event enriched = event.toBuilder()
+ .setContext(event.getContext()
+ .toBuilder()
+ .setEventContext(originContext))
+ .build();
+ eventStore.append(enriched);
+ final MemoizingObserver observer = memoizingObserver();
+ eventStore.read(EventStreamQuery.getDefaultInstance(), observer);
+ final EventContext loadedOriginContext = observer.responses()
+ .get(0)
+ .getContext()
+ .getEventContext();
+ assertTrue(isDefault(loadedOriginContext.getEnrichment()));
+ }
+
+ @Test
+ public void not_store_nested_origins_for_EventContext_origin() {
+ final EventContext.Builder context = EventContext.newBuilder()
+ .setEnrichment(newEnrichment());
+ final EventContext originContext = EventContext.newBuilder()
+ .setEventContext(context)
+ .build();
+ final Event event = projectCreated(Time.getCurrentTime());
+ final Event enriched = event.toBuilder()
+ .setContext(event.getContext()
+ .toBuilder()
+ .setEventContext(originContext))
+ .build();
+ eventStore.append(enriched);
+ final MemoizingObserver observer = memoizingObserver();
+ eventStore.read(EventStreamQuery.getDefaultInstance(), observer);
+ final EventContext loadedOriginContext = observer.responses()
+ .get(0)
+ .getContext()
+ .getEventContext();
+ assertTrue(isDefault(loadedOriginContext.getEventContext()));
+ }
+
/*
* Test environment
*********************/
@@ -245,6 +337,16 @@ private static void assertDone(AtomicBoolean done) {
}
}
+ private static Enrichment newEnrichment() {
+ final String key = "enrichment key";
+ final Any value = pack(toMessage("enrichment value"));
+ return Enrichment.newBuilder()
+ .setContainer(Container.newBuilder()
+ .putItems(key, value)
+ .build())
+ .build();
+ }
+
private static class ResponseObserver implements StreamObserver {
private final Collection resultStorage;
diff --git a/server/src/test/java/io/spine/server/event/given/EventReactorMethodTestEnv.java b/server/src/test/java/io/spine/server/event/given/EventReactorMethodTestEnv.java
deleted file mode 100644
index ab36d14b1c0..00000000000
--- a/server/src/test/java/io/spine/server/event/given/EventReactorMethodTestEnv.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2017, TeamDev Ltd. All rights reserved.
- *
- * Redistribution and use in source and/or binary forms, with or without
- * modification, must retain the above copyright notice and the following
- * disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package io.spine.server.event.given;
-
-import com.google.protobuf.Int32Value;
-import com.google.protobuf.StringValue;
-import com.google.protobuf.UInt32Value;
-import io.spine.core.React;
-import io.spine.server.aggregate.Aggregate;
-import io.spine.server.aggregate.Apply;
-import io.spine.server.command.Assign;
-import io.spine.validate.StringValueVBuilder;
-
-/**
- * @author Alexander Yevsyukov
- */
-public class EventReactorMethodTestEnv {
-
- public static class ReactingAggregate
- extends Aggregate {
-
- public ReactingAggregate(Long id) {
- super(id);
- }
-
- @Assign
- StringValue handle(Int32Value value) {
- final String str = String.valueOf(value.getValue());
- return toMessage(str);
- }
-
- private static StringValue toMessage(String str) {
- return StringValue.newBuilder()
- .setValue(str)
- .build();
- }
-
- @Apply
- private void event(StringValue value) {
- final String currentState = getState().getValue();
- getBuilder().setValue(currentState + System.lineSeparator() + value.getValue());
- }
-
- @React
- StringValue on(UInt32Value value) {
- final String str = String.valueOf(value.getValue());
- return toMessage(str);
- }
- }
-}