define custom configuration in sbt - scala

I want to set another set of options for running tests in integration server and in dev environment.
Let's have this option:
testOptions := Seq(Tests.Filter(s => Seq("Spec", "Unit").exists(s.endsWith(_))))
How can change the testOptions, so it is only applied, when the test command is prefixed with some scope like teamcity:test?
I expect, that the testOptions would be modified with similar syntax:
testOptions in Teamcity := ...
I also would like to know, how to define the custom scope, preferable in simple *.sbt build, not in project/*.scala build.

The scope could be either project, configuration, or task. In this case, I think you're looking to define a custom configuration.
using itSettings
There's a built-in configuration called IntegrationTest already. You can define it in your build definition by writing:
Defaults.itSettings
This will use completely different setup from normal tests including the test code (goes into src/it/scala/) and libraries, so this may not be what you want.
defining your own configuration
Using sbt 0.13, you can define a custom configuration as follows in build.sbt:
val TeamCity = config("teamcity") extend(Test)
val root = project.in(file(".")).
configs(TeamCity).
settings(/* your stuff here */, ...)
defining teamcity:test
Now you have to figure out how to define teamcity:test.
Edit: Mark Harrah pointed out to me that there's a documentation for this. See Additional test configurations with shared sources.
An alternative to adding separate sets of test sources (and compilations) is to share sources. In this approach, the sources are compiled together using the same classpath and are packaged together.
putting it all together
val TeamCity = config("teamcity") extend(Test)
val root = project.in(file(".")).
configs(TeamCity).
settings(
name := "helloworld",
libraryDependencies ++= Seq(
"org.specs2" %% "specs2" % "2.2" % "test"
)
).
settings(inConfig(TeamCity)(Defaults.testTasks ++ Seq(
testOptions := Seq(Tests.Argument("nocolor"))
)): _*)
When you run teamcity:test the Specs2 output displays without color.

Related

Creating an aspectJ library using sbt-aspect

I am in the process of writing a library that does monitoring/OpenTracing and I am attempting to use sbt-aspectj so that users of the library don't need to manually instrument their code. I am currently however getting an issue with creating an sbt-project representing such a library.
The idea is that I want an external library as indicated in this sample here https://github.com/sbt/sbt-aspectj/tree/master/src/sbt-test/weave/external however that external library is dependant on an external dependency (i.e. akka-actors). Basically I am trying to combine both https://github.com/sbt/sbt-aspectj/tree/master/src/sbt-test/weave/external and https://github.com/sbt/sbt-aspectj/tree/master/src/sbt-test/weave/jar. I have created a sample project here https://github.com/mdedetrich/sbt-aspectj-issue to indicate the problem I am having however below is the relevant sample
lazy val root = (project in file("."))
.enablePlugins(SbtAspectj)
.settings(
name := RootName,
version := Version,
// add akka-actor as an aspectj input (find it in the update report)
// aspectjInputs in Aspectj ++= update.value.matching(
// moduleFilter(organization = "com.typesafe.akka", name = "akka-actor*")),
// replace the original akka-actor jar with the instrumented classes in runtime
// fullClasspath in Runtime := aspectjUseInstrumentedClasses(Runtime).value,
// only compile the aspects (no weaving)
aspectjCompileOnly in Aspectj := true,
// ignore warnings (we don't have the target classes at this point)
aspectjLintProperties in Aspectj += "invalidAbsoluteTypeName = ignore",
// replace regular products with compiled aspects
products in Compile ++= (products in Aspectj).value,
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % akkaVersion
)
)
lazy val test = (project in file("test"))
.enablePlugins(SbtAspectj)
.settings(
aspectjBinaries in Aspectj ++= update.value.matching(
moduleFilter(organization = Organization, name = s"$RootName*")),
aspectjInputs in Aspectj ++= update.value.matching(
moduleFilter(organization = "com.typesafe.akka", name = "akka-actor*")),
fullClasspath in Runtime := aspectjUseInstrumentedClasses(Runtime).value,
// weave this project's classes
aspectjInputs in Aspectj += (aspectjCompiledClasses in Aspectj).value,
products in Compile := (products in Aspectj).value,
products in Runtime := (products in Compile).value,
libraryDependencies ++= Seq(
Organization %% RootName % Version
)
)
The idea is that we publish the root project using root/publishLocal and the test project is just designed to include root as a libraryDependency so we can see if the aspect-j is working properly.
The problem is simple that I am unable to get it working. The current code at https://github.com/mdedetrich/sbt-aspectj-issue publishes with root/publishLocal (not sure if its correct though) however when I then do test/run I get this
[info] Weaving 2 inputs with 1 AspectJ binary to /home/mdedetrich/github/sbt-aspectj-issue/test/target/scala-2.13/aspectj/classes...
[error] stack trace is suppressed; run last test / Compile / packageBin for the full output
[error] (test / Compile / packageBin) java.util.zip.ZipException: duplicate entry: META-INF/MANIFEST.MF
[error] Total time: 1 s, completed Dec 29, 2019 4:31:27 PM
sbt:sbt-aspectj-issue>
Which seems to be an issue with having duplicate akka-actor entries. I tried toggling various entries in build.sbt but didn't manage to get it working.
EDIT: This was also posted as a github issue here https://github.com/sbt/sbt-aspectj/issues/44
Generally, you can exclude the META-INF directories from the external libraries woven.
mappings in (Compile, packageBin) := {
(mappings in (Compile, packageBin)).value
.filterNot(_._2.startsWith("META-INF/"))
}
But for akka libraries, there is another problem. In each akka library, there is a reference.conf, which contains the fallback configuration for the provided features. This will also lead to conflicts like the META-INF did. But it cannot be just excluded like the META-INF, because they are essential for akka to work properly.
If you exclude them, you'll have to provide all the required akka configurations in your application.conf, or a merged (not simply concatenate) reference.conf in your project. It's not trivial, and subject to version change of akka.
Another solution would be weaving and repackaging the akka libraries individually, so the reference.conf can be kept in the repackaged libraries. The project layout and build script will a bit more complicated, but also be easier to maintain if you have plan to upgrade to newer versions of akka in the future.

SBT : Override behavior of task "test" to run only tests from default testSource folder, there are multiple test source folders

We have standard SBT project with standard directory structure.
The test folder contains all the JUnit tests.
We introduced a new folder othertests and the folder othertests is peer to folder test
The othertest folder contains some special test cases. The test classes names in the folder othertest can be easily distinguished from the normal JUnit tests.
Below is my working build.sbt configuration.
I have added the folder othertest in test sources using javaSources in Test SBT task.
We are using activator to run tests and do other stuff.
When I run activator> test I want all tests from the folder test only to run and I want to run tests from the folder othertests separately.
Questions.
How to override the behavior of test tasks to filter out tests from the folder othertests
Should I create shared modules to run normal junit tests separately and other junit tests separately.
Below is my build.sbt configuration
import java.io.PrintStream
import play.sbt.PlayJava
import play.twirl.sbt.Import._
name := "Service"
version := "5.1.0"
scalaVersion := "2.11.8"
routesGenerator := InjectedRoutesGenerator
lazy val ContractTest = config("contract") extend(Test)
def contractTestFilter(name: String): Boolean = name endsWith "ContractTest"
def ignoreContractTest(name: String): Boolean = !contractTestFilter(name)
lazy val root = (project in file("."))
.enablePlugins(PlayJava)
.configs(ContractTest)
.settings(
inConfig(ContractTest) (Defaults.testTasks),
javaSource in Test := { (baseDirectory in Test) (_ / "contracttest") }.value,
testOptions in ContractTest := Seq(Tests.Filter(contractTestFilter),Tests.Argument(TestFrameworks.JUnit, "-q", "-v", "-s")),
testOptions in Test := Seq(Tests.Filter(ignoreContractTest),Tests.Argument(TestFrameworks.JUnit, "-q", "-v", "-s"))
)
lazy val xyz = taskKey[Unit]("custom task to create loglayout jar file under lib folder")
xyz := {
LogLayoutJar.build(scalaBinaryVersion.value, streams.value.log)
}
run := (run in Runtime).dependsOn(xyz).evaluated
javaOptions in Test ++= Seq("-Dconfig.resource=applic.tt.cnf")
libraryDependencies ++= Seq(
json,
javaWs,
"org.mockito" % "mockito-all" % "1.10.19" % Test,
"org.scalatestplus.play" %% "scalatestplus-play" % "1.5.1" % Test,
"org.easytesting" % "fest-assert" % "1.4" % Test,
"org.scalactic" %% "scalactic" % "2.2.0",
"org.jmockit" % "jmockit" % "1.9" % Test,
"com.portingle" % "slf4jtesting" % "1.0.0" % Test,
"org.scalacheck" %% "scalacheck" % "1.12.6" % Test
)
resolvers ++= Seq(
"Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
)
parallelExecution in Test := runningTestInParallel
testGrouping in Test := groupByModule((externalDependencyClasspath in Test).value,
(definedTests in Test).value, streams.value.log)
javacOptions ++= Seq(
"-Xlint:unchecked",
"-Xlint:deprecation"
)
scalacOptions ++= Seq(
"-feature",
"-language:implicitConversions",
"-deprecation"
)
// Custom tasks //
val silenceSystemErr = taskKey[Unit]("Replaces System.err with a PrintStream to nowhere.")
silenceSystemErr := {
System.setErr(new PrintStream(new DevNull))
println("Messages System.err will not be printed.")
}
val restoreSystemErr = taskKey[Unit]("Restores the original System.err")
restoreSystemErr := {
System.setErr(systemErr)
println("Messages System.err will be printed.")
}
From jenkins we run tests using below command -
bin/activator -Dsbt.log.noformat=true -Denvironment_name=test -DsuppressLogging=true clean silenceSystemErr jacoco:cover
Thank You
Rakesh
1.
You're contradicting yourself. Why add javaSources in Test if you don't want them to run when you run the Test command?
What you should do is create an [Additional Test configuration|http://www.scala-sbt.org/0.13/docs/Testing.html#Additional+test+configurations] that extends Test and runs only tests inside your othertests folder.
2.
You can create another module. I personally don't like this idea because then I have to name the module according to what it tests and I have 2 separate modules that should actually only be one.
A separate test module might be a good idea if you have some dependencies in your tests that slow down the overall build time of your module. For example imagine a Java project with Gatling performance tests. If the performance tests are in the same module then whenever I rebuild it it will also rebuild the gatling tests that require the scala compiler which is slower.
Some people can live with this, I'm one of them. I prefer to have the tests in the same project and possibly suffer a time penalty when rebuilding the module. Which rarely happens I create different test configurations when needed.
Another reason to choose separate modules for tests is when your tests depend on multiple modules and you don't want this module dependency at compile time for the src code.
Some IDE's and/or languages might encourage the use of separate module for tests as I understand is the case for C# and Visual Studio (but I might be wrong here, don't take my word for it).

After migrating library to scalajs, publish-local does not work

Following the hints of the post explaining the basics of migrating to scalajs and this page about cross-compilations, I decided to add cross compilation to my standalone dependency-free scala library by doing the following changes:
I added a file project/plugins.sbt with the content
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.16")
I added scalaVersion in ThisBuild := "2.11.8" in build.sbt because else just scalaVersion was using 2.10
I also added in the build.sbt the following content to ensure that I can keep the same directory structure, since I don't have any particular files for the JVM or for Javascript:
lazy val root = project.in(file(".")).
aggregate(fooJS, fooJVM).
settings(
publish := {},
publishLocal := {}
)
lazy val foo = crossProject.crossType(CrossType.Pure).in(file(".")).
settings(version := "0.1").
jvmSettings(
// Add JVM-specific settings here
).
jsSettings(
// Add JS-specific settings here
)
lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js
But now, after I published the project locally using sbt publish-local the projects depending on this library do not work anymore, i.e. they don't see the classes that this library was offering and raise errors.
I looked into .ivy2/local/.../foo/0.1/jars and the JAR went from 1MB to 1KB, so the errors make sense.
However, how can I make sure the JVM jar file is compiled correctly?
Further informations
The jar time does not change anymore, it looks like there had been some miscompilation. I deleted the .ivy2 cache, but now sbt publish-local always finishes with success but does not regenerate the files.
Ok I found the solution myself.
I needed to remove the publishLocal := {} from the build, and now all the projects depending on my library work fine.

Can I make sbt compile additional sources with additional dependencies only for a specific task?

I am using spray revolver to test my application while writting code.
I would like to make a revolver run compile additional sources (e.g. /src/dev.scala or whatever) with additional dependencies. This is so when testing locally I can startup some external sevices we are using (e.g. cassandra) in the same vm without the need to have a proper environment set up.
Initially I tried setting these settings like this:
unmanagedSources in Revolver.reStart <<= (unmanagedSources in Compile) map { ss => ss :+ new File("/path/to/my/dev.scala") }
libraryDependencies in Revolver.reStart += ("org.cassandraunit" % "cassandra-unit" % "2.0.2.1")
mainClass in Revolver.reStart := Some("my.main.class.in.dev")
But when running the task,I just get that the main class doesn't exist.
Is there any way to make this work? The idea is to avoid having the cassandra-unit and code in dev.scala out of the compilation for tests & packaging.
That cannot work, because Revolver.reStart still uses compile in Compile, and compile in Compile uses libraryDependencies, not libraryDependencies in Revolver.reStart.
To do this, you need to defined an entirely different, custom configuration that extends your Compile configuration. In that configuration, say "Localcompile", you can define your dependency with
unmanagedSources in Localcompile += new File("/path/to/my/dev.scala")
libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "2.0.2.1" % "localcompile"
See http://www.scala-sbt.org/0.13/docs/Advanced-Configurations-Example.html for examples.

How can I pass JVM options to SBT to use when running the app or test cases?

I would like to specify JVM options when running my app or the tests for the app through SBT. Specifically, I need to be able to give the JVM the -Djava.security.policy parameter so that my policy is loaded and used for the test.
How can I do this with SBT?
With xsbt, you could run your test in a forked JVM (because of one of the reasons mentioned in "Running Project Code".
If you are using a forked jvm:
specify the configuration to affect only the main or test run tasks:
scala javaOptions in (Test,run) += "-Xmx8G"
You should be able to specify any other options to that JVM through javaOptions.
The OP David Eagen reports that the following configuration didn't work at first, not because of the sbt options, but because of the path:
lazy val escacheServer =
Project( "escache-server",
file("server"),
settings = buildSettings ++ Seq(resolvers ++=
Seq(scala_tools_snapshots, typesafe_repo),
libraryDependencies ++= escacheServerDeps,
javaOptions in run += "-Djava.security.policy=jini.policy",
fork in run := true
)
).dependsOn(escache) }
It looks like my problem was that jini.policy wasn't found in the current directory.
I set the full path and now it runs.