Skip to content

Commit

Permalink
Fix TestServer for windows
Browse files Browse the repository at this point in the history
There were two issues with the server tests on windows
1) Sometimes client connections fail on the first attempt but
   will succeed with retries
2) It is possible for named pipes to leak which causes subsequent
   tests to be unable to run
3) ClientTest did not handle lines with carriage returns correctly

Issue #1 is fixed with retries. Issue #2 is fixed by using a
unique temp directory for each test run. Issue #3 was fixed by
simplifying the output stream cache to only cache the bytes returned
and then letting scala do the line splitting for us in linesIterator.

After these changes, all of the server tests work on appveyor.
  • Loading branch information
eatkins committed Jun 29, 2020
1 parent 27e4b9c commit e1103d1
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .appveyor.yml
Expand Up @@ -155,4 +155,4 @@ for:
- '%USERPROFILE%\.sbt'

test_script:
- sbt "scripted actions/* classloader-cache/* nio/* watch/*" "serverTestProj/testOnly serverTestProj/testOnly testpkg.HandshakeTest"
- sbt "scripted actions/* classloader-cache/* nio/* watch/*" "serverTestProj/test"
12 changes: 3 additions & 9 deletions server-test/src/test/scala/testpkg/ClientTest.scala
Expand Up @@ -27,15 +27,9 @@ object ClientTest extends AbstractServerTest {
def lines = cos.lines
}
class CachingOutputStream extends OutputStream {
private val lineBuffer = new mutable.ArrayBuffer[String]
private var byteBuffer = new mutable.ArrayBuffer[Byte]
override def write(i: Int) = {
if (i == 10) {
lineBuffer += new String(byteBuffer.toArray)
byteBuffer = new mutable.ArrayBuffer[Byte]
} else Util.ignoreResult(byteBuffer += i.toByte)
}
def lines = lineBuffer.toVector
private val byteBuffer = new mutable.ArrayBuffer[Byte]
override def write(i: Int) = Util.ignoreResult(byteBuffer += i.toByte)
def lines = new String(byteBuffer.toArray, "UTF-8").linesIterator.toSeq
}
class FixedInputStream(keys: Char*) extends InputStream {
var i = 0
Expand Down
25 changes: 19 additions & 6 deletions server-test/src/test/scala/testpkg/TestServer.scala
Expand Up @@ -8,7 +8,8 @@
package testpkg

import java.io.{ File, IOException }
import java.nio.file.Path
import java.net.Socket
import java.nio.file.{ Files, Path }
import java.util.concurrent.{ LinkedBlockingQueue, TimeUnit }
import java.util.concurrent.atomic.AtomicBoolean

Expand Down Expand Up @@ -37,10 +38,11 @@ trait AbstractServerTest extends TestSuite[Unit] {
}

override def setupSuite(): Unit = {
temp = targetDir / "test-server" / testDirectory
if (temp.exists) {
IO.delete(temp)
}
val base = Files.createTempDirectory(
Files.createDirectories(targetDir.toPath.resolve("test-server")),
"server-test"
)
temp = base.toFile
val classpath = sys.props.get("sbt.server.classpath") match {
case Some(s: String) => s.split(java.io.File.pathSeparator).map(file)
case _ => throw new IllegalStateException("No server classpath was specified.")
Expand Down Expand Up @@ -191,8 +193,19 @@ case class TestServer(
hostLog(s"wait $waitDuration until the server is ready to respond")
waitForPortfile(waitDuration)

@tailrec
private def connect(attempt: Int): Socket = {
val res = try Some(ClientSocket.socket(portfile)._1)
catch { case _: IOException if attempt < 10 => None }
res match {
case Some(s) => s
case _ =>
Thread.sleep(100)
connect(attempt + 1)
}
}
// make connection to the socket described in the portfile
val (sk, _) = ClientSocket.socket(portfile)
val sk = connect(0)
val out = sk.getOutputStream
val in = sk.getInputStream
private val lines = new LinkedBlockingQueue[String]
Expand Down

0 comments on commit e1103d1

Please sign in to comment.