sqality / scct

Scala Code Coverage Tool
Apache License 2.0
67 stars 7 forks source link

sbt multi project build - Could not initialize class error #6

Open taylorleese opened 11 years ago

taylorleese commented 11 years ago

Below is the relevant piece of my Build.scala. Any idea what I'm doing wrong or is this a bug? I'm using sbt 0.12.4, Scala 2.10.2, and version 0.3-SNAPSHOT of scct.

NoClassDefFoundError: : Could not initialize class com.github.scct.Coverage$
lazy val myProject = Project("myproject", file("."),
  settings = standardSettings ++ Seq(
    name := "myproject",
    publish := {}
  )
)
.settings(ScctPlugin.mergeReportSettings: _*)
.aggregate(common, server)

lazy val common = Project("common", file("common"),
  settings = standardSettings ++ Seq(
    name := "common",
    libraryDependencies ++= sharedDependencies ++ testDependencies,
    publishArtifact in Test := true
  )
)
.settings(ScctPlugin.instrumentSettings: _*)

lazy val server = Project("server", file("server"),
  dependencies = Seq(common % "compile->compile;test->test"),
  settings = standardSettings ++ oneJarSettings ++ Seq(
    name := "server",
    libraryDependencies ++= sharedDependencies ++ serverDependencies ++ testDependencies
  )
)
.configs(Atmos)
.settings(atmosSettings: _*)
.settings(ScctPlugin.instrumentSettings: _*)
taylorleese commented 11 years ago

@D-Roch Any idea what could be going on with this?

jimschubert commented 11 years ago

I was having the same issue with this until I updated sbt to 0.13.0.

I use a slightly modified sbt bootstrap script (original here) configured for sbt 0.12.4. I updated the script to pull 0.13.0, but kept sbt.version=0.12.4 in my build.properties.

I received the following warnings:

$ ./sbt scct:test
[warn] The global sbt directory is now versioned and is located at /Users/jschubert/.sbt/0.13.
[warn]   You are seeing this warning because there is global configuration in /Users/jschubert/.sbt but not in /Users/jschubert/.sbt/0.13.
[warn]   The global sbt directory may be changed via the sbt.global.base system property.
[info] Loading project definition from /Users/jschubert/tmp/scala/domain/project
[info] Updating {file:/Users/jschubert/tmp/scala/domain/project/}domain-build...
[info] Resolving com.twitter#sbt-package-dist;1.1.1 ...

After doing this, I received an error while executing tests:

Fail: java.lang.IllegalArgumentException: URI is not hierarchical
java.lang.IllegalArgumentException: URI is not hierarchical
    at java.io.File.<init>(File.java:363)
    at com.github.scct.Env$$anonfun$coverageFile$2.apply(Env.scala:55)
    at com.github.scct.Env$$anonfun$coverageFile$2.apply(Env.scala:55)
    at scala.Option.getOrElse(Option.scala:120)
    at com.github.scct.Env.coverageFile(Env.scala:55)
    at com.github.scct.Coverage$.readMetadata(Coverage.scala:34)
    at com.github.scct.Coverage$.<init>(Coverage.scala:9)
    at com.github.scct.Coverage$.<clinit>(Coverage.scala)
...

I tracked this error down to PackageDist.newSettings from the twitter sbt-package-dist plugin (link). Removing PackageDist.newSettings from my settings fixed the 'URI is not hierarchical' issue. There may be a conflicting setting in PackageDist, but I didn't dig any deeper.

Code coverage is now generated for me. There's also the added bonus that sbt is backward compatible so I can still use the twitter sbt-package-dist plugin which targets 0.12.4.

taylorleese commented 11 years ago

@jimschubert I get a similar but different error with sbt 0.13.0. With 0.13.0 I get a NoClassDef found error on one of my own classes and PermGen errors even with 1GB of PermGen. Interesting.

taylorleese commented 11 years ago

Actually, if I follow the stack trace a little further the core issue is the same as with 0.12.4:

Could not initialize class com.github.scct.Coverage$
taylorleese commented 11 years ago

I believe this may be related to perm gen issues since I also see them along with the error listed above. How do you increase perm gen size to scct:test?

val defaultArgs = Seq(
  "-Xmx2048m",
  "-XX:MaxPermSize=512m"
)
javaOptions in Test ++= defaultArgs
0xRoch commented 11 years ago

@taylorleese have you tried ? :

val defaultArgs = Seq(
  "-Xmx2048m",
  "-XX:MaxPermSize=512m"
)

javaOptions in ScctTest ++= defaultArgs
taylorleese commented 11 years ago

@D-Roch It got rid of the permgen error but the original issue is still there.

kscaldef commented 11 years ago

the "URI is not hierarchical" error seems independent of whether it's a multi-project or simple build. I see it in either case. Per http://stackoverflow.com/questions/10144210/java-jar-file-use-resource-errors-uri-is-not-hierarchical, it seems like the construction being used in Env.scala is simply not valid.

cmbaxter commented 11 years ago

We are experiencing this same issue. From what I can see, the plugin is first creating a coverage.data file under /target/scala-2.10/scct-classes. After that, that contents of that folder is packaged up into a jar called $projectnameandversion$-scct.jar under /target/scala-2.10. That jar also contains the coverage.data file in it. When the Env class tries to find the coverage.data file, it seems to be picking it up from the jar and not the external classpath and when it tries to convert a jar based File into a URI, it fails for that 'URI is not hierarchical' reason. Anyone have any idea on why this is happening this way and how to work around it?

gshakhn commented 11 years ago

@cmbaxter We hit the 'URI is not hierarchical' error as well. The comments in mtkopone/scct#22 helped me a lot. See my comments on that issue for my solution. Not quite sure if you're hitting the same exact problem, but the 'URI is not hierarchical' part makes me suspicious.

cmbaxter commented 11 years ago

@gshakhn, ya, I actually came to the same conclusion about exportJars := true being the main culprit. We're just going to disable that during the coverage run so as to avoid this issue. Thanks for responding though. It's always good to see someone draw the same conclusion.

taylorleese commented 11 years ago

@cmbaxter Is there a nice way to disable that in the build file just for the code coverage task?

cmbaxter commented 11 years ago

@taylorleese from a logic perspective, this should basically be seeing if the scct:test command is being run and setting exportJars setting accordingly. But I'm not an sbt expert by any means, so I was not able to see an easy way to get the list of commands that are about to be executed. I certainly would appreciate any advice on how to get this in a build.scala file. In the mean time, I have got this working by setting up a val like so:

val runningCoverage = Option(System.getProperty("sun.java.command")).map(_.split(" ")).getOrElse(Array.empty).find(_ == "scct:test").isDefined  

And then setting export jars as: exportJars := !runningCoverage

taylorleese commented 11 years ago

I was able to get sbt clean scct:test to run with exportJars := false however I get another exception when attempting to run sbt scct-merge-report.

java.util.NoSuchElementException: empty map
    at scala.collection.immutable.RedBlackTree$.smallest(RedBlackTree.scala:65)
    at scala.collection.immutable.TreeMap.head(TreeMap.scala:75)
    at scala.collection.immutable.TreeMap.head(TreeMap.scala:48)
    at com.github.scct.report.HtmlReporter.projectSummaryReport(HtmlReporter.scala:35)
    at com.github.scct.report.HtmlReporter.summaryReport(HtmlReporter.scala:25)
    at com.github.scct.report.MultiProjectHtmlReporter$.report(MultiProjectHtmlReporter.scala:17)
    at ScctPlugin$.generateReport(ScctPlugin.scala:102)
    at ScctPlugin$$anonfun$2.apply(ScctPlugin.scala:86)
    at ScctPlugin$$anonfun$2.apply(ScctPlugin.scala:86)
    at scala.Function2$$anonfun$tupled$1.apply(Function2.scala:54)
    at scala.Function2$$anonfun$tupled$1.apply(Function2.scala:53)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
    at sbt.std.Transform$$anon$4.work(System.scala:64)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
    at sbt.Execute.work(Execute.scala:244)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:695)
taylorleese commented 10 years ago

@D-Roch Any movement on this? I still have the problem of requiring exportJars := false for sbt scct:test to work and have never been able to successfully run sbt scct-merge-report.

choedl commented 10 years ago

Hi, I have exactly the same problem (java.util.NoSuchElementException). Any news on this issue?

taylorleese commented 10 years ago

@choedl I switched to the sbt jacoco plugin. Works great.

kscaldef commented 10 years ago

@taylorleese We use jacoco4sbt currently too. While it "works", I can't really say that it works. Even under the best of conditions, its understanding of Scala is pathetic and leads to tons of "uncovered" code. But, it also seems buggy in that the coverage reports can't be reliably trusted unless you run 'clean' immediately before 'jacoco:cover'.

leonardschneider commented 10 years ago

Same exception here.

> last model/*:scctMergeReport
java.util.NoSuchElementException: empty map
sksamuel commented 10 years ago

Migrate to scoverage, because as you say, jacoco doesn't really understand Scala.