Added 'Versioned' abstraction which is versioned through a VectorClock (including tests).

Signed-off-by: Jonas Bonér <jonas@jonasboner.com>
This commit is contained in:
Jonas Bonér 2012-01-27 14:50:33 +01:00
parent 98d4864e04
commit c944dafda4
2 changed files with 95 additions and 3 deletions

View file

@ -8,6 +8,20 @@ import akka.AkkaException
class VectorClockException(message: String) extends AkkaException(message)
trait Versioned {
def version: VectorClock
}
object Versioned {
def latestVersionOf[T <: Versioned](versioned1: T, versioned2: T): T = {
(versioned1.version compare versioned2.version) match {
case VectorClock.Before versioned2 // version 1 is BEFORE (older), use version 2
case VectorClock.After versioned1 // version 1 is AFTER (newer), use version 1
case VectorClock.Concurrent versioned1 // can't establish a causal relationship between versions => conflict - keeping version 1
}
}
}
/**
* Representation of a Vector-based clock (counting clock), inspired by Lamport logical clocks.
*

View file

@ -6,7 +6,7 @@ import akka.testkit.AkkaSpec
class VectorClockSpec extends AkkaSpec {
import VectorClock._
"An VectorClock" must {
"A VectorClock" must {
"have zero versions when created" in {
val clock = VectorClock()
@ -40,7 +40,7 @@ class VectorClockSpec extends AkkaSpec {
clock1.compare(clock2) must not be (Concurrent)
}
"A clock should not happen before an identical clock" in {
"not happen before an identical clock" in {
val clock1_1 = VectorClock()
val clock2_1 = clock1_1.increment(1, System.currentTimeMillis)
val clock3_1 = clock2_1.increment(2, System.currentTimeMillis)
@ -54,7 +54,7 @@ class VectorClockSpec extends AkkaSpec {
clock4_1.compare(clock4_2) must not be (Concurrent)
}
"A clock should happen before an identical clock with a single additional event" in {
"happen before an identical clock with a single additional event" in {
val clock1_1 = VectorClock()
val clock2_1 = clock1_1.increment(1, System.currentTimeMillis)
val clock3_1 = clock2_1.increment(2, System.currentTimeMillis)
@ -121,4 +121,82 @@ class VectorClockSpec extends AkkaSpec {
clock5_1.compare(clock3_2) must be(After)
}
}
"A Versioned" must {
class TestVersioned(val version: VectorClock = VectorClock()) extends Versioned {
def increment(v: Int, time: Long) = new TestVersioned(version.increment(v, time))
}
"have zero versions when created" in {
val versioned = new TestVersioned()
versioned.version.versions must be(Vector())
}
"happen before an identical versioned with a single additional event" in {
val versioned1_1 = new TestVersioned()
val versioned2_1 = versioned1_1.increment(1, System.currentTimeMillis)
val versioned3_1 = versioned2_1.increment(2, System.currentTimeMillis)
val versioned4_1 = versioned3_1.increment(1, System.currentTimeMillis)
val versioned1_2 = new TestVersioned()
val versioned2_2 = versioned1_2.increment(1, System.currentTimeMillis)
val versioned3_2 = versioned2_2.increment(2, System.currentTimeMillis)
val versioned4_2 = versioned3_2.increment(1, System.currentTimeMillis)
val versioned5_2 = versioned4_2.increment(3, System.currentTimeMillis)
Versioned.latestVersionOf[TestVersioned](versioned4_1, versioned5_2) must be(versioned5_2)
}
"Two versioneds with different events should be concurrent: 1" in {
var versioned1_1 = new TestVersioned()
val versioned2_1 = versioned1_1.increment(1, System.currentTimeMillis)
val versioned1_2 = new TestVersioned()
val versioned2_2 = versioned1_2.increment(2, System.currentTimeMillis)
Versioned.latestVersionOf[TestVersioned](versioned2_1, versioned2_2) must be(versioned2_1)
}
"Two versioneds with different events should be concurrent: 2" in {
val versioned1_3 = new TestVersioned()
val versioned2_3 = versioned1_3.increment(1, System.currentTimeMillis)
val versioned3_3 = versioned2_3.increment(2, System.currentTimeMillis)
val versioned4_3 = versioned3_3.increment(1, System.currentTimeMillis)
val versioned1_4 = new TestVersioned()
val versioned2_4 = versioned1_4.increment(1, System.currentTimeMillis)
val versioned3_4 = versioned2_4.increment(1, System.currentTimeMillis)
val versioned4_4 = versioned3_4.increment(3, System.currentTimeMillis)
Versioned.latestVersionOf[TestVersioned](versioned4_3, versioned4_4) must be(versioned4_3)
}
"be earlier than another versioned if it has an older version" in {
val versioned1_1 = new TestVersioned()
val versioned2_1 = versioned1_1.increment(2, System.currentTimeMillis)
val versioned3_1 = versioned2_1.increment(2, System.currentTimeMillis)
val versioned1_2 = new TestVersioned()
val versioned2_2 = versioned1_2.increment(1, System.currentTimeMillis)
val versioned3_2 = versioned2_2.increment(2, System.currentTimeMillis)
val versioned4_2 = versioned3_2.increment(2, System.currentTimeMillis)
val versioned5_2 = versioned4_2.increment(3, System.currentTimeMillis)
Versioned.latestVersionOf[TestVersioned](versioned3_1, versioned5_2) must be(versioned5_2)
}
"be later than another versioned if it has an newer version" in {
val versioned1_1 = new TestVersioned()
val versioned2_1 = versioned1_1.increment(1, System.currentTimeMillis)
val versioned3_1 = versioned2_1.increment(2, System.currentTimeMillis)
val versioned4_1 = versioned3_1.increment(2, System.currentTimeMillis)
val versioned5_1 = versioned4_1.increment(3, System.currentTimeMillis)
val versioned1_2 = new TestVersioned()
val versioned2_2 = versioned1_2.increment(2, System.currentTimeMillis)
val versioned3_2 = versioned2_2.increment(2, System.currentTimeMillis)
Versioned.latestVersionOf[TestVersioned](versioned5_1, versioned3_2) must be(versioned5_1)
}
}
}