diff options
Diffstat (limited to 'sync/src/test/scala/akka')
-rw-r--r-- | sync/src/test/scala/akka/serial/PseudoTerminal.scala | 43 | ||||
-rw-r--r-- | sync/src/test/scala/akka/serial/sync/SerialConnectionSpec.scala | 101 |
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) + } + } + } + + } + +} |