How to disable Spring-Boot scheduling during Maven Clean Install? - spring-boot

I have a #Configuration class annotated with #EnableScheduling and I want it to be disabled during the mvn clean install command.
The problem is that it also triggers the start & stop goals, due to the Spring-Doc maven plugin, https://springdoc.org/#maven-plugin
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot-maven-plugin.version}</version>
<configuration>
<jvmArguments>-Dspring.application.admin.enabled=true</jvmArguments>
</configuration>
<executions>
<execution>
<goals>
<goal>start</goal>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
Is there a way to set some environment variable, e.g. SCHEDULING_ENABLED=false, during the maven clean install command in order to avoid the scheduling jobs at compile time ?
Update
I can't simply skip the springdoc generate loagoal because I have to download the OpenAPI yaml file.
I updated my configuration class as follows:
#Configuration
#ConditionalOnProperty(prefix = "scheduling", value = "enabled", havingValue = "true")
#EnableScheduling
public class SchedulingConfiguration {
#Value("${scheduling.enabled}")
private Boolean schedulingEnabled;
#PostConstruct
public void init(){
System.out.println("Scheduling enabled: " + this.schedulingEnabled);
}
}
and these are th two application.yml:
src/main/resources/application.yml
scheduling:
enabled: true
src/test/resources/application.yml
scheduling:
enabled: false
However, during the mvn clean install command I alway get Scheduling enabled: true on the console.
Is there something I am missing?
Update 2
I did upload a minimal project on GitHub https://github.com/MaurizioCasciano/Scheduling-Demo
showing the problem.
My idea is that the following pom.xml snippet, required by Spring-Doc, simply starts the app as usual without any particular profile, e.g. test properties:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>start</goal>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<apiDocsUrl>http://localhost:8081/v3/api-docs.yaml</apiDocsUrl>
<outputFileName>API.yaml</outputFileName>
<outputDir>src/main/resources/api</outputDir>
</configuration>
</plugin>
</plugins>
</build>
Is it possible to specify here the properties to load or the Spring-Boot profile to activate?

According to the documentation the relevant configuration is the<skip>true</skip>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>true</skip> <----------------
</configuration>
</plugin>
This will avoid the application execution during this phase of the build so the scheduller will not be executed as well.
But this will work only if you dont have integration tests related with documentation. Otherwise you would want the application to be started during this phase.
If you still want the application to startup during integration-test phase as to make some integration testing on documentation you can follow this answer in order to exclude the enable scheduling configuration for tests. In integration-test phase normally your application will load application.yml from test classpath. So there you can provide the adviced property to switch it of.

After a lot of trials and errors I came to the conclusion that the only way to disable Scheduling during the maven clean instal command, or in other words during the following goals/phases:
Spring-Boot-Maven-Plugin start
Spring-Boot-Maven-Plugin stop
SpringDoc-OpenAPI-Maven-Plugin integration-test
is as follows.
Annotate the Scheduling #Configuration in order to be disabled when the test profile is active.
Define the active profile equal to test in src/test/resources/application.yml
Define the active profile equal to test in the spring-boot-maven-plugin execution configuration.
#Configuration
#Profile("!test")
#EnableScheduling
public class SchedulingConfiguration {
#PostConstruct
public void init(){
System.out.println("Scheduling enabled");
}
}
spring:
profiles:
active: test
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<configuration>
<profiles>
<profile>test</profile>
</profiles>
</configuration>
<goals>
<goal>start</goal>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
Explanation of what I understood:
point 1 allows disabling scheduling when the test profile is active.
point 2 allows disabling scheduling during the execution of test classes.
point 3 allows disabling scheduling when the app is started for allowing the download of the OpenAPI documentation.
Here https://github.com/MaurizioCasciano/Scheduling-Demo/tree/Disable-Scheduling-On-Tests you can find the working code on GitHub.

Related

Command line mvn parameter to stop spring-boot-maven-plugin from executing run

I'm developing a Spring Boot application and as part of the Integration Test phase of my maven project, I have configured the spring-boot maven plugin to start up and shut down during the pre and post integration test parts of the build as follows:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
However, I did this just so that my developers can run their tests against a local instance of the service. On Jenkins, I would run the tests against an external service where I had deployed the service and I do not need the Spring Boot application to be spun up within the Jenkins job.
Is there a way for me to explicitly stop the spring-boot maven plugin from starting up the service via a mvn command line override?
Sure, you can expose a property for it, something like
<properties>
<skip.it>false</skip.it>
</properties>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
</executions>
</plugin>
Once you have that, run your command as follows: mvn verify -Dskip.it=true and the Spring Boot application will not be started as part of your integration tests.

Include testing test groups for failsafe (integration testing) only but exclude them from surefire

The following config does not work. No test is in scope for the goal integration-test.
In case it is unclear, What should happen is that what I do a mvn integration-test the failsafe plugin should run my test. But the surefire plugin configuration is excluding the test. If I uncomment the surefire config block the test is run during the integration-test goal.
Maven config:
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<groups>spring-container-sanity</groups>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludedGroups>spring-container-sanity</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
A Java Test class
#SpringApplicationConfiguration(TestApplication.class)
#TestPropertySource("/test.properties")
public class SimpleTest extends AbstractTestNGSpringContextTests {
#Test(groups = "spring-container-sanity")
public void isHessianServiceExported() throws Exception {
/*...*/
}
}
I don't know why the tests are run when surefire is disabled. Failsafe has a file naming convention for integration tests, if the tests you want to run do not follow this they won't be in scope and the group rule will have nothing to match. So, in this case to get failsafe to resolve the tests it should run correctly you first need to add an include filter. This build block will work:
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<groups>spring-container-sanity</groups>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludedGroups>spring-container-sanity</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
When annotating your test, make sure to define an array of groups, even if its only a single one.
#Test(groups = {"spring-container-sanity"})

Spring doesn't autowire #Configurable when running Dropwizard integration test during maven build

I'm using Spring's #Configurable to autowire a bean constructed with 'new' in a Dropwizard application. I have an integration test that uses the DropwizardAppRule to bring up the application and am using the aspectj-maven-plugin for compile time weaving.
When I make build and run the integration test from IDEA the bean is wired as expected and the test passes.
When I run 'mvn clean install' the bean is NOT wired and the test fails with a NullPointerException.
When I run 'mvn clean install -DskipTests' and start the application the bean is wired correctly.
My question is why does it fail during 'mvn clean install'?
The aspectj-maven-plugin is running during the process-sources phase so the classes should be instrumented before the integration tests run:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
If I decompile the class I can see that it has indeed been instrumented.
If I put break point in the #Autowired setter and run the integration test from IDEA I can see that the class is being wired by Spring.
It doesn't break in the setter at all when running 'mvn clean install'.
Replacing #Autowired with #Resource doesn't help.
I have a Spring configuration class that has #EnableSpringConfigured. My best guess is that the DropwizardAppRule isn't using the correct Spring configuration although the other spring components are being managed correctly.
Any help is greatly appreciated. Thank you.
edit
I've also tested both default surefire (maven 3.2.5) and with:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
I figured it out but a little more context is required to explain the problem. The #Configurable was being instantiated in an enum like so:
public enum Day {
MONDAY(new MyConfigurableObject()),
...
}
Unit and integration tests were run together and the unit tests were instantiating the enum before a spring context was available. Because enums exist in a static context, the unwired enum was then used by the integration test.
The solution is to split up unit and integration test execution. I did this using the maven-failsafe-plugin like so:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<excludes>
<exclude>it/**</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>it/**</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

Maven Plugin conflict

What all i want to do is run test in phase integration-test and then generate report.
by mvn verify
But only test are executed report never runs. When i comment first plugin then other is executed. Any idea how to fix it?
I have below in my pom
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<classpathScope>test</classpathScope>
<executableDependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-core</artifactId>
</executableDependency>
<mainClass>cucumber.api.cli.Main</mainClass>
<arguments>
<argument>target/test-classes/feature</argument>
<agrument>--glue</agrument>
<argument>integration</argument>
<argument>src\test\java</argument>
<argument>--plugin</argument>
<argument>pretty</argument>
<argument>--plugin</argument>
<argument>html:target/cucumber-report</argument>
<argument>--plugin</argument>
<argument>json:target/cucumber-report/cucumber.json</argument>
<argument>--tags</argument>
<argument>~#ignore</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>poc.selenium.it</projectName>
<outputDirectory>target/cucumber-report</outputDirectory>
<cucumberOutput>target/cucumber-report/cucumber.json</cucumberOutput>
<enableFlashCharts>true</enableFlashCharts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The problem is due to the fact that cucumber.api.cli.Main calls System.exit and therefore terminates the Maven process before the other plugin gets to be executed.
One way to fix the problem would be to use the exec goal of the exec-maven-plugin, rather than the java goal, as it runs in a separate process.
However, a better (and easier) solution is to define a JUnit test that will configure and run your cucumber tests, for example:
package integration;
import org.junit.runner.RunWith;
import cucumber.api.junit.Cucumber;
import cucumber.api.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(plugin = "json:target/cucumber-report/cucumber.json")
public class RunTest {
}
You can then use either the maven-surefire-plugin or the maven-failsafe-plugin plugin to execute that test. The maven-cucumber-reporting plugin will then execute successfully and create the report.
You can see this in action on a github branch I have just pushed.

JMS integration tests with Maven and Glassfish

I'm developing an app requiring MDB, running over Glassfish 3.1. I've managed already to run unit/integration tests of simple EJBs using embedded container with no problem. Now I'm trying to create integration tests for my MDBs.
1) I tried launching the Glassfish embedded server programatically, but it does not support creation of JMS queues.
2) I run a Glassfish server from the Maven plugin.
Now I can create queues, and deploy my MDBs, no problem at all. Now, I just can't figure out a way of running JUnit.
- When I create an InitialContext, it times-out when accessing the local server. I have no ways of accessing my beans.
I found a workaround, but it's not serving my needs perfectly:
In my test sources, I created a simple Singleton #Startup bean. In the #PostConstruct method, I call the unit test classes I want to achieve. In order for this bean to be deployed, I have a special special maven build rule that packages some of my tests files in the EJB jar. Deploying this special jar results in my tests being launch. To make it clear, here's an extract of my Maven file:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>pre-integration-test</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/test-ejb</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/classes</directory>
</resource>
<resource>
<directory>${project.build.directory}/test-classes</directory>
<includes>
<include>**/*TestTrigger.class</include>
<include>**/*IntegrationTest.class</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
<ejbVersion>3.1</ejbVersion>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>ejb</goal>
</goals>
<configuration>
<classifier>TEST</classifier>
<outputDirectory>${project.build.directory}/test-ejb</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.glassfish</groupId>
<artifactId>maven-embedded-glassfish-plugin</artifactId>
<version>${glassfish.version}</version>
<configuration>
<goalPrefix>glassfish</goalPrefix>
<app>target/${project.build.finalName}-TEST.jar</app>
<port>8080</port>
<name>MyApp</name>
<serverID>embedded</serverID>
</configuration>
<executions>
<execution>
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>admin</id>
<phase>pre-integration-test</phase>
<goals>
<goal>admin</goal>
</goals>
<configuration>
<commands>
<param>create-jms-resource --restype javax.jms.QueueConnectionFactory jms/TestQueueConnectionFactory</param>
<param>create-jms-resource --restype javax.jms.Queue --property imqDestinationName=ceQueue jms/ceQueue</param>
</commands>
</configuration>
</execution>
<execution>
<id>deploy</id>
<phase>pre-integration-test</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>undeploy</goal>
<goal>stop</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
Now, is there any way my IntegrationTest can be launched using surfire, in order to produce a proper report and fail build if test don't pass? Not to mention Cobertura.
Thank you for your help.
I didn't solve my problem so to say. What I had to do is upgrade to GlassFish 3.1.1. This version supports JMS in embedded mode. Therefore I can run a server programatically and deploy the queues I want using the admin command runner.
I just lost a bit of time trying to name my connection factory jms/connectionFactory where the jms/ prefix was unnecessary and was failing all lookups.
I also had to include a thread sleep in all my unit tests or else the server would close before tests are over.

Resources