aboutsummaryrefslogtreecommitdiff
path: root/sync/src/test/scala/akka/serial
diff options
context:
space:
mode:
Diffstat (limited to 'sync/src/test/scala/akka/serial')
-rw-r--r--sync/src/test/scala/akka/serial/PseudoTerminal.scala43
-rw-r--r--sync/src/test/scala/akka/serial/sync/SerialConnectionSpec.scala101
2 files changed, 144 insertions, 0 deletions
diff --git a/sync/src/test/scala/akka/serial/PseudoTerminal.scala b/sync/src/test/scala/akka/serial/PseudoTerminal.scala
new file mode 100644
index 0000000..3e9e9fe
--- /dev/null
+++ b/sync/src/test/scala/akka/serial/PseudoTerminal.scala
@@ -0,0 +1,43 @@
+package akka.serial
+
+import java.io.{File, IOException}
+import java.nio.file.Files
+
+import scala.concurrent.duration._
+import scala.sys.process._
+import scala.util.control.NonFatal
+
+trait PseudoTerminal {
+
+ final val SetupTimeout = 100.milliseconds
+
+ def withEcho[A](action: (String, SerialSettings) => A): A = {
+ val dir = Files.createTempDirectory("akka-serial-pty").toFile
+ val pty = new File(dir, "pty")
+
+ val socat = try {
+ val s = Seq(
+ "socat",
+ "-d -d",
+ s"exec:cat,pty,raw,b115200,echo=0",
+ s"pty,raw,b115200,echo=0,link=${pty.getAbsolutePath}"
+ ).run(ProcessLogger(println(_)), false)
+ Thread.sleep(SetupTimeout.toMillis) // allow ptys to set up
+ s
+ } catch {
+ case NonFatal(ex) =>
+ throw new IOException(
+ "Error running echo service, make sure the program 'socat' is installed", ex)
+ }
+
+ try {
+ val result = action(pty.getAbsolutePath, SerialSettings(baud = 115200))
+ Thread.sleep(SetupTimeout.toMillis) // allow for async cleanup before destroying ptys
+ result
+ } finally {
+ socat.destroy()
+ dir.delete()
+ }
+ }
+
+}
diff --git a/sync/src/test/scala/akka/serial/sync/SerialConnectionSpec.scala b/sync/src/test/scala/akka/serial/sync/SerialConnectionSpec.scala
new file mode 100644
index 0000000..24069d7
--- /dev/null
+++ b/sync/src/test/scala/akka/serial/sync/SerialConnectionSpec.scala
@@ -0,0 +1,101 @@
+package akka.serial
+package sync
+
+import java.nio.ByteBuffer
+import org.scalatest._
+
+class SerialConnectionSpec extends WordSpec with PseudoTerminal {
+
+ def withEchoConnection[A](action: SerialConnection => A): A = {
+ withEcho { (port, settings) =>
+ val connection = SerialConnection.open(port, settings)
+ try {
+ action(connection)
+ } finally {
+ connection.close()
+ }
+ }
+ }
+
+ "A SerialConnection" should {
+
+ "open a valid port" in {
+ withEcho { (port, settings) =>
+ SerialConnection.open(port, settings)
+ }
+ }
+
+ "throw an exception on an invalid port" in {
+ val settings = SerialSettings(baud = 115200)
+ intercept[NoSuchPortException] {
+ SerialConnection.open("/dev/nonexistant", settings)
+ }
+ }
+
+ "read the same data it writes to an echo pty" in {
+ withEchoConnection { conn =>
+ /* Note: this test assumes that all data will be written and read
+ * within single write and read calls. This in turn assumes that
+ * internal operating system buffers have enough capacity to
+ * store all data. */
+ val bufferSize = 64
+
+ val outString = "hello world"
+ val outBuffer = ByteBuffer.allocateDirect(bufferSize)
+ val outData = outString.getBytes
+ outBuffer.put(outData)
+ conn.write(outBuffer)
+
+ val inBuffer = ByteBuffer.allocateDirect(bufferSize)
+ conn.read(inBuffer)
+ val inData = new Array[Byte](inBuffer.remaining())
+ inBuffer.get(inData)
+ val inString = new String(inData)
+
+ assert(inString == outString)
+ }
+ }
+
+ "interrupt a read when closing a port" in {
+ withEchoConnection { conn =>
+ val buffer = ByteBuffer.allocateDirect(64)
+
+ val closer = new Thread {
+ override def run(): Unit = {
+ Thread.sleep(100)
+ conn.close()
+ }
+ }
+ closer.start()
+ intercept[PortInterruptedException]{
+ conn.read(buffer)
+ }
+ closer.join()
+ }
+ }
+
+ "throw an exception when reading from a closed port" in {
+ withEchoConnection { conn =>
+ val buffer = ByteBuffer.allocateDirect(64)
+ conn.close()
+
+ intercept[PortClosedException]{
+ conn.read(buffer)
+ }
+ }
+ }
+
+ "throw an exception when writing to a closed port" in {
+ withEchoConnection { conn =>
+ val buffer = ByteBuffer.allocateDirect(64)
+ conn.close()
+
+ intercept[PortClosedException]{
+ conn.write(buffer)
+ }
+ }
+ }
+
+ }
+
+}