document Specs2 + TestKit, see #2068, plus fix up broken includes

- include move of doc samples out of akka package also in the
  includecode directives
- fix broken serialization docs, which require one thing in the akka
  package
This commit is contained in:
Roland 2012-05-24 22:23:36 +02:00
parent 7d342e5c96
commit dd30e81a1a
44 changed files with 681 additions and 555 deletions

View file

@ -1,91 +1,105 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.serialization
import org.scalatest.matchers.MustMatchers
import akka.testkit._
//#imports
import akka.actor.{ ActorRef, ActorSystem }
import akka.serialization._
import com.typesafe.config.ConfigFactory
//#imports
import akka.actor.ExtensionKey
import akka.actor.ExtendedActorSystem
import akka.actor.Extension
import akka.actor.Address
import akka.remote.RemoteActorRefProvider
//#my-own-serializer
class MyOwnSerializer extends Serializer {
// This is whether "fromBinary" requires a "clazz" or not
def includeManifest: Boolean = false
// Pick a unique identifier for your Serializer,
// you've got a couple of billions to choose from,
// 0 - 16 is reserved by Akka itself
def identifier = 1234567
// "toBinary" serializes the given object to an Array of Bytes
def toBinary(obj: AnyRef): Array[Byte] = {
// Put the code that serializes the object here
//#...
Array[Byte]()
//#...
}
// "fromBinary" deserializes the given array,
// using the type hint (if any, see "includeManifest" above)
// into the optionally provided classLoader.
def fromBinary(bytes: Array[Byte],
clazz: Option[Class[_]]): AnyRef = {
// Put your code that deserializes here
//#...
null
//#...
}
//#extract-transport
package object akka {
// needs to be inside the akka package because accessing unsupported API !
def transportOf(system: actor.ExtendedActorSystem): remote.RemoteTransport =
system.provider match {
case r: remote.RemoteActorRefProvider r.transport
case _
throw new UnsupportedOperationException(
"this method requires the RemoteActorRefProvider to be configured")
}
}
//#my-own-serializer
//#extract-transport
trait MyOwnSerializable
case class Customer(name: String) extends MyOwnSerializable
package docs.serialization {
class SerializationDocSpec extends AkkaSpec {
"demonstrate configuration of serialize messages" in {
//#serialize-messages-config
val config = ConfigFactory.parseString("""
import org.scalatest.matchers.MustMatchers
import akka.testkit._
//#imports
import akka.actor.{ ActorRef, ActorSystem }
import akka.serialization._
import com.typesafe.config.ConfigFactory
//#imports
import akka.actor.ExtensionKey
import akka.actor.ExtendedActorSystem
import akka.actor.Extension
import akka.actor.Address
import akka.remote.RemoteActorRefProvider
//#my-own-serializer
class MyOwnSerializer extends Serializer {
// This is whether "fromBinary" requires a "clazz" or not
def includeManifest: Boolean = false
// Pick a unique identifier for your Serializer,
// you've got a couple of billions to choose from,
// 0 - 16 is reserved by Akka itself
def identifier = 1234567
// "toBinary" serializes the given object to an Array of Bytes
def toBinary(obj: AnyRef): Array[Byte] = {
// Put the code that serializes the object here
//#...
Array[Byte]()
//#...
}
// "fromBinary" deserializes the given array,
// using the type hint (if any, see "includeManifest" above)
// into the optionally provided classLoader.
def fromBinary(bytes: Array[Byte],
clazz: Option[Class[_]]): AnyRef = {
// Put your code that deserializes here
//#...
null
//#...
}
}
//#my-own-serializer
trait MyOwnSerializable
case class Customer(name: String) extends MyOwnSerializable
class SerializationDocSpec extends AkkaSpec {
"demonstrate configuration of serialize messages" in {
//#serialize-messages-config
val config = ConfigFactory.parseString("""
akka {
actor {
serialize-messages = on
}
}
""")
//#serialize-messages-config
val a = ActorSystem("system", config)
a.settings.SerializeAllMessages must be(true)
a.shutdown()
}
//#serialize-messages-config
val a = ActorSystem("system", config)
a.settings.SerializeAllMessages must be(true)
a.shutdown()
}
"demonstrate configuration of serialize creators" in {
//#serialize-creators-config
val config = ConfigFactory.parseString("""
"demonstrate configuration of serialize creators" in {
//#serialize-creators-config
val config = ConfigFactory.parseString("""
akka {
actor {
serialize-creators = on
}
}
""")
//#serialize-creators-config
val a = ActorSystem("system", config)
a.settings.SerializeAllCreators must be(true)
a.shutdown()
}
//#serialize-creators-config
val a = ActorSystem("system", config)
a.settings.SerializeAllCreators must be(true)
a.shutdown()
}
"demonstrate configuration of serializers" in {
//#serialize-serializers-config
val config = ConfigFactory.parseString("""
"demonstrate configuration of serializers" in {
//#serialize-serializers-config
val config = ConfigFactory.parseString("""
akka {
actor {
serializers {
@ -96,14 +110,14 @@ class SerializationDocSpec extends AkkaSpec {
}
}
""")
//#serialize-serializers-config
val a = ActorSystem("system", config)
a.shutdown()
}
//#serialize-serializers-config
val a = ActorSystem("system", config)
a.shutdown()
}
"demonstrate configuration of serialization-bindings" in {
//#serialization-bindings-config
val config = ConfigFactory.parseString("""
"demonstrate configuration of serialization-bindings" in {
//#serialization-bindings-config
val config = ConfigFactory.parseString("""
akka {
actor {
serializers {
@ -122,96 +136,92 @@ class SerializationDocSpec extends AkkaSpec {
}
}
""")
//#serialization-bindings-config
val a = ActorSystem("system", config)
SerializationExtension(a).serializerFor(classOf[String]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializerFor(classOf[Customer]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializerFor(classOf[java.lang.Boolean]).getClass must equal(classOf[MyOwnSerializer])
a.shutdown()
}
"demonstrate the programmatic API" in {
//#programmatic
val system = ActorSystem("example")
// Get the Serialization Extension
val serialization = SerializationExtension(system)
// Have something to serialize
val original = "woohoo"
// Find the Serializer for it
val serializer = serialization.findSerializerFor(original)
// Turn it into bytes
val bytes = serializer.toBinary(original)
// Turn it back into an object
val back = serializer.fromBinary(bytes, manifest = None)
// Voilá!
back must equal(original)
//#programmatic
system.shutdown()
}
"demonstrate serialization of ActorRefs" in {
val theActorRef: ActorRef = system.deadLetters
val theActorSystem: ActorSystem = system
//#actorref-serializer
// Serialize
// (beneath toBinary)
// If there is no transportAddress,
// it means that either this Serializer isn't called
// within a piece of code that sets it,
// so either you need to supply your own,
// or simply use the local path.
val identifier: String = Serialization.currentTransportAddress.value match {
case null theActorRef.path.toString
case address theActorRef.path.toStringWithAddress(address)
}
// Then just serialize the identifier however you like
// Deserialize
// (beneath fromBinary)
val deserializedActorRef = theActorSystem actorFor identifier
// Then just use the ActorRef
//#actorref-serializer
//#external-address
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
def addressFor(remoteAddr: Address): Address =
system.provider.getExternalAddressFor(remoteAddr) getOrElse
(throw new UnsupportedOperationException("cannot send to " + remoteAddr))
//#serialization-bindings-config
val a = ActorSystem("system", config)
SerializationExtension(a).serializerFor(classOf[String]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializerFor(classOf[Customer]).getClass must equal(classOf[JavaSerializer])
SerializationExtension(a).serializerFor(classOf[java.lang.Boolean]).getClass must equal(classOf[MyOwnSerializer])
a.shutdown()
}
def serializeTo(ref: ActorRef, remote: Address): String =
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressFor(remote))
//#external-address
}
"demonstrate the programmatic API" in {
//#programmatic
val system = ActorSystem("example")
"demonstrate how to do default Akka serialization of ActorRef" in {
val theActorSystem: ActorSystem = system
// Get the Serialization Extension
val serialization = SerializationExtension(system)
//#external-address-default
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
// Have something to serialize
val original = "woohoo"
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
def addressForAkka: Address = system.provider match {
case r: RemoteActorRefProvider r.transport.address
case _
throw new UnsupportedOperationException(
"this method requires the RemoteActorRefProvider to be configured")
// Find the Serializer for it
val serializer = serialization.findSerializerFor(original)
// Turn it into bytes
val bytes = serializer.toBinary(original)
// Turn it back into an object
val back = serializer.fromBinary(bytes, manifest = None)
// Voilá!
back must equal(original)
//#programmatic
system.shutdown()
}
"demonstrate serialization of ActorRefs" in {
val theActorRef: ActorRef = system.deadLetters
val theActorSystem: ActorSystem = system
//#actorref-serializer
// Serialize
// (beneath toBinary)
// If there is no transportAddress,
// it means that either this Serializer isn't called
// within a piece of code that sets it,
// so either you need to supply your own,
// or simply use the local path.
val identifier: String = Serialization.currentTransportAddress.value match {
case null theActorRef.path.toString
case address theActorRef.path.toStringWithAddress(address)
}
// Then just serialize the identifier however you like
// Deserialize
// (beneath fromBinary)
val deserializedActorRef = theActorSystem actorFor identifier
// Then just use the ActorRef
//#actorref-serializer
//#external-address
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
def addressFor(remoteAddr: Address): Address =
system.provider.getExternalAddressFor(remoteAddr) getOrElse
(throw new UnsupportedOperationException("cannot send to " + remoteAddr))
}
def serializeTo(ref: ActorRef, remote: Address): String =
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressFor(remote))
//#external-address
}
def serializeAkkaDefault(ref: ActorRef): String =
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressForAkka)
//#external-address-default
"demonstrate how to do default Akka serialization of ActorRef" in {
val theActorSystem: ActorSystem = system
//#external-address-default
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
def addressForAkka: Address = akka.transportOf(system).address
}
def serializeAkkaDefault(ref: ActorRef): String =
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressForAkka)
//#external-address-default
}
}
}

View file

@ -0,0 +1,34 @@
package docs.testkit
import org.specs2._
import org.specs2.specification.Scope
import akka.actor.{ Props, ActorSystem, Actor }
import akka.testkit.{ TestKit, ImplicitSender }
class Specs2DemoAcceptance extends Specification {
def is =
"This is a specification of basic TestKit interop" ^
p ^
"A TestKit should" ^
"work properly with Specs2 acceptance tests" ! e1 ^
"correctly convert durations" ! e2
val system = ActorSystem()
implicit def d2d(d: org.specs2.time.Duration): akka.util.FiniteDuration =
akka.util.Duration(d.inMilliseconds, "millis")
def e1 = new TestKit(system) with Scope with ImplicitSender {
within(1 second) {
system.actorOf(Props(new Actor {
def receive = { case x sender ! x }
})) ! "hallo"
expectMsgType[String] must be equalTo "hallo"
}
}
def e2 = ((1 second): akka.util.Duration).toMillis must be equalTo 1000
}

View file

@ -0,0 +1,34 @@
package docs.testkit
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import akka.actor.{ Props, ActorSystem, Actor }
import akka.testkit.{ TestKit, ImplicitSender }
class Specs2DemoUnitSpec extends Specification {
val system = ActorSystem()
implicit def d2d(d: org.specs2.time.Duration): akka.util.FiniteDuration =
akka.util.Duration(d.inMilliseconds, "millis")
/*
* this is needed if different test cases would clash when run concurrently,
* e.g. when creating specifically named top-level actors
*/
sequential
"A TestKit" should {
"work properly with Specs2 unit tests" in
new TestKit(system) with Scope with ImplicitSender {
within(1 second) {
system.actorOf(Props(new Actor {
def receive = { case x sender ! x }
})) ! "hallo"
expectMsgType[String] must be equalTo "hallo"
}
}
}
}