fixed async bug in active object + added AllTests for scala tests

This commit is contained in:
Jonas Boner 2009-07-04 06:38:47 +02:00
parent 800f3bc917
commit d75d769351
14 changed files with 757 additions and 380 deletions

933
akka.iws

File diff suppressed because it is too large Load diff

View file

@ -2,14 +2,6 @@
VERSION=0.5 VERSION=0.5
#if [ $# -gt 1 ];
#then
# echo 'USAGE: bin/start-akka-server.sh'
# exit 1
#fi
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
BASE_DIR=$(dirname $0)/.. BASE_DIR=$(dirname $0)/..
echo 'Starting Akka Kernel from directory' $BASE_DIR echo 'Starting Akka Kernel from directory' $BASE_DIR

View file

@ -0,0 +1,38 @@
package se.scalablesolutions.akka.api;
import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
public class AllTests extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite("All tests");
// Java tests
suite.addTestSuite(InMemoryStateTest.class);
suite.addTestSuite(InMemNestedStateTest.class);
suite.addTestSuite(PersistentStateTest.class);
suite.addTestSuite(PersistentNestedStateTest.class);
suite.addTestSuite(RemoteInMemoryStateTest.class);
suite.addTestSuite(RemotePersistentStateTest.class);
suite.addTestSuite(ActiveObjectGuiceConfiguratorTest.class);
suite.addTestSuite(RestTest.class);
// Scala tests
//suite.addTestSuite(se.scalablesolutions.akka.kernel.SupervisorSpec.class);
/*
suite.addTestSuite(se.scalablesolutions.akka.kernel.RemoteSupervisorSpec.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.reactor.EventBasedDispatcherTest.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.reactor.ThreadBasedDispatcherTest.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.actor.ActorSpec.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.actor.RemoteActorSpec.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.actor.InMemStatefulActor.class);
suite.addTestSuite(se.scalablesolutions.akka.kernel.actor.PersistentActor.class);
*/
return suite;
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}

View file

@ -70,8 +70,8 @@ public class PersistentNestedStateTest extends TestCase {
PersistentStatefulNested nested = conf.getActiveObject(PersistentStatefulNested.class); PersistentStatefulNested nested = conf.getActiveObject(PersistentStatefulNested.class);
nested.setVectorState("init"); // set init state nested.setVectorState("init"); // set init state
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state", nested); // transactionrequired stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state", nested); // transactionrequired
assertEquals(3, stateful.getVectorLength()); // BAD: keeps one element since last test assertEquals(2, stateful.getVectorLength()); // BAD: keeps one element since last test
assertEquals(3, nested.getVectorLength()); assertEquals(2, nested.getVectorLength());
} }
public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() { public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() {

View file

@ -15,8 +15,6 @@ public class RemotePersistentStateTest extends TestCase {
static String messageLog = ""; static String messageLog = "";
static { static {
se.scalablesolutions.akka.kernel.Kernel$.MODULE$.config();
System.setProperty("storage-config", "config");
Kernel.startCassandra(); Kernel.startCassandra();
Kernel.startRemoteService(); Kernel.startRemoteService();
} }
@ -28,8 +26,8 @@ public class RemotePersistentStateTest extends TestCase {
conf.configureActiveObjects( conf.configureActiveObjects(
new RestartStrategy(new AllForOne(), 3, 5000), new RestartStrategy(new AllForOne(), 3, 5000),
new Component[] { new Component[] {
new Component(PersistentStateful.class, new LifeCycle(new Permanent(), 1000), 1000, new RemoteAddress("localhost", 9999)), new Component(PersistentStateful.class, new LifeCycle(new Permanent(), 1000), 1000000, new RemoteAddress("localhost", 9999)),
new Component(PersistentFailer.class, new LifeCycle(new Permanent(), 1000), 1000, new RemoteAddress("localhost", 9999)) new Component(PersistentFailer.class, new LifeCycle(new Permanent(), 1000), 1000000, new RemoteAddress("localhost", 9999))
}).supervise(); }).supervise();
} }
@ -43,13 +41,13 @@ public class RemotePersistentStateTest extends TestCase {
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired
assertEquals("new state", stateful.getMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess")); assertEquals("new state", stateful.getMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess"));
} }
public void testMapShouldRollbackStateForStatefulServerInCaseOfFailure() { public void testMapShouldRollbackStateForStatefulServerInCaseOfFailure() {
PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class); PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class);
stateful.setMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state stateful.setMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state
PersistentFailer failer = conf.getActiveObject(PersistentFailer.class); PersistentFailer failer = conf.getActiveObject(PersistentFailer.class);
try { try {
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "MapShouldRollBack", failer); // call failing transactionrequired method
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (RuntimeException e) { } catch (RuntimeException e) {
} // expected } // expected
@ -58,22 +56,21 @@ public class RemotePersistentStateTest extends TestCase {
public void testVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess() { public void testVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class); PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class);
stateful.setVectorState("init"); // set init state int init = stateful.getVectorLength();
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "VectorShouldNotRollback"); // transactionrequired
assertEquals("init", stateful.getVectorState(0)); assertEquals(init + 1, stateful.getVectorLength());
assertEquals("new state", stateful.getVectorState(1));
} }
public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() { public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() {
PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class); PersistentStateful stateful = conf.getActiveObject(PersistentStateful.class);
stateful.setVectorState("init"); // set init state int init = stateful.getVectorLength();
PersistentFailer failer = conf.getActiveObject(PersistentFailer.class); PersistentFailer failer = conf.getActiveObject(PersistentFailer.class);
try { try {
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (RuntimeException e) { } catch (RuntimeException e) {
} // expected } // expected
assertEquals("init", stateful.getVectorState(0)); // check that state is == init state assertEquals(init, stateful.getVectorLength());
} }
public void testRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess() { public void testRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
@ -94,4 +91,5 @@ public class RemotePersistentStateTest extends TestCase {
} // expected } // expected
assertEquals("init", stateful.getRefState()); // check that state is == init state assertEquals("init", stateful.getRefState()); // check that state is == init state
} }
} }

View file

@ -16,6 +16,7 @@ import javax.ws.rs.core.UriBuilder;
import javax.servlet.Servlet; import javax.servlet.Servlet;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import junit.framework.TestCase;
import org.junit.*; import org.junit.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -27,7 +28,7 @@ import java.util.HashMap;
import se.scalablesolutions.akka.kernel.config.*; import se.scalablesolutions.akka.kernel.config.*;
import static se.scalablesolutions.akka.kernel.config.JavaConfig.*; import static se.scalablesolutions.akka.kernel.config.JavaConfig.*;
public class RestTest extends TestSuite { public class RestTest extends TestCase {
private static int PORT = 9998; private static int PORT = 9998;
private static URI URI = UriBuilder.fromUri("http://localhost/").port(PORT).build(); private static URI URI = UriBuilder.fromUri("http://localhost/").port(PORT).build();

View file

@ -192,9 +192,9 @@ sealed class ActorAroundAdvice(val target: Class[_],
private def localDispatch(joinpoint: JoinPoint): AnyRef = { private def localDispatch(joinpoint: JoinPoint): AnyRef = {
val rtti = joinpoint.getRtti.asInstanceOf[MethodRtti] val rtti = joinpoint.getRtti.asInstanceOf[MethodRtti]
if (isOneWay(rtti)) actor ! Invocation(joinpoint) if (isOneWay(rtti)) actor ! Invocation(joinpoint, true)
else { else {
val result = actor !! Invocation(joinpoint) val result = actor !! Invocation(joinpoint, false)
if (result.isDefined) result.get if (result.isDefined) result.get
else throw new IllegalStateException("No result defined for invocation [" + joinpoint + "]") else throw new IllegalStateException("No result defined for invocation [" + joinpoint + "]")
} }
@ -233,22 +233,24 @@ sealed class ActorAroundAdvice(val target: Class[_],
* *
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a> * @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/ */
@serializable private[kernel] case class Invocation(val joinpoint: JoinPoint) { @serializable private[kernel] case class Invocation(val joinpoint: JoinPoint, val isOneWay: Boolean) {
override def toString: String = synchronized { override def toString: String = synchronized {
"Invocation [joinpoint: " + joinpoint.toString + "]" "Invocation [joinpoint: " + joinpoint.toString + ", isOneWay: " + isOneWay + "]"
} }
override def hashCode(): Int = synchronized { override def hashCode(): Int = synchronized {
var result = HashCode.SEED var result = HashCode.SEED
result = HashCode.hash(result, joinpoint) result = HashCode.hash(result, joinpoint)
result = HashCode.hash(result, isOneWay)
result result
} }
override def equals(that: Any): Boolean = synchronized { override def equals(that: Any): Boolean = synchronized {
that != null && that != null &&
that.isInstanceOf[Invocation] && that.isInstanceOf[Invocation] &&
that.asInstanceOf[Invocation].joinpoint == joinpoint that.asInstanceOf[Invocation].joinpoint == joinpoint &&
that.asInstanceOf[Invocation].isOneWay == isOneWay
} }
} }
@ -283,8 +285,9 @@ private[kernel] class Dispatcher extends Actor {
} }
override def receive: PartialFunction[Any, Unit] = { override def receive: PartialFunction[Any, Unit] = {
case Invocation(joinpoint: JoinPoint) => case Invocation(joinpoint, oneWay) =>
reply(joinpoint.proceed) if (oneWay) joinpoint.proceed
else reply(joinpoint.proceed)
case unexpected => case unexpected =>
throw new ActiveObjectException("Unexpected message [" + unexpected + "] sent to [" + this + "]") throw new ActiveObjectException("Unexpected message [" + unexpected + "] sent to [" + this + "]")
} }

View file

@ -32,7 +32,8 @@ final object CassandraStorage extends Logging {
val RUN_THRIFT_SERVICE = kernel.Kernel.config.getBool("akka.storage.cassandra.thrift-server.service", false) val RUN_THRIFT_SERVICE = kernel.Kernel.config.getBool("akka.storage.cassandra.thrift-server.service", false)
val BLOCKING_CALL = kernel.Kernel.config.getInt("akka.storage.cassandra.blocking", 0) val BLOCKING_CALL = kernel.Kernel.config.getInt("akka.storage.cassandra.blocking", 0)
@volatile private[this] var isRunning = false
private[this] val serializer: Serializer = { private[this] val serializer: Serializer = {
kernel.Kernel.config.getString("akka.storage.cassandra.storage-format", "serialization") match { kernel.Kernel.config.getString("akka.storage.cassandra.storage-format", "serialization") match {
case "serialization" => new JavaSerializationSerializer case "serialization" => new JavaSerializationSerializer
@ -48,22 +49,25 @@ final object CassandraStorage extends Logging {
private[this] var thriftServer: CassandraThriftServer = _ private[this] var thriftServer: CassandraThriftServer = _
def start = { def start = synchronized {
try { if (!isRunning) {
server.start try {
log.info("Persistent storage has started up successfully"); server.start
} catch { log.info("Persistent storage has started up successfully");
case e => } catch {
log.error("Could not start up persistent storage") case e =>
throw e log.error("Could not start up persistent storage")
} throw e
if (RUN_THRIFT_SERVICE) { }
thriftServer = new CassandraThriftServer(server) if (RUN_THRIFT_SERVICE) {
thriftServer.start thriftServer = new CassandraThriftServer(server)
thriftServer.start
}
isRunning
} }
} }
def stop = { def stop = if (isRunning) {
//server.storageService.shutdown //server.storageService.shutdown
if (RUN_THRIFT_SERVICE) thriftServer.stop if (RUN_THRIFT_SERVICE) thriftServer.stop
} }

View file

@ -87,7 +87,7 @@ trait Transactional {
/** /**
* Base trait for all state implementations (persistent or in-memory). * Base trait for all state implementations (persistent or in-memory).
* *
* TODO: Make this class inherit scala.collection.mutable.Map and/or java.util.Map * FIXME: Create Java versions using pcollections
* *
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a> * @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/ */
@ -168,9 +168,9 @@ abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] {
def getRange(start: Int, count: Int) def getRange(start: Int, count: Int)
// ---- For Transactional ---- // ---- For Transactional ----
override def begin = changeSet.clear override def begin = {}
override def rollback = {} override def rollback = changeSet.clear
// ---- For scala.collection.mutable.Map ---- // ---- For scala.collection.mutable.Map ----
override def put(key: K, value: V): Option[V] = { override def put(key: K, value: V): Option[V] = {
verifyTransaction verifyTransaction
@ -200,11 +200,7 @@ class CassandraPersistentTransactionalMap extends PersistentTransactionalMap[Str
// ---- For Transactional ---- // ---- For Transactional ----
override def commit = { override def commit = {
CassandraStorage.insertMapStorageEntriesFor(uuid, changeSet.toList) CassandraStorage.insertMapStorageEntriesFor(uuid, changeSet.toList)
// FIXME: should use batch function once the bug is resolved changeSet.clear
// for (entry <- changeSet) {
// val (key, value) = entry
// CassandraStorage.insertMapStorageEntryFor(uuid, key, value)
// }
} }
// ---- Overriding scala.collection.mutable.Map behavior ---- // ---- Overriding scala.collection.mutable.Map behavior ----
@ -316,8 +312,8 @@ abstract class PersistentTransactionalVector[T] extends TransactionalVector[T] {
protected[kernel] var changeSet: List[T] = Nil protected[kernel] var changeSet: List[T] = Nil
// ---- For Transactional ---- // ---- For Transactional ----
override def begin = changeSet = Nil override def begin = {}
override def rollback = {} override def rollback = changeSet = Nil
// ---- For TransactionalVector ---- // ---- For TransactionalVector ----
override def add(value: T) = { override def add(value: T) = {
@ -358,9 +354,8 @@ class CassandraPersistentTransactionalVector extends PersistentTransactionalVect
// ---- For Transactional ---- // ---- For Transactional ----
override def commit = { override def commit = {
// FIXME: should use batch function once the bug is resolved // FIXME: should use batch function once the bug is resolved
for (element <- changeSet) { for (element <- changeSet) CassandraStorage.insertVectorStorageEntryFor(uuid, element)
CassandraStorage.insertVectorStorageEntryFor(uuid, element) changeSet = Nil
}
} }
} }
@ -398,8 +393,11 @@ class TransactionalRef[T] extends Transactional {
} }
class CassandraPersistentTransactionalRef extends TransactionalRef[AnyRef] { class CassandraPersistentTransactionalRef extends TransactionalRef[AnyRef] {
override def commit = if (ref.isDefined) CassandraStorage.insertRefStorageFor(uuid, ref.get) override def commit = if (ref.isDefined) {
CassandraStorage.insertRefStorageFor(uuid, ref.get)
ref = None
}
override def rollback = ref = None
override def get: Option[AnyRef] = { override def get: Option[AnyRef] = {
verifyTransaction verifyTransaction
CassandraStorage.getRefStorageFor(uuid) CassandraStorage.getRefStorageFor(uuid)

View file

@ -1,14 +1,10 @@
package se.scalablesolutions.akka.kernel.actor package se.scalablesolutions.akka.kernel.actor
import concurrent.Lock
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import reactor._
import org.junit.{Test, Before}
import org.junit.Assert._ import org.junit.Assert._
class ActorTest { class ActorSpec extends junit.framework.TestCase {
private val unit = TimeUnit.MILLISECONDS private val unit = TimeUnit.MILLISECONDS
class TestActor extends Actor { class TestActor extends Actor {
@ -20,8 +16,7 @@ class ActorTest {
} }
} }
@Test def testSendOneWay = {
def sendOneWay = {
implicit val timeout = 5000L implicit val timeout = 5000L
var oneWay = "nada" var oneWay = "nada"
val actor = new Actor { val actor = new Actor {
@ -36,8 +31,7 @@ class ActorTest {
actor.stop actor.stop
} }
@Test def testSendReplySync = {
def sendReplySync = {
implicit val timeout = 5000L implicit val timeout = 5000L
val actor = new TestActor val actor = new TestActor
actor.start actor.start
@ -46,8 +40,7 @@ class ActorTest {
actor.stop actor.stop
} }
@Test def testSendReplyAsync = {
def sendReplyAsync = {
implicit val timeout = 5000L implicit val timeout = 5000L
val actor = new TestActor val actor = new TestActor
actor.start actor.start
@ -56,8 +49,7 @@ class ActorTest {
actor.stop actor.stop
} }
@Test def testSendReceiveException = {
def sendReceiveException = {
implicit val timeout = 5000L implicit val timeout = 5000L
val actor = new TestActor val actor = new TestActor
actor.start actor.start

View file

@ -0,0 +1,22 @@
package se.scalablesolutions.akka.kernel
import junit.framework.Test
import junit.framework.TestCase
import junit.framework.TestSuite
object AllTests extends TestCase {
def suite(): Test = {
val suite = new TestSuite("All tests")
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.SupervisorSpec])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.RemoteSupervisorSpec])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.reactor.EventBasedDispatcherTest])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.reactor.ThreadBasedDispatcherTest])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.actor.ActorSpec])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.actor.RemoteActorSpec])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.actor.PersistentActorSpec])
suite.addTestSuite(classOf[se.scalablesolutions.akka.kernel.actor.InMemoryActorSpec])
suite
}
def main(args: Array[String]) = junit.textui.TestRunner.run(suite)
}

View file

@ -96,7 +96,7 @@ class PersistentActorSpec extends TestCase {
stateful.start stateful.start
stateful !! SetVectorState("init") // set init state stateful !! SetVectorState("init") // set init state
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
assertEquals(3, (stateful !! GetVectorSize).get) assertEquals(2, (stateful !! GetVectorSize).get)
} }
@Test @Test

View file

@ -10,7 +10,7 @@ import kernel.config.ScalaConfig._
import com.jteigen.scalatest.JUnit4Runner import com.jteigen.scalatest.JUnit4Runner
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.scalatest._ import org.scalatest.Suite
object Log { object Log {
var messageLog: String = "" var messageLog: String = ""
@ -20,7 +20,7 @@ object Log {
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a> * @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/ */
@RunWith(classOf[JUnit4Runner]) @RunWith(classOf[JUnit4Runner])
class RemoteSupervisorSpec extends Suite { class RemoteSupervisorSpec extends junit.framework.TestCase with Suite {
Kernel.config Kernel.config
new Thread(new Runnable() { new Thread(new Runnable() {

View file

@ -9,13 +9,13 @@ import kernel.config.ScalaConfig._
import com.jteigen.scalatest.JUnit4Runner import com.jteigen.scalatest.JUnit4Runner
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.scalatest._ import org.scalatest.Suite
/** /**
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a> * @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/ */
@RunWith(classOf[JUnit4Runner]) @RunWith(classOf[JUnit4Runner])
class SupervisorSpec extends Suite { class SupervisorSpec extends junit.framework.TestCase with Suite {
var messageLog: String = "" var messageLog: String = ""
var oneWayLog: String = "" var oneWayLog: String = ""