Spring Boot profiles not active when set with maven plugin - spring-boot

I'm trying to set spring profiles when starting Tomcat for integration tests in maven like this:
...
<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>
<profiles>
<profile>testProfile</profile>
</profiles>
</configuration>
...
The profile is definitely not active.
On the other hand the following does work and the requested profile is active:
<jvmArguments>-Dspring.profiles.active=testProfile</jvmArguments>
The problem here is that we can't stop the server, which is a problem when running automated integration tests.
I'm using spring boot "1.4.0.RELEASE".
My questions:
1. Why does the profile tag not work? (Bug?)
2. Why id the JMX bean not found when trying to shutdown the server in the "stop" goal? Does this something have to do with the forking because of the jvmArguments?

I was ignoring the args in the main method. Passing them to the Spring application solved it:
public static void main(String[] args) throws Exception {
SpringApplication.run(RunServer.class, args);
}

Related

Change port of deployed Spring project on Wildfly

Note to moderator: Other existing questions in SO make reference to the default interface. I'm not interested on changing that. I need to specifically change the port of each deployment.
Other questions regard wildfly running in standalone mode. I'm running it as a Windows Server Service.
Based on this please do not close the question.
Now, the question:
Taking as a reference the following Spring application, running on Wildfly on Windows Server 2019 installed as a service:
#Configuration
#SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
static Logger logger = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<DemoApplication> applicationClass = DemoApplication.class;
}
When I was using Tomcat, changing the web service port was easy as adding:
Application.properties
server.port=8093
Resulting in the desired URL:
http://127.0.0.1:8093/swagger-ui.html
However, deploying on Wildfly proved to be harder. At first, it was the .war name and the wrong context root, which I fixed by adding the following changes:
pom.xml
<finalName>${project.artifactId}</finalName>
src\main\webapp\WEB-INF\jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.jboss.com/xml/ns/javaee
http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<context-root>/</context-root>
</jboss-web>
However, there's the last problem. The web service is being exposed on http://127.0.0.1:8080/swagger-ui.html instead of using port 8093.
How can I change the port of each deployed web service in Wildfly, instead of the default 8080?
The server.port property only controls the listening port of an embedded server in a Spring boot app (tomcat, jetty, etc.).
The app's port in a standalone application server is specified during the deployment. The easiest way to do this on Wildfly is via the wildfly-maven-plugin (https://docs.jboss.org/wildfly/plugins/maven/latest/deploy-mojo.html):
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>2.1.0.Final</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<filename>${project.build.finalName}.war</filename>
<hostname>127.0.0.1</hostname>
<port>8093</port> <!-- <<<<<<<< -->
<username>my-wildfly-user</username>
<password>my-wildfly-password</password>
</configuration>
</plugin>
<!-- ... -->
</plugins>
</build>

When I do "mvn verify", I cannot get the spring-boot project to load the application properties

My project is on an isolated computer, so I can't do massive dumps of files, but I will try to provide the necessary information.
I have a Spring-Boot MVC project. I can get it to run fine from the command line. I can get the ApplicationContext to fun fine as long as I am using the Spring-Boot-Test starter:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
#TestPropertySource(locations = { "classpath:application-test-h2.properties" })
#DirtiesContext(classMode = ClassMod.AFTER_EACH_TEST_METHOD)
I have recently added some HTMLUnit tests to go do some integration testing. The tests run fine when I have the application already running (which means it can't be done automatically on the corporate Bamboo). So, after stumbling around the web, I added the cargo plugin:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.16</version>
<configuration>
<wait>false</wait>
<container>
<containerId>tomcat8x</containerId>
<type>embedded</type>
<logLevel>info</logLevel>
<container>
<configuration>
<properties>
<cargo.servlet.port>8443</cargo.servlet.port>
<cargo.protocol>https</cargo.protocol>
<cargo.tomcat.connector.clientAuth>false</cargo.tomcat.connector.clientAuth>
<cargo key and password stuff censored>
<cargo.tomcat.httpSecure>true</cargo.tomcat.httpSecure>
</properties>
</configuration>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals><goal>start</goal></goals>
</execution>
<execution>
<id>stop-server</id>
<phase>post-integration-test</phase>
<goals><goal>stop</goal></goals>
</execution>
</executions>
</plugin>
I also went to the maven failsafe plugin and did:
<execution>
<id>integration-test</id>
<goals><goal>integration-test</goal></goals>
</execution>
<execution>
<id>verify</id>
<goals><goal>verify</goal></goals>
</execution>
Finally I edited the spring-boot-maven-plugin and added:
<execution>
<id>pre-integration-test</id>
<goals><goal>start</goal></goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals><goal>stop</goal></goals>
</execution>
So, I can finally see my application context start up when I do a "mvn verify". All is well and good, right up until it tries to connect to the database. I have 2 application.properties files and a application-test-h2.properties.
They are:
|--- ProjectDirectory
\--- src/main/resources
\--- application.properties (1)
\--- src/test/resources
\--- application-test-h2.properties (2)
\--- application.properties (3)
It appears from the error message that it is only picking up the application.properties noted by (1). The cargo startup does not appear to be getting (2) or (3) or using the precedence Spring projects use.
The integration tests are simple:
#RunWith(Theories.class)
public void HTMLUnitIT {
#Datapoints
private static MyTestObject[] datapoints;
#Theory
public void testSearches(MyTestObject obj) throws Exception {
//..... stuff ... This stuff runs if I just run the class and have the application running
}
}
So the $64,000 question is, how do I get the properties to all resolve in the cargo plugin?
Thank you in advance.

Auto-configured tests as integration tests

I've got a spring boot application that I'd like to automatically test.
I've written an #DataJpaTest unit test like the one here, and it works fine, however it slows down the build process considerably due to having to start spring.
I'd like to run these tests as integration tests using the maven failsafe plugin, but I can figure out how to do this. If I rename the tests so they match *IT.java, failsafe tries to run them, but spring doesn't start and I get java.lang.NoClassDefFoundError errors for the injected repositories.
What's the best way to run spring boot tests as integration tests?
Update 18 March:
With a dependency on spring-boot-starter-test:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
And the following plugin configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<plugin>
The integration tests execute correctly using mvn failsafe:integration-test. However, I'd like the tests to be run when I do mvn install, so I updated the plugin config to:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<plugin>
And now the spring framework doesn't start when I run the test with mvn verify, so I get java.lang.NoClassDefFoundError for the JpaRepository I'm trying to inject and test.

application-test.properties isn't loaded when activating profiles with <profiles>

I'm trying to use new feature from Spring Boot 1.3.0.RELEASE -- activate profile via configuration of spring-boot-maven-plugin:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>test</profile>
</profiles>
</configuration>
<executions>
<execution>
<id>start-application</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-application</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
But in this case my integration test starts to fail, because of IllegalArgumentException: Could not resolve placeholder 'spring.mail.host' in string value "${spring.mail.host}"
This variable defined in src/main/resources/application-test.properties:
spring.profiles: test
spring.mail.host: 127.0.0.1
My test look like this:
#ContextConfiguration(
loader = AnnotationConfigContextLoader.class,
initializers = ConfigFileApplicationContextInitializer.class,
classes = TestContext.class
)
public class WhenAnonymousUserRegisterAccount extends AbstractTestNGSpringContextTests {
#Value("${spring.mail.host}")
private String mailHost;
TestContext only defines PropertySourcesPlaceholderConfigurer with another property files.
The interesting part is that if I remove <profiles> and activate profile from application.properties my test works:
spring.profiles.active: test
So, it looks like that when I'm using <profiles> Spring doesn't load application-test.properties file to the environment.
Questions:
is it a bug?
(if it's not) how to configure Spring to load application-test.properties and use <profiles>?
why these approaches are differ?
If you specify the profiles in the configuration of the spring-boot-maven-plugin then they are only available if you execute the application with that plugin, i.e. by running mvn spring-boot:run. I suspect, that's not the case for your integration test and thus it doesn't work.

hsql for unit tests maven

I am using sql-maven-plugin to setup a in memory hsql database for unit tests
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.5</version>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.8</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>create-db</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<driver>org.hsqldb.jdbcDriver</driver>
<url>jdbc:hsqldb:mem:test;shutdown=false</url>
<username>SA</username>
<password></password>
<autocommit>true</autocommit>
<srcFiles>
<srcFile>src/test/sql/test_db/test.sql</srcFile>
</srcFiles>
</configuration>
</execution>
</executions>
</plugin>
in unit tests that run in maven:test phase, I instantiated a datasource with that url
org.hsqldb.jdbc.JDBCDataSource ds = new JDBCDataSource();
ds.setUrl(URL);
ds.setUser("sa");
ds.setPassword("");
but this does not have the tables that i had initialized via the scripts. it turns out surefire forks a new jvm and the original hsql instance started is not accessible from there. Is there a solution without introducing a file backed hsqldb ?
Thanks
You could try turning off forking in surefire.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<forkCount>0</forkCount>
</configuration>
</plugin>
Or, you could instantiate the HSQL server directly in your unit test environment, so that HSQL is spawned within the forked Surefire JVM:
#BeforeClass
public static void oneTime() throws Exception {
org.hsqldb.Server.main(new String[]{});
}
#AfterClass
public static void oneTime() throws Exception {
BasicDataSource dataSource = ... // get your data source
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("SHUTDOWN");
}
If you don't shutdown HSQL after your test class, you'll run into "Port already in use" type errors from trying to spawn a new db server for each test class.
Or, you could use a framework like Hibernate or DbUnit.
Have you considered using dbunit? That will also make it a lot easier to run the unit-tests from your IDE without requiring Maven or executing all its pre test phases.
Also, for a unittest is it required to use a database? You shouldn't be testing if a db connection could be made. Instead I'd prefer to mock such objects with something like mockito. It is about specifying what result you want for a certain sql statement.

Resources