Play应用中的specs/scalatest交互问题

bet*_*ess 10 scala sbt scalatest playframework specs2

我遇到了一个我无法解释的问题......在https://github.com/betehess/play-scalatest的项目中它是孤立的.

当我运行时test,sbt卡住一段时间然后抛出此异常:

> test
[error] Uncaught exception when running tests: java.net.ConnectException: Connection timed out
Exception in thread "Thread-1" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:196)
    at java.net.SocketInputStream.read(SocketInputStream.java:122)
    at java.net.SocketInputStream.read(SocketInputStream.java:210)
    at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2293)
    at java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:2473)
    at java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:2543)
    at java.io.ObjectInputStream$BlockDataInputStream.skipBlockData(ObjectInputStream.java:2445)
    at java.io.ObjectInputStream.skipCustomData(ObjectInputStream.java:1941)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1620)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:500)
    at java.lang.Throwable.readObject(Throwable.java:914)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1893)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at sbt.React.react(ForkTests.scala:117)
    at sbt.ForkTests$$anonfun$mainTestTask$1$Acceptor$2$.run(ForkTests.scala:76)
    at java.lang.Thread.run(Thread.java:745)
Run Code Online (Sandbox Code Playgroud)

看起来sbt卡在分叉环境的阻塞调用中,网址是https://github.com/sbt/sbt/blob/0.13.5/main/actions/src/main/scala/sbt/ForkTests.scala#L117.

一些评论:

  • 我运行Ubuntu 13.10和Java HotSpot(TM)64位"1.7.0_65"
  • 没有一个同事可以在他们的机器上重现这个问题......
  • 只有当scalatest在类路径上时才会出现问题,即使这里没有使用它
  • 如果我不使用PlayScala插件并将specs2显式添加为依赖项,问题就会消失
  • 如果我将最新的依赖项移动到main中,问题就会消失 build.sbt

bet*_*ess 3

我终于知道发生了什么事。

事实证明,在正确的设置下,sbt 将分叉 JVM 来执行测试,并希望与其通信。如何完成此操作取决于测试框架。在 scalatest 的情况下,两个进程之间的通信将通过服务器完成。scalatest 只是传达 sbt 必须使用的服务器地址和端口。而这一切正在那里发生。

val array = Array(InetAddress.getLocalHost.getHostAddress, skeleton.port.toString)
Run Code Online (Sandbox Code Playgroud)

现在,去阅读 javadoc 中关于InetAddress#getLocalHost的内容:

返回本地主机的地址。这是通过从系统检索主机的名称,然后将该名称解析为 InetAddress 来实现的。

我在Linux上。我的本地主机(从来没有 localhost)最终成为dopey. 现在,由于某种原因(我在家里搞乱了我的网络),我/etc/hosts正在为dopey. 127.0.0.1因此,scalatest 会尝试在这个虚构的服务器上打开一个套接字,而不是类似的东西。由于发生这种情况的位置,您在堆栈跟踪中看不到任何有用的信息。

我的猜测是,目的始终是使用127.0.0.1......