I'm trying to get a passing build of the embedded Tomcat 6 container from which to start work on adding an embedded Tomcat 7 container. Thanks to some helpful IRC conversations with Aslak I believe I've pushed through the Maven issues leftover from the old-to-new Git repository switch. Now I've hit a new issue when running the embedded in-container tests (full test output attached):
Caused by: java.lang.IllegalStateException: Service org.jboss.arquillian.protocol.servlet.ServletExtension does not implement expected type org.jboss.arquillian.core.spi.LoadableExtension at org.jboss.arquillian.core.impl.loadable.JavaSPIExtensionLoader.load(JavaSPIExtensionLoader.java:113) ... 57 more
Of course ServletExtension does implement LoadableExtension, so this seems like the old classes loaded twice by multiple classloaders situation. Assuming I've interpreted my debug sessions correctly here is what I believe is going on:
LoadableExtension is included from the launching test's classloader (i.e. the system classloader) from arquillian-core-spi as a compile-scoped dependency in Maven.
Then org.jboss.arquillian.container.test.impl.deployment.ArquillianDeploymentAppender also adds it to the webapp classloader from arquillian-core.jar in WEB-INF/lib.
ServletExtension is not added to the webapp's libs, so when it is loaded by JavaSPIExtensionLoader during the in-container test it comes from system classloader, as implements the system classloader's copy of LoadableExtension.
When JavaSPIExtensionLoader then goes to asSubclass ServletExtension from LoadableExtension it pulls the LoadableExtension copy from the webapp classloader on account of org.jboss.arquillian.container.tomcat.embedded_6.EmbeddedWebappClassLoader reversing the standard delegation order.
Because the ServletExtension from the system classloader implements the LoadableExtension copy from the system classloader, this casting to the webapp classloader's copy of LoadableExtension fails.
I can think of two ways to resolve this:
One approach would be to launch embedded containers such as Tomcat and Jetty from a new thread, and use setContextClassLoader to give them a minimal bootstrap classpath. This would be similar to how they're started as remote containers. Then all the necessary API for the in-container test would be added to the deployed test archive.
The other approach would be to add nothing to the deployed test archive, and pull everything from the launching test's system classloader. If nothing is added to the webapp that's already in launching test's classpath then there are no such conflicts.
Both of these seem about equidistant from the current state of affairs, so I could use some direction on how to proceed. In general would it be preferable to keep the system classpath for embedded containers minimal, or to not augment deployed test archives as much?
My instinct says the to go with the minimal bootstrap classpath for launching, as it's closer to the remote container classloader/classpath situation that I believe most are more familiar with. In my case in particular I'm looking to leverage the convenience of an embedded container for integration tests of an app that is otherwise normally deployed to a remote container. I believe the closer the integration test environment is to the deployed environment the better.