Spring Boot with Cucumber E2E (Selenium) testing - spring

In my project, I have to current Maven modules setup:
- Application
|- (application code, using Spring Boot 1.2.6)
- E2E-testing (has a dependency to Application)
|- src
|- main
|- java
|- AbstractCucumberTest.java
Before, this used to be a Spring 3 application serving JSP pages, so no Boot included. I refactored it to be a Boot application.
The E2E testing setup basically built a WAR file of the application code, and the E2E module booted a Jetty server, running that WAR. All was well.
Now, after the refactor, not so much.
The Jetty setup no longer works as-is. When I boot the WAR, I'm getting class loading exceptions, which are related to Jetty itself. Now, I'm not hung up on Jetty, it's just a testing container for me. So I started digging around in the Boot documentation, because I was convinced there had to be a way to make it all "Boot'-iful, meaning: I could simply boot the application when launching the tests. And there is, of course, so I ended up with these annotations on my AbstractCucumberTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfig.class, loader = SpringApplicationContextLoader.class)
#WebIntegrationTest({"spring.profiles.active=local"})
public abstract class AbstractCucumberTest extends SeleniumTest {
So, basically, I'm loading the application config of the application, and launching the Tomcat server from the test. And all rejoiced, because now the application was successfully booting upon launching a Cucumber test. The application boots, it reads the classpath, Liquibase boots, everything is working alright. I can call the Actuator endpoints, which all work fine. Even the REST endpoints of the application are all working, so Spring MVC is doing its thing.
However, 1 thing is not, and that's serving JSP's -- and that's of course a deal breaker for E2E tests. Every time I surf to a page, I get the same unnerving 404 error. Before you ask: yes, tomcat-embed-jasper and jstl are present. They are present in the application, I even added them to the E2E pom, no luck. In fact, these are the things I tried, but they all failed:
Excluding the tomcat-embed-jasper and jstl dependency from the application
Copying over the JSP's from the application to the resources of the E2E module
Setting up my own CucumberConfig, which basically contained the same configuration as the ApplicationConfig
It just seems to me that the application cannot find the JSP's. Everything else is working just fine, just the JSP's are not found/served.
Does anyone have any thoughts?
Oh, on a side note, I tried using the spring-boot-maven-plugin, to try and boot the application that way. Problem is, though, that it cannot be forked. In the 1.2.6 release, the fork simply ... does not fork. When I say fork, I mean it in the Jetty way: it boots the application, and gives control back to Maven. It instantiates a "stop" command, which Maven can call after all tests have run.
In the 1.3.0.BUILD-SNAPSHOT version, it should be present (using the start goal), but that's still not working for me.
[EDIT] For what it's worth, the Application module is configured to build a WAR file. So it's not JAR packaging.

To whom it may concern, eventually I turned to the Maven Cargo plugin, which works just fine. I configured it in the pom of the E2E testing module. As you can see, my application is marked as a deployable, and the cargo plugin boots at the pre-integration-test phase, and shuts down at post-integration-test phase.
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.16</version>
<configuration>
<container>
<containerId>tomcat8x</containerId>
<zipUrlInstaller>
<url>
http://archive.apache.org/dist/tomcat/tomcat-8/v8.0.27/bin/apache-tomcat-8.0.27.zip
</url>
</zipUrlInstaller>
</container>
<deployables>
<deployable>
<groupId>my.group.id</groupId>
<artifactId>Application</artifactId>
<type>war</type>
<properties>
<context>/context</context>
</properties>
</deployable>
</deployables>
<configuration>
<type>standalone</type>
<properties>
<cargo.servlet.port>9999</cargo.servlet.port>
<cargo.jvmargs>-Dspring.profiles.active=local</cargo.jvmargs>
</properties>
</configuration>
</configuration>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>

Related

Quarkus Endpoints in dependency jars

I have a quarkus application which has dependencies to another maven module within the same project
within that module are REST endpoints
For some strange reason i cannot access those endpoints tho.. It seems quarkus will only accept endpoints of java classes within the quarkus module, or am I mistaken?
I foudn a solution:
if yopu add the jandex, endpoiints of other modules are being scanned, and can thus be found :
<build>
<plugins>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You can do this by creating a dummy extended class:
Lets assume your imported jar has this pattern, app\proto-gen\1.0-SNAPSHOT\proto-gen-1.0-SNAPSHOT.jar
Add the below to application.properties,
quarkus.index-dependency.mygrpc.group-id=app
quarkus.index-dependency.mygrpc.artifact-id=proto-gen
#Singleton
MyGrpc extends XImplBase{
//your implementation
}
beans you extended/implemented in your current project will be started.
Check https://quarkus.io/guides/cdi-reference. You need to add a beans.xml to external models, create an index or reference the dependency using quarkus.index-dependency in the application.properties.
Then it will work when running tests or using the runner. But not in dev, because there is a probably in the current version (1.1.1Final). This problem has been fixed in the master, though, and will be available in the next release next month.
Please check ClassCastException in Quarkus multi-module project for more details.

Spring boot: resolve JSPs from jar dependencies

Unfortunately haven't found an answer in official documentation. Maybe what I'm trying to do is not supported event by Tomcat, but still. Is it possible to make spring-boot/Tomcat to resolve JSP pages from .jar file that is in the classpath?
I have a spring-boot (2) application that is packed as a war file. There are a numerous jsp pages in 'webapp/view' folder, and appropriate MVC configuration:
#Configuration
public class MVCConf implements WebMvcConfigurer {
// ...
#Bean
public ViewResolver internalResourceViewResolver() {
return new InternalResourceViewResolver(){{
setPrefix("/view/");
setSuffix(".jsp");
setRedirectHttp10Compatible(false);
}};
}
// ...
}
All these pages are being resolved. Okay.
But. The project is a multi-module maven one. It supports builds with different dependencies (my own modules) depending on maven profiles.
I need to make application to resolve JSPs from those optional dependencies that are included into runtime as jars in a classpath.
And I'm getting Whitelabel error that says that JSP files can not be found.
Is it even possible to make it work? And if it is, than how?
P.S.: I have already tried to make some magic with copying JSPs into "root" spring-boot application itself and it works, but this way is dirty and tricky.
I don't think it is worth to publish the whole pom.xml, but here is the maven-dependency-plugin section that works in my case:
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<!-- this skip property is set by maven profile in same pom.xml - no magic here -->
<skip>${exclude.some_submodule}</skip>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>some_submodule</artifactId>
<version>${project.version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<!-- there are webapp/view/*.jsp files in some_module's structure -->
<includes>view/**</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- ... -->
The only problem here is that it works only when you launch the executable .war. Launching this application from IDE (IntelliJ IDEA) need some additional steps to be made. And that's another one disadvantage of this solution, to my mind. The first one is a dirty pom.xml.
TL;DR
Solution:
BUT!. I have found another solution that is more suitable, I think.
Actually I have moved from Tomcat to Jetty, and solution above works fine even there. There's no need in hacking the build anymore.
Now I put my .jsp files into src/main/webapp/META-INF/resources/view/some_module folder in some_module dependency and resolve it by path 'some_module/someJsp' via standard Spring's #Controllers.
I apologize that I haven't found this topic earlier. Now this is a duplicate. But who knows, maybe someone will apply solution with maven dependency plugin.

GWT + Maven + Tomcat + JNDI + Eclipse configuration

I've got a project using GWT 2.6.1 + Maven 3.2 + Tomcat 5.5 (yes, I know it's an old one ...) + Eclipse Luna which is using JNDI allowing for external parameters to be configured.
As you might know, the context XML file is located at /conf/Catalina/localhost/myWebApp.xml where myWebApp is the Java web application name.
I am using gwt-maven-plugin for this project (the one from mojo haus) which has the version 2.6.1.
Here is my current configuration :
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>2.6.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test</goal>
<goal>i18n</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
<!-- Plugin configuration. There are many available options, see gwt-maven-plugin documentation at codehaus.org -->
<configuration>
<module>xxx.yyy.myModuleName</module>
<runTarget>myWebPage.html</runTarget>
<hostedWebapp>${webappDirectory}</hostedWebapp>
<encoding>UTF-8</encoding>
<failOnError>true</failOnError>
<style>OBF</style>
<i18nMessagesBundle>xxx.yyy.zzz.client.ui.i18n.OlbClientMessages</i18nMessagesBundle>
<extraParam>true</extraParam>
<extraJvmArgs>-Dgwt.compiler.optimizationLevel=9</extraJvmArgs>
<extraJvmArgs>-Xms128M</extraJvmArgs>
<extraJvmArgs>-Xmx1200M</extraJvmArgs>
<extraJvmArgs>-XX:MaxPermSize=768M</extraJvmArgs>
<noServer>true</noServer>
<logLevel>INFO</logLevel>
</configuration>
</plugin>
As you can see, i am using the noServer (configured to "true") option because I must use an external Tomcat container for the server side.
My question is :
How can I enable client side AND server side debugging within my actual configuration through a step-by-step help.
I've made a lot of attempts but i can't make things working.
I've tested running the "mvn gwt-debug" which tries to connect to default port 8000 and then connecting a remote java application which connects to my webapp to localhost:8000 and it works well, but it's only for the server side.
I also need to debug the client side in the DEVMODE.
Thanks for your help.
There are two ways to run a remote server. First is using using DevMode with -noserver and pointing the war directory to the output war directory of the external server. The second way is to use the CodeServer entrypoint and run a WTP server runtime and set the launcher directory to tomcat output war directory.
I prefer the second routine, and built automation into the GPE fork.
http://gwt-plugins.github.io/documentation/gwt-eclipse-plugin/servers/Tomcat.html - see it in action here. There are videos and such.

How to hot redeploy non-active maven project via jetty-maven-plugin

I'm trying to evaluate jetty for rapid development or project which is currently running on tomcat. My configuration looks like
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.3.v20140905</version>
<configuration>
<scanIntervalSeconds>3</scanIntervalSeconds>
<webApp>
<descriptor>${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml</descriptor>
<resourceBases>
<directory>${basedir}/src/main/webapp</directory>
<directory>${basedir}/../SharedWeb/src/main/webapp</directory>
</resourceBases>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
<contextPath>/test</contextPath>
</webApp>
</configuration>
</plugin>
I have main war depending on SharedWeb war via war overlay mechanism. I specify resourceBases for both maven projects so changes in resources are scanned automatically and reloaded on the fly and all working fine. Also when I compile classes in main war, jetty restarts automatically, reloading the latest changes. But when I try to change any class in SharedWeb project and compile it, the class is not reloaded. I'm just wondering if there is a way to make embed jetty to reload classes from SharedWeb automatically? I understand that jetty-maven-plugin uses SharedWeb war from local maven repository, so I need to install SharedWeb artifact before I can see any changes. So I don't have high expectations, but maybe I'm missing something.
Ivan,
The plugin is using the classes and resources from your dependency
war, NOT from the that you have added. The
simply tells jetty to watch that location and redeploy if something in
it changes - it does NOT put it onto the classpath.
You need to tell jetty to use the classes and resources from your
dependency war's project, NOT the war artifact.
So do something like:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.3.v20140905</version>
<configuration>
<webApp>
<!-- tell jetty to use the classes from the dependency
webapp project directly -->
<extraClassPath>${basedir}/../SharedWeb/target/classes</extraClassPath>
<!-- tell jetty to use both this project's static
resources, and those of the dependency webapp project -->
<resourceBases>
<directory>${basedir}/src/main/webapp</directory>
<directory>${basedir}/../SharedWeb/src/main/webapp</directory>
</resourceBases>
</webApp>
<scanIntervalSeconds>3</scanIntervalSeconds>
<!-- tell jetty to watch the dependency webapp project classes
dir for changes -->
<scanTargets>
<scanTarget>${basedir}/../SharedWeb/target/classes/</scanTarget>
</scanTargets>
</configuration>
</plugin>
Jan
Since there doesn't seem to be a good prior answer that is specific enough for this question (aka <scanTarget>) I'll just post this new one and tweak the title to make it easier to find in the future.
What you are looking for is <scanTarget>, as that will allow you to customize the scanning locations for changed content that will trigger a hot redeploy.
The jetty-maven-plugin intentionally does not set this up for custom <resourceBases> as there are far to many legitimate use cases where this can cause aggressive / too often / or infinite redeploys. It was decided that it was best to break from "convention over configuration" for <scanTarget> entries and allow the developers to decide what should be scanned for changes.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.3.v20140905</version>
<configuration>
...
<scanIntervalSeconds>3</scanIntervalSeconds>
<scanTargets>
<scanTarget>${basedir}/../SharedWeb/src/main/webapp/</scanTarget>
<scanTarget>${basedir}/../SharedWeb/target/classes/</scanTarget>
</scanTargets>
</configuration>
</plugin>

Best way to hand a WAR file from one Maven project to another, to use with Embedded Jetty?

I thought this was simple, but having problems:
Project1 is of type war. It creates an entire webapp .war file, including some Apache modules (solr/lucene), and some of our custom code.
Project2 is an existing application. It needs to launch embedded Jetty to do queries against Project1's war file. (see code below)
Main Problem:
When Project2 instantiates Jetty, it needs to pass in the full path to the WAR file, but this changes each time. Maven adds version number stuff to Project1's war file.
Assemblies to the Rescue?
I'm able to get a custom assembly to work, but can't get rid of the versioning stamp from Project1.
But I always wind up with Project1-1.4.1-20120530.233546-2.war. It's in a more convenient place, but the name is still weird.
Jetty code in Project2:
// Context
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
String jettyHome = System.getProperty( "jetty.home", ".." );
String fullWarName = ...; // Project1's WAR file. This path always changes
webapp.setWar( fullWarName );
// Server
Server server = new Server( kPort ); // TODO: get from config
server.setHandler(webapp);
server.start();
server.join();
Other considerations:
I realize there is a maven-jetty plugin, but I don't believe that's appropriate here. It seems to be targeted at Unit tests, and also our application stack doesn't use maven at runtime to launch services.
I'm also aware that Solr has a fully embedded version that doesn't require a web container, but that's been deprecated for a while and not a good idea to use.
Is there a better way to refactor this project? Maybe this isn't "the maven way" ?
It turns out I didn't need an assembly (advice I had got internally), instead there's something easier in the main pom. Also, having the war unpacked here turned out to be a nice idea.
At the top of Project1's pom.xml I have:
<groupId>com.my.group</groupId>
<artifactId>project-one</artifactId>
<version>1.2.3-SNAPSHOT</version>
<packaging>war</packaging>
This goes near the bottom of Project2's pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-webapp</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.my.group</groupId>
<artifactId>project-one</artifactId>
<version>1.2.3-SNAPSHOT</version>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/webapps/project-one</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
Then when launching Jetty I have:
webapp.setWar( "target/webapps/project-one" );
I still think there might be issues with some Jetty settings, but I think this is the right direction.

Resources