Skip to content

Commit

Permalink
test: fix possible deadlocks in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
etorreborre committed Jan 21, 2024
1 parent 3ae9fc4 commit a06f444
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: sbt '++ ${{ matrix.scala }}' githubWorkflowCheck

- name: Build and test 🔧
run: sbt '++ ${{ matrix.scala }}' 'core/testOnly -- xonly exclude ci,website timefactor 3'
run: sbt '++ ${{ matrix.scala }}' 'testOnly -- xonly exclude ci,website timefactor 3'

publish:
name: Publish Artifacts
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ lazy val releaseSettings: Seq[Setting[_]] = Seq(
),
ThisBuild / githubWorkflowBuild := Seq(
WorkflowStep
.Sbt(name = Some("Build and test 🔧"), commands = List("core/testOnly -- xonly exclude ci,website timefactor 3"))
.Sbt(name = Some("Build and test 🔧"), commands = List("testOnly -- xonly exclude ci,website timefactor 3"))
),
ThisBuild / githubWorkflowTargetTags ++= Seq(SPECS2 + "*"),
ThisBuild / githubWorkflowPublishTargetBranches := Seq(RefPredicate.StartsWith(Ref.Tag(SPECS2))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class BeforeAfterAroundSpec(val env: Env) extends Specification with OwnEnv {
)

def executeContains(s: SpecificationStructure & StringOutput, messages: String*) =
DefaultExecutor.executeFragments(s.structure.fragments)(env).traverse(_.executionResult).run(ownEnv.executionEnv)
DefaultExecutor.executeFragments(s.structure.fragments)(ownEnv).traverse(_.executionResult).run(ownEnv.executionEnv)
s.messages must contain(allOf(messages*)).inOrder

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ class SpecStructureSpec(val env: Env) extends Specification with OwnEnv:
SpecStructure.dependsOn(ee)(spec1, spec2) and SpecStructure.dependsOn(ee)(spec2, spec1).not

def a2 =
SpecStructure.linkedSpecifications(spec1, env, getClass.getClassLoader).runOption.flatMap(_.lastOption) must beSome(
SpecStructure
.linkedSpecifications(spec1, ownEnv, getClass.getClassLoader)
.runOption
.flatMap(_.lastOption) must beSome(
(_: SpecStructure).arguments
must ===(spec2.arguments)
)

def b1 =
SpecStructure
.linkedSpecifications(spec1, env.setArguments(Arguments.split("exclude spec2")), getClass.getClassLoader)
.linkedSpecifications(spec1, ownEnv.setArguments(Arguments.split("exclude spec2")), getClass.getClassLoader)
.runOption
.toList
.flatten must not(contain((s: SpecStructure) => s.name === "S2"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,14 @@ case class Env(
copy(arguments = arguments.setTimeout(duration))

/** @return a list of finalization failures by resource key if any */
private def startShutdown: Future[List[Result]] =
def startShutdown: Future[List[Result]] =
given ExecutionContext = specs2ExecutionContext
val results: Action[List[(String, Result)]] = resources.toList.traverse { case (key, resource) =>
resource.finalizer.startExecution(this).executionResult.map(r => (key, r))
resource.finalizer
.startExecution(this)
.executionResult
.map(r => (key, r))
.addLast(Finalizer.create(resources.remove(key)))
}

results
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ object DefaultExecutor:

/** only to be used in tests */
def executeFragments(fs: Fragments)(env: Env): List[Fragment] =
fs.fragments.map(fs => executeAll(fs*)(env)).runMonoid(env.specs2ExecutionEnv)
fs.fragments.map(fs => executeAll(fs*)(env)).runMonoid(env.executionEnv)

def executeFragmentsAction(fs: Fragments)(env: Env): Action[List[Fragment]] =
fs.fragments.flatMap(fs => executeAllAction(fs*)(env))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ method. It can then be accessed concurrently by several specifications
val specifications = (1 to 5).map(n => GlobalResourceExample(n, messages).structure)
for {
r <- Future.sequence(specifications.map(s => reporter.report(s).runFuture(env.executionEnv)))
_ = env.shutdown()
rs <- env.startShutdown
} yield (messages.headOption === Some("acquired")) and
(messages.lastOption === Some("released with value 5")) and
(messages.toList must contain(
Expand Down
8 changes: 4 additions & 4 deletions html/src/test/scala/org/specs2/reporter/HtmlPrinterSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ class HtmlPrinterSpec(val env: Env) extends Specification with ActionMatchers wi

def index =
val spec = new Specification { def is = s2""" one example $ok """ }
val env1 = env.setArguments(searchArguments)
val env1 = ownEnv.setArguments(searchArguments)

printer(env1).getHtmlOptions(env1.arguments).map(_.search).runOption must beSome(true)

finalize(env1, spec).runOption(env.executionEnv) must beSome
finalize(env1, spec).runOption(ownEnv.executionEnv) must beSome
FilePathReader.exists(outDir / "javascript" / "tipuesearch" | "tipuesearch_contents.js").runOption must beSome(true)

def searchPage =
val spec = new Specification { def is = s2""" one example $ok """ }
val env1 = env.setArguments(searchArguments)
val env1 = ownEnv.setArguments(searchArguments)

finalize(env1, spec).runOption(env.executionEnv) must beSome
finalize(env1, spec).runOption(ownEnv.executionEnv) must beSome
FilePathReader.exists(outDir | "search.html").runOption must beSome(true)

def finalize(env: Env, spec: SpecificationStructure): Action[Unit] =
Expand Down
15 changes: 6 additions & 9 deletions tests/jvm/src/test/scala/org/specs2/ModulesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,33 @@ import io.*

/** This is an example of running specifications module by module
*/
class ModulesSpec extends Specification {
class ModulesSpec(env: Env) extends Specification {
def is =
br ^
Fragments.foreach(specs)(s => link(showOnly("x!") ^ s) ^ br)

def specs =
List(Core, JUnit, Examples)
List(Core(env), JUnit(env), Examples(env))
}

object Core extends Specification { def is = Module.specifications(getClass) }
object JUnit extends Specification { def is = Module.specifications(getClass) }
object Examples extends Specification { def is = Module.specifications(getClass) }
class Core(env: Env) extends Specification { def is = Module.specifications(env, getClass) }
class JUnit(env: Env) extends Specification { def is = Module.specifications(env, getClass) }
class Examples(env: Env) extends Specification { def is = Module.specifications(env, getClass) }

object Module extends SpecificationCreation:
def specifications(klass: Class[?], filter: String => Boolean = (s: String) => true) =
def specifications(env: Env, klass: Class[?], filter: String => Boolean = (s: String) => true) =
val name = klass.getSimpleName.replace("$", "")
val base = DirectoryPath.unsafe(new java.io.File(".").getAbsolutePath) / FileName.unsafe(
name.toLowerCase
) / "src" / "test" / "scala"

val env = EnvDefault.default
val finder = SpecificationsFinder.create(env)
val specs =
finder
.findSpecifications(basePath = base, verbose = false, filter = filter)
.unsafeRun
.take(3)

env.shutdown()

name.title.copy(specClass = klass) ^
br ^
Fragments.foreach(specs)(s => link(showOnly("!x") ^ s.is) ^ br)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SbtPrinterSpec(val env: Env) extends Specification with OwnEnv {
def e1 =
printer
.print((new HelloWorldSpec { override def is = "title".title ^ "\ntext" }).structure)
.runAction(ownEnv.specs2ExecutionEnv)
.runAction(ownEnv.executionEnv)
eventually(logger.messages must contain(beMatching("\\[INFO\\].*title.*")))

def e2 =
Expand All @@ -54,7 +54,7 @@ class SbtPrinterSpec(val env: Env) extends Specification with OwnEnv {
| """.stripMargin.showSpaces

def print(spec: SpecStructure) =
printer.print(spec).runAction(ownEnv.specs2ExecutionEnv)
printer.print(spec).runAction(ownEnv.executionEnv)
stringOutputLogger.flush()
stringOutputLogger.messages.mkString("\n")

Expand All @@ -74,8 +74,8 @@ class SbtPrinterSpec(val env: Env) extends Specification with OwnEnv {
lazy val handler = outer.handler
lazy val taskDef = new TaskDef("", Fingerprints.fp1, true, Array())
}
val env = Env(arguments = Arguments("nocolor"))
val printer = SbtPrinter(env, Array(logger, stringOutputLogger), events)
val env1 = ownEnv.copy(arguments = Arguments("nocolor"))
val printer = SbtPrinter(env1, Array(logger, stringOutputLogger), events)

}

Expand Down Expand Up @@ -103,8 +103,8 @@ class SbtPrinterSpec(val env: Env) extends Specification with OwnEnv {
handler.events must contain(eventWithNameMatching("HW::The 'Hello world' string should::contain 11 characters"))

def executeAndPrintHelloWorldUnitSpec =
val executed = DefaultExecutor.executeSpec((new HelloWorldUnitSpec).is.fragments, env)
printer.print(executed).runAction(env.specs2ExecutionEnv)
val executed = DefaultExecutor.executeSpec((new HelloWorldUnitSpec).is.fragments, ownEnv)
printer.print(executed).runAction(ownEnv.executionEnv)

}

Expand Down

0 comments on commit a06f444

Please sign in to comment.