I wanted to share with everyone an Arquillian extension I made: https://github.com/handcraftedbits/arquillian-incontainerurl-extension (also available on Maven Central). This extension allows you to inject the URL of the deployment into a URL field or method parameter from within a container-based test. This is a feature that's been on hold for nearly four years: https://issues.jboss.org/browse/ARQ-540.
Having access to the URL from within a container-based test makes testing REST services (for example) so much easier -- set up the backend via injected beans/resources then call the service and check the state of your beans/resources. No need for convoluted schemes to bridge the gap.
I would be interested to get the opinions of the Arquillian experts on my approach, because it's really not that complicated so I'm surprised that no one's done it before (to the best of my knowledge). It's entirely possible that I'm doing something that won't work in all scenarios. Or perhaps no one has really been bothered by this limitation. Anyway, here's how the extension works:
Prereq: URL field or method parameter is annotated with @InContainerResource.
- An observer registered to the BeforeDeploy event is notified before deployment of the test archive begins. The archive is examined and:
- If this is an EAR, the first available WAR is selected and a RemoteLoadableExtension, TestEnricher, and Servlet (more on this in a moment) is added to the WAR. Arquillian won't let you have more than one WAR in an EAR so this is perfectly fine to do.
- If this is a WAR, a RemoteLoadableExtension, TestEnricher, and Servlet is added to the WAR.
- If this is a different kind of module, it's ignored since it won't be able to support a Servlet (plus there wouldn't be a URL available to access the deployment anyway).
- An observer registered to the AfterDeploy event is notified after the deployment of the test archive finishes but before remote test case enrichment begins. The observer uses a standard method (searching for an HTTPContext inside ProtocoMetaData, then using the URL associated with it) to figure out the URL of the deployment. That URL is posted to the Servlet that was added to the WAR in step 1, which in turn saves the URL.
- During remote test case enrichment, any URL fields/method parameters annotated with @InContainerResource are injected with the value posted to the Servlet.
And that's it. There are a bunch of test cases included that assert that this extension works properly with single deployments, multiple deployments (i.e., @OperateOnDeployment), and within EAR archives. Please take a look and tell me what you think!