Skip to content
This repository has been archived by the owner on Mar 16, 2022. It is now read-only.

Commit

Permalink
Add TCK model test for CRDT entities (#491)
Browse files Browse the repository at this point in the history
  • Loading branch information
pvlugter authored Nov 25, 2020
1 parent 047dd2b commit ab459ef
Show file tree
Hide file tree
Showing 15 changed files with 2,879 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,18 @@ public interface CrdtContext extends EntityContext {
* </code> type.
*/
<T extends Crdt> Optional<T> state(Class<T> crdtClass) throws IllegalStateException;

/**
* Get the current write consistency setting for replication of CRDT state.
*
* @return the current write consistency
*/
WriteConsistency getWriteConsistency();

/**
* Set the write consistency setting for replication of CRDT state.
*
* @param writeConsistency the new write consistency to use
*/
void setWriteConsistency(WriteConsistency writeConsistency);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cloudstate.javasupport.crdt;

/** Write consistency setting for replication of state updates for CRDTs. */
public enum WriteConsistency {
/**
* Updates will only be written to the local replica immediately, and then asynchronously
* distributed to other replicas in the background.
*/
LOCAL,

/**
* Updates will be written immediately to a majority of replicas, and then asynchronously
* distributed to remaining replicas in the background.
*/
MAJORITY,

/** Updates will be written immediately to all replicas. */
ALL
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ import io.cloudstate.javasupport.crdt.{
StreamCancelledContext,
StreamedCommandContext,
SubscriptionContext,
Vote
Vote,
WriteConsistency
}
import io.cloudstate.javasupport.impl.ReflectionHelper.{
CommandHandlerInvoker,
Expand Down Expand Up @@ -288,6 +289,9 @@ private final class AdaptedStreamedCommandContext(val delegate: StreamedCommandC
override def newLWWRegister[T](value: T): LWWRegister[T] = delegate.newLWWRegister(value)
override def newORMap[K, V <: Crdt](): ORMap[K, V] = delegate.newORMap()
override def newVote(): Vote = delegate.newVote()

override def getWriteConsistency: WriteConsistency = delegate.getWriteConsistency
override def setWriteConsistency(consistency: WriteConsistency): Unit = delegate.setWriteConsistency(consistency)
}

private final class EntityConstructorInvoker(constructor: Constructor[_]) extends (CrdtCreationContext => AnyRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import io.cloudstate.javasupport.crdt.{
CrdtEntityFactory,
StreamCancelledContext,
StreamedCommandContext,
SubscriptionContext
SubscriptionContext,
WriteConsistency
}
import io.cloudstate.javasupport.impl.{
AbstractClientActionContext,
Expand Down Expand Up @@ -139,7 +140,9 @@ class CrdtImpl(system: ActorSystem, services: Map[String, CrdtStatefulService],
ctx.deactivate()
}
}
verifyNoDelta("creation")
// Doesn't make sense to verify that there's no delta here.
// LWWRegister can have its value set on creation, so there may be a delta.
// verifyNoDelta("creation")

private def verifyNoDelta(scope: String): Unit =
crdt match {
Expand Down Expand Up @@ -399,6 +402,19 @@ class CrdtImpl(system: ActorSystem, services: Map[String, CrdtStatefulService],
override final def entityId(): String = EntityRunner.this.entityId

override def serviceCallFactory(): ServiceCallFactory = rootContext.serviceCallFactory()

private var writeConsistency = WriteConsistency.LOCAL

override final def getWriteConsistency: WriteConsistency = writeConsistency

override final def setWriteConsistency(writeConsistency: WriteConsistency): Unit =
this.writeConsistency = writeConsistency

def crdtWriteConsistency: CrdtWriteConsistency = writeConsistency match {
case WriteConsistency.LOCAL => CrdtWriteConsistency.LOCAL
case WriteConsistency.MAJORITY => CrdtWriteConsistency.MAJORITY
case WriteConsistency.ALL => CrdtWriteConsistency.ALL
}
}

trait CapturingCrdtFactory extends AbstractCrdtFactory with AbstractCrdtContext {
Expand Down Expand Up @@ -430,11 +446,11 @@ class CrdtImpl(system: ActorSystem, services: Map[String, CrdtStatefulService],
final def createCrdtAction(): Option[CrdtStateAction] = crdt match {
case Some(c) =>
if (deleted) {
Some(CrdtStateAction(action = CrdtStateAction.Action.Delete(CrdtDelete())))
Some(CrdtStateAction(action = CrdtStateAction.Action.Delete(CrdtDelete()), crdtWriteConsistency))
} else if (c.hasDelta) {
val delta = c.delta
c.resetDelta()
Some(CrdtStateAction(action = CrdtStateAction.Action.Update(CrdtDelta(delta))))
Some(CrdtStateAction(action = CrdtStateAction.Action.Update(CrdtDelta(delta)), crdtWriteConsistency))
} else {
None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ private[crdt] final class LWWRegisterImpl[T](anySupport: AnySupport) extends Int
override def set(value: T, clock: LWWRegister.Clock, customClockValue: Long): T = {
Objects.requireNonNull(value)
val old = this.value
if (this.value != value) {
if (this.value != value || this.clock != clock || this.customClockValue != customClockValue) {
deltaValue = Some(anySupport.encodeScala(value))
this.value = value
this.clock = clock
this.customClockValue = customClockValue
}
old
}
Expand All @@ -55,6 +57,7 @@ private[crdt] final class LWWRegisterImpl[T](anySupport: AnySupport) extends Int

override val applyDelta = {
case CrdtDelta.Delta.Lwwregister(LWWRegisterDelta(Some(any), _, _, _)) =>
resetDelta()
this.value = anySupport.decode(any).asInstanceOf[T]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.google.protobuf.any.{Any => ScalaPbAny}
import com.google.protobuf.{ByteString, Any => JavaPbAny}
import io.cloudstate.javasupport.impl.{AnySupport, ResolvedServiceMethod, ResolvedType}
import io.cloudstate.javasupport._
import io.cloudstate.javasupport.crdt.{Crdt, CrdtContext, CrdtCreationContext, CrdtEntity, Vote}
import io.cloudstate.javasupport.crdt.{Crdt, CrdtContext, CrdtCreationContext, CrdtEntity, Vote, WriteConsistency}
import org.scalatest.{Matchers, WordSpec}

import scala.compat.java8.OptionConverters._
Expand Down Expand Up @@ -58,6 +58,8 @@ class AnnotationBasedCrdtSupportSpec extends WordSpec with Matchers {
s"The current ${wrongType} CRDT state doesn't match requested type of ${crdtType.getSimpleName}"
)
}
override def getWriteConsistency: WriteConsistency = WriteConsistency.LOCAL
override def setWriteConsistency(writeConsistency: WriteConsistency): Unit = ()
}

object WrappedResolvedType extends ResolvedType[Wrapped] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
import io.cloudstate.javasupport.tck.model.valuebased.ValueEntityTwoEntity;
import io.cloudstate.javasupport.tck.model.action.ActionTckModelBehavior;
import io.cloudstate.javasupport.tck.model.action.ActionTwoBehavior;
import io.cloudstate.javasupport.tck.model.crdt.CrdtTckModelEntity;
import io.cloudstate.javasupport.tck.model.crdt.CrdtTwoEntity;
import io.cloudstate.javasupport.tck.model.eventsourced.EventSourcedTckModelEntity;
import io.cloudstate.javasupport.tck.model.eventsourced.EventSourcedTwoEntity;
import io.cloudstate.samples.shoppingcart.ShoppingCartEntity;
import io.cloudstate.tck.model.Action;
import io.cloudstate.tck.model.Crdt;
import io.cloudstate.tck.model.Eventsourced;
import io.cloudstate.tck.model.valueentity.Valueentity;

Expand All @@ -51,6 +54,11 @@ public static final void main(String[] args) throws Exception {
ShoppingCartEntity.class,
Shoppingcart.getDescriptor().findServiceByName("ShoppingCart"),
com.example.valueentity.shoppingcart.persistence.Domain.getDescriptor())
.registerCrdtEntity(
CrdtTckModelEntity.class,
Crdt.getDescriptor().findServiceByName("CrdtTckModel"),
Crdt.getDescriptor())
.registerCrdtEntity(CrdtTwoEntity.class, Crdt.getDescriptor().findServiceByName("CrdtTwo"))
.registerEventSourcedEntity(
EventSourcedTckModelEntity.class,
Eventsourced.getDescriptor().findServiceByName("EventSourcedTckModel"),
Expand Down
Loading

0 comments on commit ab459ef

Please sign in to comment.