2017-06-29 1 views
1

Sbt scheint anders Classloader zu verwenden, andernfalls einige Tests machen, wenn mehr als einmal in einer SBT-Sitzung mit dem folgenden Fehler führen:sbt mehrere Klassenladeprogramme mit

[info] java.lang.ClassCastException: net.i2p.crypto.eddsa.EdDSAPublicKey cannot be cast to net.i2p.crypto.eddsa.EdDSAPublicKey 
[info] at com.advancedtelematic.libtuf.crypt.EdcKeyPair$.generate(RsaKeyPair.scala:120) 

I tried equivalent code Muster anstelle von asInstanceOf und mir passend bekomme das gleiche Ergebnis.

Wie kann ich sicherstellen, dass sbt denselben Klassenlader für alle Testausführungen in derselben Sitzung verwendet?

+0

Können Sie Code einfügen, der dieses Problem in Ihrer Frage reproduziert? Warum denkst du, Klassenfahrer sind das Problem? –

+0

Ich beendete das Verfassen eines Problemberichts für sbt, um zu versuchen, dies zu debuggen, überprüfen Sie bitte https://github.com/sbt/sbt/issues/3306 Ich schrieb ein kleines Projekt, das dieses Problem reproduziert – simao

Antwort

1

Ich denke, es ist damit verbunden: Do security providers cause ClassLoader leaks in Java?. Grundsätzlich verwendet Security Anbieter von alten Klassenladern. Dies kann in jeder Umgebung mit mehreren Klassen (wie OSGi) passieren, nicht nur in SBT.

Fix für Ihre build.sbt (ohne Forking):

testOptions in Test += Tests.Cleanup(() => 
    java.security.Security.removeProvider("BC")) 

Experiment:

sbt-classloader-issue$ sbt 
> test 
[success] Total time: 1 s, completed Jul 6, 2017 11:43:53 PM 
> test 
[success] Total time: 0 s, completed Jul 6, 2017 11:43:55 PM 

Erläuterung:

Wie ich aus dem Code sehen kann (veröffentlicht here):

Sie verwenden den gleichen BouncyCastleProvider Provider jedes Mal, wenn Sie einen Test ausführen, da Ihr Security.addProvideronly first time funktioniert. Da sbt einen neuen Klassenlader für jeden "Testlauf" erstellt, aber denselben JVM verwendet - Security ist ein JVM-Scoped-Singleton, wie er von JVM-Bootstrap geladen wurde, sodass classOf[java.security.Security].getClassLoader() == null und sbt diese Klasse nicht erneut initialisieren/reinitialisieren können .

und Sie können leicht überprüfen, ob

classOf[org.bouncycastle.jce.spec.ECParameterSpec].getClassLoader() 
res30: ClassLoader = URLClassLoader with NativeCopyLoader with RawResources 

org.bouncycastle Klassen mit benutzerdefinierten Klassenlader (von SBT) geladen werden, die jede Zeit Sie test laufen ändert.

Also dieser Code:

val generator = KeyPairGenerator.getInstance("ECDSA", "BC") 

bekommt Instanz der Klasse von alten Klassenlader (der für die erste „Test“ run verwendet wird) geladen und Sie versuchen, es aus den neuen Klassenlader mit spec zu initialisieren:

generator.initialize(ecSpec) 

Das ist, warum Sie "Parameter Objekt nicht eine ECParameterSpec" Ausnahme erhalten. Die Argumentation um "net.i2p.crypto.eddsa.EdDSAPublicKey kann nicht in net.i2p.crypto.eddsa.EdDSAPublicKey umgewandelt werden" ist im Wesentlichen gleich.