Suma
Suma

Reputation: 34403

Can ScalaTest detect timeout without synchronization calls (like in an infinite loop?)

In a following code the test called sleep fails gracefully, while the test freeze causes the testing to never end.

import org.scalatest.FunSuite
import org.scalatest.concurrent.TimeLimitedTests
import org.scalatest.time.SpanSugar._
import scala.language.postfixOps

class MainTest extends FunSuite with TimeLimitedTests {
  def timeLimit = 1 second

  test("sleep") {
    Thread.sleep(10000)
  }

  test("unintentional freeze") {
    var i = 100
    var j = 0
    while (i>0) {
      i += 1 // a bug: should be j += 1
      i -= 1
    }
  }

}

I understand this because of the way how TimeLimitedTests uses ThreadInterruptor to abort timeouted tests. Is there some other way how can ScalaTest detect and fail such code? If not, is there some common practice how avoid or detect this type of bugs in the tested code?

When I run tests manually in the IDE, I can abort them manually and those with infinite loops will be marked as not started, but I am concerned that when this happens in a code committed, the Jenkins build process is frozen as a result, requiring a manual abort on the build server.

Upvotes: 3

Views: 1195

Answers (1)

vvg
vvg

Reputation: 6385

First of all your example is artificial. In real life even infinite loops has invokes thread sleeping at least for millisecond: Thread.sleep(1). And in such case interrupt will properly work.

But assume there are no sleeping. So you need to override defaultInterrruptor to kill thread in more "reliable" way.

import org.scalatest.FunSuite
import org.scalatest.concurrent.{Interruptor, TimeLimitedTests, ThreadInterruptor, Timeouts}
import org.scalatest.time.SpanSugar._

import scala.language.postfixOps

class MainTest extends FunSuite with TimeLimitedTests {

  override val defaultTestInterruptor: Interruptor = new Interruptor {
    override def apply(testThread: Thread): Unit = {
      println("Kindly die")
      testThread.stop() // deprecated. unsafe. do not use
    }
  }

  def timeLimit = 1 second


  test("sleep") {
    Thread.sleep(10000)
  }

  test("freeze") {
    while (true) {}
  }


}

Upvotes: 5

Related Questions