My Test.scala has 2 tests that I'd like to run in parallel.
C:/users/Kevin/workspace/playApp> sbt test
class ConcurrentRequests extends FunSuite with BeforeAndAfterAll with ParallelTestExecution {
val start = System.nanoTime()
test("foo") {
println("foo")
foo
println("foo in " + (System.nanoTime - start) / 1000000000 + " seconds.")
}
test("bar") {
println("bar")
bar
println("bar in " + (System.nanoTime - start) / 1000000000 + " seconds.")
}
}
I tried this post's answers, namely adding testOptions to my $PLAY_APP/build.sbt, as well as using the -P option, but neither worked. I say it didn't work since "foo" printed out, executed its calls, and then bar printed out and executed after.
How can I run this Play test in parallel via sbt?
EDIT
As a work-around, I put the first test in ConcurrentTest.scala and the second in a separate ConcurrentTest2.scala file. And then ScalaTest ran the tests in parallel. From a maintenance point-of-view, I'd rather have a single test file and then run each of them in parallel.
Related
I have this code evaluated with Ammonite:
$ amm
Welcome to the Ammonite Repl 2.5.1 (Scala 2.13.8 Java 17.0.1)
# import $ivy.`org.scala-lang.modules::scala-parallel-collections:1.0.4`
# import scala.collection.parallel.CollectionConverters._
# Seq(1,2).foreach { x => Thread sleep x*1000; println(s"Fin $x") };println("Fin")
Fin 1
Fin 2
Fin
It completes ok.
If I add the par to parallelize, then it never finishes:
# Seq(1,2).par.foreach { x => Thread sleep x*1000; println(s"Fin $x") };println("Fin")
Is this a bug?
With Scala 2.12 I get the same behaviour.
You're having this problem due this bug with Scala's lambda encoding that will also happen in the Scala REPL.
The bug on the Scala side: https://github.com/scala/scala-parallel-collections/issues/34
The corresponding ammonite bug report is here: https://github.com/com-lihaoyi/Ammonite/issues/556
You can work around this in two ways that I'm aware of.
The first is to put your parallel work inside of an object e.g.
object work {
def execute() = Seq(1, 2).foreach { x =>
Thread.sleep(x * 1000); println(s"Fin $x")
}; println("Fin")
}
work.execute
I believe running Ammonite with amm --class-based should also do the trick, but I'm not able to test this right now.
I'm trying to write an integration test for a small command line app I'm writing with Scala and SBT. My app would usually be run from the SBT prompt like so:
> run "my arg"
The argument "my arg" is accessed in the app with args(0). For an integration test how can I simulate calling run with an argument and asserting console output?
Your app needs to have an object with main method that takes Array[String] as parameter.
It looks like this
object Main extends App {
print("hi, " + args(0))
}
or like this
object Main {
def main(args: Array[String]) = print("hi, " + args(0))
}
Anyway you definitely have this kind of entry point if you can do > run "my arg" in sbt.
It is just an object with a method called main that you can call wherever you want. Just import it and use:
Main.main(Array("my arg"))
that would print the text to the console when executed. We need to redirect the console output to some other stream to be able to verify it.
Using answer from Redirect stdout in another thread you can come up with something like this:
val baos = new ByteArrayOutputStream
val ps = new PrintStream(baos)
Console.withOut(ps)(Main.main(Array("my arg")))
val output = baos.toString
And you can do all sort of tests on output value
You can then create a helper method to handle this for you
def outputFor(args: String*): String = {
val baos = new ByteArrayOutputStream
val ps = new PrintStream(baos)
Console.withOut(ps)(Main.main(args.toArray))
baos.toString
}
And then easly test your app
"My app" should "greet me" {
outputFor("harryg") shouldBe "hi, harryg"
}
Just to clarify, the whole solution has nothing to do with sbt itself, we directly call the program in a similar way that sbt would do it.
I want to create a new custom InputTask (testOnlyCustom)
that calls testOnly with the same arguments as given to testOnlyCustom and
that maybe, based on a SBT setting (condition), calls another task (let's call it pre) before calling testOnly. Here, I have to force "sequential" execution.
Thus:
If condition is true
testOnlyCustom com.dummy.TestSuite calls
pre and then
testOnly com.dummy.TestSuite
If condition is false
testOnlyCustom com.dummy.TestSuite calls
testOnly com.dummy.TestSuite
While I was able to achieve a solution with testCustom referring to pre and test (and thus having no arguments), I'm not able to solve the problem for testOnlyCustom, as InputTask used
Here is my code:
import sbt._
import sbt.Keys._
import sbt.Def._
import sbtsequential.Plugin._
object Simple extends sbt.Plugin {
import SimpleKeys._
object SimpleKeys {
lazy val condition = SettingKey[Boolean]("mode", "The mode.")
lazy val pre = TaskKey[Unit]("test-with-pre", "Do some pre step.")
lazy val testWithPre = TaskKey[Unit]("test-with-pre", "Run pre task beforehand")
lazy val testCustom = TaskKey[Unit]("test-custom", "Run pre (depending on condition) and then test.")
lazy val testOnlyWithPre = InputKey[Unit]("test-only-with-pre", "Run selected tests (like test-only in SBT) with pre executed before.")
lazy val testOnlyCustom = InputKey[Unit]("test-only-configured", "Run pre (depending on condition) and then call test-only.")
}
lazy val baseSettings: Seq[sbt.Def.Setting[_]] = Seq(
// this is working
testWithPre := test.value,
testWithPre <<= testWithPre.dependsOn( pre ),
testCustom := Def.taskDyn {
val c = condition.value
if (c) {
testWithPre
} else {
test
}
}.value,
//
// this is the part, where my question focuses on
//
testOnlyWithPre := testOnly.evaluated,
testOnlyWithPre <<= testOnlyWithPre.dependsOn( pre ),
// is this the correct approach?
testOnlyCustom := Def.inputTaskDyn {
// ???????????????????????????????
Def.task()
}.evaluated
)
lazy val testSimpleSettings: Seq[sbt.Def.Setting[_]] = baseSettings
}
Is inputTaskDyn the way to go? What exactly does it? I have just chosen it, because it seems to be dynamic version for InputTasks. Unfortunately, documentation is very rare on inputTaskDyn.
Is it okay to force "sequential" execution via dependsOn, like I did? I already have seen tha SBT 0.13.8 contains Def.sequantial. But this does not seem to be applicable to InputTasks?
How to convert an InputTask into a Task (to be used with taskDyn / inputTaskDyn) but still sticking to evaluated instesd of using an explicit parser? Or is there a way to reuse the testOnly parser?
Could someone illustrate a little more on .evaluated and .parsed of InputTask. What exactly does InputTask.parse do under the hood?
It would be great if someone could provide a working solution!
Many thanks in advance
Martin
Just for the record, the SBT 1 equivalent is
testOnlyWithPre := test.dependsOn(pre).value
and
testOnlyWithPre := testOnly.dependsOn(pre).evaluated
the best solution I could come up with is
testOnlyCustom := Def.inputTaskDyn {
val args: Seq[String] = spaceDelimited("").parsed
val c = condition.value
if (c) {
testOnlyWithPre.toTask(" " + args.head)
} else {
testOnly.toTask(" " + args.head)
}
}.evaluated
But still, this forces me to use a new parser (spaceDelimited) and I am not able to (re-)use the testOnly parser.
Any ideas how to reuse the parser?
Additional comments
First, OlegYch_ indicated on Freenode # sbt that coming up with SBT 0.13.9 the execution of Inputtasks will be possible via
def runInputTask[T](key: InputKey[T], input: String, state: State): (State, T)
in sbt.Extracted.scala.
Second, the testOnly parsers can be reused via sbt.Defaults#inputTests.
When I run tests in Junit, their ordering isn't guaranteed. By default, specs2 runs the examples in parallel so ordering isn't guaranteed here as well. However, if I add the sequential keyword, the tests are executed (at least from what it seems) in order. Is there a way to get the sequential behavior but have the examples run in random order?
You can use the latest specs2 2.3-SNAPSHOT version with the random command-line argument (or args.execute(random=true) inside the specification):
class TestSpec extends Specification { def is = s2"""
test1 $e1
test2 $e2
test3 $e3
"""
def e1 = { "starting e1".pp; Thread.sleep(30); "e1".pp; ok }
def e2 = { "starting e2".pp; Thread.sleep(20); "e2".pp; ok }
def e3 = { "starting e3".pp; Thread.sleep(40); "e3".pp; ok }
}
sbt> testOnly *TestSpec* -- random
starting e3
e3
starting e2
e2
starting e1
e1
[info] TestSpec
[info]
[info] + test1
[info] + test2
[info] + test3
[info]
How about decorating/wrapping the test cases with code that acquires a lock at the beginning of each test case? Hacky perhaps, but should work reliably and be easy to implement, until/unless you can find a more meant-to-be-used alternative.
I am reading Martin Odersky's Programming in Scala, and I have been using vi and the command line to compile so far. I want to learn to use Eclipse and the Scala-IDE plug-in, but I lack a basic understanding of compiling and executing multiple source code files in Eclipse.
My IDE is as follows:
Ubuntu 12.04
Eclipse 3.7.2
Scala Plugin 2.0.1
Scala Library 2.9.2
I am using the Checksum example in Chapter 4 for practice. The source code is as follows:
Listings 4.1 & 4.2 / ChecksumAccumulator.scala:
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte) { sum += b }
def checksum(): Int = ~(sum & 0xFF) + 1
}
import scala.collection.mutable.Map
object ChecksumAccumulator {
private val cache = Map[String, Int]()
def calculate(s: String): Int =
if (cache.contains(s))
cache(s)
else {
val acc = new ChecksumAccumulator
for (c <- s)
acc.add(c.toByte)
val cs = acc.checksum()
cache += (s -> cs)
cs
}
}
Listing 4.3 / Summer.scala:
import ChecksumAccumulator.calculate
object Summer {
def main(args: Array[String]) {
for (arg <- args)
println(arg + ": " + calculate(arg))
}
}
I can compile these classes using scalac Summer.scala ChecksumAccumulator.scala at the command line. I can then execute the object code with the command line scala Summer of love, which returns the checksum results for "of" and "love" (-213 and -182, respectively).
How would I build the object code using Eclipse and not the command line, and how would I call the Summer object code through Eclipse?
In Eclipse, you can just create a new Scala project, and put the source files there.
Once the files are part of the same project, there's no need to do anything special:
Just click on Run >> Run As >> Scala Application (or press Alt + Shift + X, S)
Have fun learning Scala :)