SBT cleanup hook in test - scala

SBT has a nice hook which allows you to execute arbitrary code after all tests are run:
testOptions in Test += Tests.Cleanup( () => println("Cleanup"))
That works.
My question is: I want to do some actual cleanup (stopping some services for example) but I can't import any dependencies which I've declared in the same build file. Is there any way to do this? I guess I need to put these on the sbt classpath or something, but I can't seem to find this in the docs.
P.S. I might be doing this in the wrong location, is there a better place to shutdown things after all tests are run?)

Complementing venechka's answer: I'm running integration tests using Specs2, and in specs there is no way of knowing when all tests have run. So I solved it pretty much the way venechka and you yourself already indicated, by loading a class from the project that does the cleanup when it's initialized:
testOptions in IntegrationTest += Tests.Cleanup( (loader: java.lang.ClassLoader) => {
loader.loadClass("com.mypackage.IntegrationTestCleanup").newInstance
} )

You can't use the classes that are added with libraryDependencies in project (you can add libraryDependencies in project/project, but I wouldn't recommend adding in 2 places). Instead you can invoke a cleanup method that is in your project's sources, and that has access to the declared library dependencies.

Related

SBT: add command-line parsing to modify settings for existing tasks

When running tasks (e.g., test, jmh:run), I often want to specify javaOptions which are tedious to type by hand (e.g., to dump program data).
This is my current approach:
// build.sbt
lazy val myProject = project
...
.settings(
...
Test / javaOptions ++= if (sys.props.get("dump").nonEmpty) Seq("-X...", ...) else Nil
)
I can set system properties on sbt launch (e.g., sbt -Ddump) and then check them with sys.props, but changing these properties requires me to reload sbt. I would like to parse some arguments when the task is invoked, such that I can write test -dump and modify the Test / javaOptions setting accordingly.
Is this possible? Someone recommended I override the default task but I'm having trouble figuring out what that would look like. I have a suspicion I need an InputTask for this, but also don't know what that'd look like.
You don’t need to reload sbt, if you are running sbt in a shell, you will need to programtically call‚ sys.props.set

In SBT, how do you override compile to run arbitrary code afterwards?

I'm trying to use SBT to build a project that depends on bytecode enhancement. Basically, I need to run some code after compile using the classpath in the current scope (so the command can find the classes to modify), and then make sure that compile doesn't run again afterwards to undo the enhancement.
I'm using SBT 0.13.12, if that matters.
I believe you would want to make a new sbt task and have it depend on compile. Then use that rather than compile.
lazy val bytecodeEnhancedCompile = taskKey[Unit]("bytecode Enhance")
bytecodeEnhancedCompile <<= bytecodeEnhancedCompile dependsOn (compile in Compile)
bytecodeEnhancedCompile := {
....
}

SBT: modify the order of dependencies in the classpath

I'm currently experiencing a problem with Specs2 + SBT where my tests always fail via command-line because of dependency order in the classpath. Specs2 requires that the Mockito jars come after the Specs2 jars so that Mockito classes can be overridden to fix issues with by-name scala method parameters (see this issue for more information: https://github.com/etorreborre/specs2/issues/428).
In IntelliJ, I can order my dependencies via the Project Structure/Modules/Dependencies window, which fixes my tests when run inside IntelliJ, however, I have not found a solution to fix this issue when running my tests on the command-line via sbt test.
Does anyone know if it is possible to change the classpath order of dependencies for SBT using settings in build.sbt (or similar)?
To my knowledge you need to make sure that specs2-mock comes before mockito in your libraryDependencies setting.

Real SBT Classpath at Runtime

I have some test cases that need to look at the classpath to extract the paths of some files/directories in there. This works fine in the IDE.
The problem is that, when running SBT test, Properties.javaClassPath gives me /usr/share/sbt-launcher-packaging/bin/sbt-launch.jar.
The classpath is fine when I run show test:dependency-classpath. Is there a way to obtain that information from inside the running Scala/Java program? Or is there a way to toss it into a system property or environment variable?
By default the tests are run inside of the SBT process, so the classpath will look like it did when you started sbt (I guess sbt does some trixery to dynamicly load the classes for the tests, not sure). One way to do what you want is to run your tests in a forked jvm, that way sbt will start a new jvm to run the test suite and that should have the expected class path:
fork in Test := true
I have been working on understanding how the EmbeddedCassandra works in the spark-cassandra-connector project which uses the classpath to start up and control a Cassandra instance. Here is a line from their configuration that gets the correct classpath.
(compile in IntegrationTest) <<= (compile in Test, compile in IntegrationTest) map { (_, c) => c }
The entire source can be found here: https://github.com/datastax/spark-cassandra-connector/blob/master/project/Settings.scala
Information on the <<= operator can be found here: http://www.scala-sbt.org/0.12.2/docs/Getting-Started/More-About-Settings.html#computing-a-value-based-on-other-keys-values. I'm aware that this is not the current version of sbt, but the definition still holds.

SBT doesn't reconize junit testcase written in java file

I made a Scala/Java mixed project with SBT 0.11.2. My config for JUnit testing is
resolvers += "twitter.com" at "http://maven.twttr.com/"
seq(com.github.retronym.SbtOneJar.oneJarSettings: _*)
libraryDependencies += "com.novocode" % "junit-interface" % "0.10-M2" % "test"
When I write JUnit test cases in Scala with #Test, every goes well. But when I write a Java JUnit test case, then run test in sbt, the Java JUnit test cannot be reconized. Only test cases written in Scala are executed.
How can I make sbt recognize my Java and Scala test cases at the same time?
Probably late for the origional question, but..
I've just been looking at this. The JUnit tests in my project were not running for me until I ran sbt clean test. Now all working like a charm.
There was a bug in 0.11.x in detecting Java tests that was fixed in 0.12.0, although I didn't think it affected detecting annotated tests. You might try coming up with a minimal test case and checking with the latest sbt version (0.12.1). If the problem still exists, file a bug.
you should put your test classes into src/test/java and your class name should end with "Test" (for example myTest.java)