diff --git a/build.sbt b/build.sbt index 2103744e2..9aadc7a3b 100644 --- a/build.sbt +++ b/build.sbt @@ -6,8 +6,10 @@ lazy val commonSettings = Seq( resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % "2.4.4", + "com.typesafe.akka" %% "akka-testkit" % "2.4.8" % "test", "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0", "org.specs2" %% "specs2-core" % "3.8.3" % "test", + "org.scalatest" %% "scalatest" % "3.0.1" % "test", "org.scodec" %% "scodec-core" % "1.10.0", "org.scodec" %% "scodec-akka" % "0.2.0", "net.java.dev.jna" % "jna" % "4.2.1", diff --git a/common/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala b/common/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala index 961360470..ef4a99afd 100644 --- a/common/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala +++ b/common/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala @@ -87,8 +87,8 @@ object NumberPoolActor { def GetSpecificNumber(pool : NumberPool, number : Int) : Try[Int] = { val original : NumberSelector = pool.Selector val specific : SpecificSelector = new SpecificSelector - specific.SelectionIndex = pool.Numbers.indexOf(number) pool.Selector = specific + specific.SelectionIndex = pool.Numbers.indexOf(number) val out : Try[Int] = pool.Get() pool.Selector = original out diff --git a/common/src/test/scala/objects/NumberPoolActorTest.scala b/common/src/test/scala/objects/NumberPoolActorTest.scala index f0f710dd0..90ffa0f63 100644 --- a/common/src/test/scala/objects/NumberPoolActorTest.scala +++ b/common/src/test/scala/objects/NumberPoolActorTest.scala @@ -2,72 +2,70 @@ package objects import akka.actor.{ActorSystem, Props} -import akka.pattern.ask -import akka.util.Timeout - -import scala.concurrent.duration._ -import com.typesafe.config.ConfigFactory +import akka.testkit.{ImplicitSender, TestKit, TestProbe} import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.actor._ - -import scala.collection.JavaConverters._ +import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} +import net.psforever.objects.guid.actor.{NumberPoolAccessorActor, NumberPoolActor, Register} import net.psforever.objects.guid.pool.ExclusivePool import net.psforever.objects.guid.selector.RandomSelector import net.psforever.objects.guid.source.LimitedNumberSource -import org.specs2.mutable.Specification +import org.specs2.specification.Scope -import scala.concurrent.Await -import scala.util.{Failure, Try} -import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.Duration +import scala.util.Success -class NumberPoolActorTest extends Specification { - val config : java.util.Map[String,Object] = Map( - "akka.loggers" -> List("akka.event.slf4j.Slf4jLogger").asJava, - "akka.loglevel" -> "INFO", - "akka.logging-filter" -> "akka.event.slf4j.Slf4jLoggingFilter" - ).asJava - implicit val timeout = Timeout(100 milliseconds) - - class TestEntity extends IdentifiableEntity - - "NumberPoolActor" in { - val system : akka.actor.ActorSystem = ActorSystem("ActorTest", ConfigFactory.parseMap(config)) - val pool = new ExclusivePool((25 to 50).toList) - pool.Selector = new RandomSelector - val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor") - val future = (poolActor ? NumberPoolActor.GetAnyNumber()).mapTo[Try[Int]] - future.onComplete(value => { - system.terminate - value.foreach { - case Failure(_) => - ko - case _ => ; - } - }) - Await.result(system.whenTerminated, Duration.Inf) - ok +class NumberPoolActorTest extends TestKit(ActorSystem("test")) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll { + override def afterAll { + TestKit.shutdownActorSystem(system) } - "NumberPoolAccessorActor" in { - /* - Notes: - Receiver sets resultObject.complete to true and shuts down the ActorSystem. - If Receiver never gets the appropriate message, Await.result will timeout (and the exception will be caught safely). - */ - val system : akka.actor.ActorSystem = ActorSystem("ActorTest", ConfigFactory.parseMap(config)) - val hub = new NumberPoolHub(new LimitedNumberSource(51)) - val pool = hub.AddPool("test", (25 to 50).toList) - pool.Selector = new RandomSelector - val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor") - val poolAccessor = system.actorOf(Props(classOf[NumberPoolAccessorActor], hub, pool, poolActor), name = "accessor") - val resultObject = new ResolutionObject - resultObject.complete mustEqual false - val receiver = system.actorOf(Props(classOf[Receiver], system, resultObject), "receiver") + "NumberPoolActor" should { + "GetAnyNumber" in { + val pool = new ExclusivePool((25 to 50).toList) + pool.Selector = new RandomSelector + val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor1") + poolActor ! NumberPoolActor.GetAnyNumber() + val msg = receiveOne(Duration.create(100, "ms")) + assert(msg.isInstanceOf[NumberPoolActor.GiveNumber]) + } - val obj : TestEntity = new TestEntity - poolAccessor ! Register(obj, receiver) - try { Await.result(system.whenTerminated, 5 seconds) } catch { case _ : Exception => ; } - resultObject.complete mustEqual true + "GetSpecificNumber" in { + val pool = new ExclusivePool((25 to 50).toList) + pool.Selector = new RandomSelector + val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor2") + poolActor ! NumberPoolActor.GetSpecificNumber(37) + expectMsg(NumberPoolActor.GiveNumber(37, None)) + } + + "NoNumber" in { + val pool = new ExclusivePool((25 to 25).toList) //pool only has one number - 25 + pool.Selector = new RandomSelector + val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor3") + poolActor ! NumberPoolActor.GetAnyNumber() + expectMsg(NumberPoolActor.GiveNumber(25, None)) + + poolActor ! NumberPoolActor.GetAnyNumber() + val msg = receiveOne(Duration.create(100, "ms")) + assert(msg.isInstanceOf[NumberPoolActor.NoNumber]) + } + } + + "NumberPoolAccessorActor" should { + class TestEntity extends IdentifiableEntity + + "register" in { + val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val pool = hub.AddPool("test", (25 to 50).toList) + pool.Selector = new RandomSelector + val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor") + val poolAccessor = system.actorOf(Props(classOf[NumberPoolAccessorActor], hub, pool, poolActor), name = "accessor") + + val obj : TestEntity = new TestEntity + val probe = new TestProbe(system) + poolAccessor ! Register(obj, probe.ref) + probe.expectMsg(Success(obj)) + assert({obj.GUID; true}) //NoGUIDException if failure + } } } diff --git a/common/src/test/scala/objects/Receiver.scala b/common/src/test/scala/objects/Receiver.scala deleted file mode 100644 index bb1894ec5..000000000 --- a/common/src/test/scala/objects/Receiver.scala +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects - -import akka.actor.{Actor, ActorSystem} -import net.psforever.objects.entity.IdentifiableEntity - -import scala.util.{Failure, Success} - -class ResolutionObject { - var complete = false -} - -/** - * This is for file NumberPoolActorTest, for its tests. - * Attempting to define this class in the aforementioned file causes a "can not find constructor" issue. - */ -class Receiver(private val system : ActorSystem, result : ResolutionObject) extends Actor { - def receive : Receive = { - case Success(objct : IdentifiableEntity) => - objct.GUID //this will throw a NoGUIDException if it fails - result.complete = true - system.terminate() - case Failure(ex) => - org.log4s.getLogger.error(s"object did not register - ${ex.getMessage}") - system.terminate() - } -} -//TODO Look into whether that was a legitimate issue or whether I (the user) was in error during Actor initialization later.