RestController test fails with h2 database - spring

I am trying to run a test to my RestController in my Spring boot application with h2 database.
Here is some code:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
#ActiveProfiles("test")
public class E2E_EconomicOperatorAPIControllerTest {
#Autowired
private TestRestTemplate restTemplate;
#Test public void test_newEconomicOperator() {
//staff
}
}
But when I run it, i get this error:
2018-04-03 12:16:57.084 WARN 14332 --- [ Thread-7] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'inMemoryDatabaseShutdownExecutor': org.h2.jdbc.JdbcSQLException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-196]
And here is my properties file:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=Oracle;DB_CLOSE_DELAY=-1
logging.level.org.gso.admin=DEBUG
logging.level.gso.gd.client=INFO
logging.level.org.springframework.web.client=WARN
logging.level.org.springframework=WARN
logging.level.org.thymeleaf=WARN
logging.level.root=WARN

Actually, you shouldn't need to set any property for an embedded h2 database, as boot configures that for you (additionally, I think you should leave out the MODE=Oracle flag). Here's what I did:
Put the following dependendy in your .pom:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
Note the scope. This will load the dependency on your classpath during test (and nothing else). You should then make sure, that you have an application.properties file per environment, where you set the database wehnever you need a real one.
As an example from my app:
application-dev.properties: (note: I wanted a real db for dev, so i put in prostgres...)
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=validate
spring.database.driverClassname=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://192.168.1.100:5432/winecellar
spring.datasource.username=winecellar
spring.datasource.password=winecellar
application-test.properties:
spring.jpa.database=H2
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.database.driverClassname=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.username=sa
spring.datasource.password=
And I have a similar file for production settings (using postgres as well...)
Then, as long as you annotate it as you have done with #ActiveProfiles("test"), you should be fine.

Related

Unable to connect non stop SQL from Spring boot applivcation

My project uses non stop SQL/MX as RDBMS database, a product from HP.I am not able to connect to the data source using Spring Boot's standard practice of defining JDBC URL, user, password inside application.properties file.
spring.datasource.driverClassName = com.tandem.sqlmx.SQLMXDriver
spring.datasource.url = jdbc:sqlmx:
spring.datasource.username=
spring.datasource.password=
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SqlmxDialect
spring.datasource.hikari.connection-test-query=SELECT 1 FROM $USER1.TLFM3SQL.IF09CSTB
This is the error:
com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Driver does not support get/set network timeout for
connections. (com.tandem.sqlmx.SQLMXConnection.getNetworkTimeout()I)
JdbcEnvironmentInitiator: could not obtain connection to query metadata: Unable to resolve name
[org.hibernate.dialect.SqlmxDialect ] as strategy [org.hibernate.dialect.Dialect]
I had not included SQLMX hibernate jar in project.
It worked after I included that jar in my pom.

Spring Boot Test seems to be creating H2 Test DB different than what I would expect

So, I have a Test annotated with #DataJpaTest and #RunWith(SpringRunner.class), and an application.yml under /src/test/resources with this block (yes, indenting should be fine):
spring:
datasource:
url: jdbc:h2:mem:foobar;MODE=Mysql;MVCC=FALSE;
username: sa
password:
driver-class-name: org.h2.Driver
When I start the Test, I unexpectedly get these lines in the log:
2019-10-23 17:11:08.311 INFO 13468 --- [ main] beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version
2019-10-23 17:11:08.801 INFO 13468 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:7855270f-61b7-4f37-8796-cbfeb8ad42ea;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
In particular this: Starting embedded database: url='jdbc:h2:mem:7855270f-61b7-4f37-8796-cbfeb8ad42ea;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false
Why is Spring boot starting a DB with a UUID-Generated DB and not taking the settings from spring.datasource.url?
The "productive" app takes the datasource settings fine from the file in /src/main/resources with same syntax without issues...
From the documentation of #DataJpaTest you can see that:
#DataJpaTest uses an embedded in-memory
database (replacing any explicit or usually auto-configured
DataSource). The #AutoConfigureTestDatabase annotation can be used to
override these settings.
So #DataJpaTest annotated with #AutoConfigureTestDatabase that causes TestDatabaseAutoConfiguration to create embedded datasource with hard-coded generateUniqueName(true):
TestDatabaseAutoConfiguration.java :
EmbeddedDatabase getEmbeddedDatabase() {
...
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(connection.getType())
.build();
}
I think they do this to prevent DB name collisions and state mix between test runs.

Spring boot 2.1.0 Hikari CP bad password

So I updated my Spring Boot to 2.1.0, and now hikari is the default CP. According to some SO questions related to this I no longer needed to use the .hikari in my application.properties file. My properties file now looks like this:
# H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Datasource
spring.datasource.url=jdbc:h2:file:~/deployHistory/deployHistory
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
Now if I use the driver manager directly, like this:
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection(databaseUrl);
Statement stat = conn.createStatement();
stat.execute("create table ...)");
stat.close();
conn.close();
It all works fine, However, when I use the Spring Boot JDBC template, and do a simple:
jdbcTemplate.update(...);
I get an error:
2018-11-26 14:27:54.772 INFO 7349 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2018-11-26 14:27:56.059 ERROR 7349 --- [nio-8080-exec-1] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
org.h2.jdbc.JdbcSQLException: Wrong user name or password [28000-197]
What is the way to fix this? All the pre-2.0.4 answers don't seem to work.

Spring boot embedded tomcat logs

i'm using spring boot embedded tomcat with spring boot 1.5.9 ,
im also using Log4j2.
recently i exerience problems during load, so i want to understand better the tomcat logs [Not the access Logs] , i tried (in application.properties) :
logging.level.org.apache.tomcat: INFO
logging.level.org.apache.catalina: INFO
but none of the above worked. is there any other way to achieve it ?
Found it !! You are now able to see the internal Logs of Embedded Tomcat in your App's Log4j log file with 3 easy steps:
1] add to your pom:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
</dependency>
2] add to your running arg a new JVM param , e.g:
java -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -jar target/demo-0.0.1-SNAPSHOT.jar
3] add to your application.properties:
logging.level.org.apache=DEBUG
Enjoy Life ! :)
Explaination:
the problem is because Log4j log levels is not propagated into JUL (which is the actual Logging way Embedded tomcat use) so the above achieves this connection with JUL and Log4j log levels.
Reference:
After reading the Spring boot 1.5.10 release notes (which is not required for the solution) i saw the new documentation that shed light how to achive it and explaination about it:
https://github.com/spring-projects/spring-boot/issues/2923#issuecomment-358451260
I struggled a lot,and didnt find anything of my help.Utlimately I had build "WAR" out of my spring boot application.Deploy it to tomcat instance and
followed below steps,which redirected all the internal tomcat logs(JULI) logs to my application log file.
Delete existing JULI library (CATALINA_HOME/bin/tomcat-juli.jar file) and the existing Tomcat Java Logging configuration file (CATALINA_HOME/conf/logging.properties).
Download JULI Log4j Tomcat library (tomcat-juli.jar) from the Tomcat downloads’ Extras section (http://tomcat.apache.org/download-70.cgi). Place the downloaded file to CATALINA_HOME/bin directory.
Download Tomcat JULI adapters library (tomcat-juli-adapters.jar) from the Tomcat downloads’ Extras section. Place this file in the CATALINA_HOME/lib directory.
Download Log4j (version 1.2 or later), and place the downloaded library file to CATALINA_HOME/lib directory.
Create the Log4j configuration file at the following location: CATALINA_HOME/lib/log4j.properties. Check below log4j configuration matching the default Java Logging configuration.
Restart Tomcat.
Log4j configuration File Matching the Default Tomcat Logging Settings:
log4j.rootLogger=INFO, CATALINA
//Define all the appenders log4j.appender.CATALINA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.CATALINA.File=${catalina.base}/logs/catalina.
log4j.appender.CATALINA.Append=true log4j.appender.CATALINA.Encoding=UTF-8
//Roll-over the log once per day
log4j.appender.CATALINA.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.LOCALHOST=org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost.
log4j.appender.LOCALHOST.Append=true log4j.appender.LOCALHOST.Encoding=UTF-8
log4j.appender.LOCALHOST.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.MANAGER=org.apache.log4j.DailyRollingFileAppender
log4j.appender.MANAGER.File=${catalina.base}/logs/manager.
log4j.appender.MANAGER.Append=true log4j.appender.MANAGER.Encoding=UTF-8
log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.HOST-MANAGER=org.apache.log4j.DailyRollingFileAppender
log4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager.
log4j.appender.HOST-MANAGER.Append=true log4j.appender.HOST-MANAGER.Encoding=UTF-8
log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
//Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].
[localhost]=INFO,
LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].
[localhost].[/manager]=INFO,MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].
[localhost].[/host-manager]=
INFO, HOST-
MANAGER
You can also check a adapter avaiable on GIT # link
In your spring boot application,you can make changes like adding and removing jars,folder from embedded Tomcat server Or even adding custom config files to it using TomcatEmbeddedServletContainerFactory.class ,of spring boot.
For slf4j and Spring Boot 2 hide exceptions from Tomcat and handle them by yourself:
Add to pom:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
Add to config:
#PostConstruct
void postConstruct() {
SLF4JBridgeHandler.install();
}
Add to application.yaml
logging:
level:
org.apache.catalina: off
Handle exception in ErrorController
#Controller
#Slf4j
public class ErrorController implements
org.springframework.boot.web.servlet.error.ErrorController {
private static final String ERROR_PATH = "/error";
#Autowired
private ErrorAttributes errorAttributes;
#Override
public String getErrorPath() {
return ERROR_PATH;
}
#RequestMapping(ERROR_PATH)
public ModelAndView error(HttpServletRequest request) {
return processException(errorAttributes.getError(new ServletWebRequest(request)));
}
}
Default configurations are provided for Java Util Logging, Log4J, Log4J2 and Logback. In each case loggers are pre-configured to use console output with optional file output also available
refer this link : https://stackoverflow.com/questions/31939849/spring-boot-default-log-location/31939886
The embedded tomcat in spring boot internally echoes logs to console.
The default log configuration will echo messages to the console as they are written. So until you explicitly specify a file as you described, it stays in the Console.
From the spring boot logging doc.
You can custmize the logging as per your need.
A log file, generated by org.apache.catalina.valves.AccessLogValve, usually named something like localhost_access_log can be configured like this:
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory = new TomcatEmbeddedServletContainerFactory();
AccessLogValve accessLogValve = new AccessLogValve();
// set desired properties like
accessLogValve.setDirectory(...);
tomcatEmbeddedServletContainerFactory.addEngineValves(accessLogValve);
return tomcatEmbeddedServletContainerFactory;
}
}
Or, much better with Spring Boot 2:
#Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customizer() {
return container -> {
AccessLogValve accessLogValve = new AccessLogValve();
// set desired properties like
accessLogValve.setDirectory("...");
container.addEngineValves(accessLogValve);
};
}

Spring Boot JPA H2 Console not running, application.properties file ignored

The Spring Boot guide says I can get the H2 console but it's not working for me.
http://localhost:8080/h2/ Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Oct 26 12:31:46 BST 2016
There was an unexpected error (type=Not Found, status=404).
No message available
I created an application.properties file as follows
spring.h2.console.enabled=true
spring.h2.console.path=/h2
My project is based on this
The default path /h2-console doesn't work either.
I found another answer where the problem is solved by adding to Application.java:
#Bean
public ServletRegistrationBean h2servletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet());
registration.addUrlMappings("/h2/*");
return registration;
}
Everything in my application.properties file is ignored. I have tried adding:
spring.datasource.url=jdbc:h2:file:~/portal;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
But the database is still created in memory only.
Check if you set a base path in application.properties.
For example, if you have a setting
server.contextPath=/api
You access the h2 Console under
http://localhost:8080/api/h2-console
Obvious, but that was it for me
Another possible cause for this problem, is if you're using spring security.
In that case, you may want to add a specific permission to the h2-console URL you defined.
For example, for the default h2-console configuration (without a spring.h2.console.path property), you will add this inside your WebSecurityConfigurerAdapter extending class:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.anyRequest().authenticated();
http.headers().frameOptions().sameOrigin();
}
Please also note that line at the end - http.headers().frameOptions().sameOrigin();.
It's needed to prevent a Whitelable page error when logging in to the console.
This is described also here.
Your current location src\main\java\h‌​ello\application.pro‌​perties is the culprit. For 2 reasons.
Non java resources in src\main\java are ignored
only application.properties in the root or config directory or taken into account (by default). (See the reference guide).
The fix is to simply move your application.properties to src\main\resources.
In my case, I just had to remove the tag <scope>runtime</scope> from the h2 dependency as explained in here.
a / is missing before spring.h2.console.path it have to look like :
spring.h2.console.path=/h2
also when you indicate spring.h2.console.path /h2-console is no more available
Regards
I tried h2-console while building my microservice project and fell into the same issue "Whitelabel error page".
I haven't added any security in my project for now but I found the problem for me is solved by removing spring.h2.console.enabled= true from application.properties and adding dependency dev-tools. for me not adding dev-tools also caused the problem so try to add this dependency as well. while of course, you will add h2, actuator, web dependencies.
Try the below in application.properties
spring.h2.console.enabled: true
try to add to application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
//then
create class SecurityConfig
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().antMatchers("/").permitAll().and()
.authorizeRequests().antMatchers("/h2-console/**").permitAll();
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
}
}
For me scope=test was the issue as I carelessly copied from https://mvnrepository.com/artifact/com.h2database/h2/1.4.200
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
<scope>test</scope>
</dependency>
And replaced it with
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
<scope>runtime</scope>
</dependency>
After this, it should work with default configurations.
I am not using spring security, but you might need to make certain changes accordingly. Please check above answers for that https://stackoverflow.com/a/59729714/7359806
First, make sure to have these dependencies:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Then add these to your application.properties:
##spring.main.web-application-type=none make sure it's commented
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
##server.port=9999 make sure you use default port (8080). In other words, don't specify a server.port
For me - a computer restart fixed it.
Not sure why this would be the cause but perhaps a port was occupied, or the h2 related files were not deployed correctly
make sure you that when the springBoot application is launched, you can see the log lines for Hibernate and H2 are present:
2017-04-22 14:41:03.195 INFO 912 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final}
2017-04-22 14:41:03.197 INFO 912 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2017-04-22 14:41:03.199 INFO 912 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2017-04-22 14:41:03.278 INFO 912 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-04-22 14:41:03.469 INFO 912 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2017-04-22 14:41:03.935 INFO 912 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
2017-04-22 14:41:03.945 INFO 912 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
For this problem, i just add the default string at my application.properties and works.
spring.datasource.url=jdbc:h2:file:~/test
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
Maybe the spring boot dont set this for some reason.
Remove <scope>test</scope> from h2 dependency in pom.xml works in my case.
Don't forget to reinstall and build again after your modification.
<!-- H2 database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<!-- <scope>test</scope> -->
</dependency>
I used compile otherwise testCompile in the Gradle declaration and was worked fine for me.
Example:
compile group: 'com.h2database', name: 'h2', version: '1.4.200'
If you are having troubles with the program ignoring the application.properties and you are using Eclipse, do the following:
Move the application.properties into the src/main/resources folder, right click on it and click "build path" -> "Add to build path"
Make sure to use> spring.datasource.url=jdbc:h2:mem:testdb as this db is required for h2
I found the same case using Eclipse 4.26.0
Did some of above method and not work. Until in one forum, someone suggest us to add devtools dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
I hope it works for you.

Resources