#SpringBootTest constructor is running multiple times - spring-boot

I am trying to run below test case in Spring Boot.
:: Spring Boot :: (v2.3.1.RELEASE)
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = com.dineoutsafe.api.dosadmin.DOSAdminAPIApplication.class)
#ActiveProfiles("test")
public class POSTSessionTest {
public POSTSessionTest() {
System.out.println("Calling post construct");
}
#Test
public void testOne(){
assertThat(45,equalTo(30+15));
}
#Test
public void testTwo(){
assertThat(45,equalTo(30+15));
}
#Test
public void testThree(){
assertThat(45,equalTo(30+15));
}
#Test
public void testFour(){
assertThat(45,equalTo(30+15));
}
#Test
public void testFive(){
assertThat(45,equalTo(30+15));
}
}
And I noticed that the constructor is running multiple times. Actually it is running (no. of #Test -1) times.
In standard output
2020-06-21 16:00:26.668 INFO 93912 --- [ task-1] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-06-21 16:00:26.679 INFO 93912 --- [ task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-06-21 16:00:27.025 INFO 93912 --- [ Test worker] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
2020-06-21 16:00:27.034 INFO 93912 --- [ Test worker] c.d.a.d.i.session.POSTSessionTest : Started POSTSessionTest in 5.511 seconds (JVM running for 6.414)
Calling post construct
Calling post construct
Calling post construct
Calling post construct
Same behaviour I noticed for #PostConstruct.
Is it normal for #SpringBootTest?

This is the default behavior of JUnit5, you can change it by annotating the per-class lifecycle on the class: https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/TestInstance.Lifecycle.html

Related

running the application on controller

I'm still a beginner with spring boot, I'm using spring JPA to fetch the data from multiple tables in the same database and everything going fine, I used to run my application at the Main but here I have added a Controller class and running things there, then i used #Scheduled(fixedRate=7000) instead of creating an infinite loop to keep check the data from db and stay live, the application working fine but as far as at the running time application executed twice instead of once at the beginning before scheduling, a is there any idea about what happened here :
Mainclass :
#SpringBootApplication
#EnableScheduling
public class AccessingDataJpaApplication {
public static void main(String[] args) throws Exception{
SpringApplication.run(AccessingDataJpaApplication.class);
}
}
Controller class :
#Controller
#EnableScheduling
public class MainController {
private static final Logger logger = LoggerFactory.getLogger(MainController.class);
#Autowired
private CustomerRepository customerRepository;
#Autowired
private MessageRepository messageRepository;
private Set<String> camps = new HashSet<String>();
#Bean
#Scheduled(fixedRate=7000)
public void run(){
logger.info("Running");
if((customerRepository.findAllByStatusAndCampType(0, 1).size()) > 0 ){
for(Customer customer : customerRepository.findAll()){
System.out.println(customer.getCampCd());
camps.add(customer.getCampCd());
}
System.out.println("----------------------------------------");
for(MessageCampain messagecampain : messageRepository.findAllByCampCdIn(camps)) {
System.out.println(messagecampain.toString());
}
System.out.println("------------------------------------------");
for(String value : camps) {
System.out.println(value);
}
}
}
}
execution log :
[ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
[ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
[ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
[ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
[ main] c.e.accessingdatajpa.MainController : Running
[ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
[ main] c.e.a.AccessingDataJpaApplication : Started AccessingDataJpaApplication in 5.467 seconds (JVM running for 6.242)
[ scheduling-1] c.e.accessingdatajpa.MainController : Running
[ scheduling-1] c.e.accessingdatajpa.MainController : Running
you can notice that at Running word
It is because you annotate the run() in MainController as #Bean , which will creates a lite mode bean called run. (Spring represents this bean as the type of NullBean internally)
So , the 1st call of 'Running' in the main thread is due to spring instantiate this run bean. The remaining calls of 'Running' in the scheduling-1 thread are due to the the effect of #Scheduled. So please remove #Bean from the run() as it does not have any points to create a null bean ...
#Scheduled(fixedRate=7000)
public void run(){
}

#Cacheable and initialization during startup

I would like to initialize all entries in cache during startup of my spring boot application (loading stuff from DB). Ideally, this is done before the application is already ready. So I implemented all loading in #PostConstruct. I remarked, that the cache is not already setup in #PostContruct and I followed some tips to do such initializations in the ApplicationReadyEvent. However, this still does not work as expected:
Even though I already call a #Cacheable Method in ApplicationReadyEvent, the second invocation re-enters the method instead of using the cache.
My Service:
#Service
public class MyService implements ApplicationListener<ApplicationReadyEvent {
#Cacheable("entry")
public List<String> getEntry() {
System.out.println("getEntry called!");
return Arrays.asList("aaa", "bbb");
}
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
System.out.println("*** onApplicationEvent");
getEntry();
}
}
My Caffeine CacheManager Config:
#Configuration
#EnableCaching
public class CachingConfig {
#Bean
public CacheManager cacheManager() {
List<CaffeineCache> caffeineCaches = chacheList(Arrays.asList(
"entry"
));
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
simpleCacheManager.setCaches(caffeineCaches);
System.out.println("*** #Bean CacheManager");
return simpleCacheManager;
}
private List<CaffeineCache> chacheList(List<String> cacheNames) {
return cacheNames.stream().map(s -> new CaffeineCache(s, Caffeine.newBuilder().build()))
.collect(Collectors.toList());
}
}
A simple REST endpoint using the service:
#RestController
public class MyController {
#Autowired
MyService myService;
#GetMapping("/test")
public void test()
{
System.out.println("*** GET /test");
myService.getEntry();
}
}
If I start the application and perform two GET /test, I get the following output:
INFO 20120 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 907 ms
*** #Bean CacheManager
INFO 20120 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
INFO 20120 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
INFO 20120 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.639 seconds (JVM running for 2.473)
*** onApplicationEvent
*** getEntry called!
INFO 20120 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO 20120 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
INFO 20120 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
*** GET /test
*** getEntry called!
*** GET /test
So why does the second invocation of MyService.getEntry (i.e. the first invocation after "Startup") enters the code again?
At the end, I need a solution, which performs the first loading before the application finished to startup - i.e. I will try ContextRefreshedEvent or again #PostConstruct (and #Autowire CacheManager to have it configured before executing #PostConstruct). But the first step would be to get this example here behave as expected.
Ok, stupid error: in my service, the call to getEntry() must be done over proxy object rather than directly:
#Service
public class MyService implements ApplicationListener<ApplicationReadyEvent {
#Autowired
MyService self;
#Cacheable("entry")
public List<String> getEntry() {
System.out.println("getEntry called!");
return Arrays.asList("aaa", "bbb");
}
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
System.out.println("*** onApplicationEvent");
self.getEntry();
}
}

Configuring Camel for Spring with MINA 2

I want to configure Camel for Spring with MINA 2.
I did the following configuration code:
#Configuration
public class SpringConfiguration {
public static final String THREADPOOL_ID = "poolId";
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
context.addComponent("mina2", new Mina2Component());
}
#Override
public void afterApplicationStart(CamelContext arg0) {
}
};
}
}
But when I wrote the router code like below. But it is not working:
#Component
public class RouteConfiguration extends RouteBuilder {
#Value("${app.collectorStringInput}")
private String collectorStringInput;
#Value("${app.mapOutputQueue}")
private String mapOutputQueue;
private final SiemParserProcessor parserProcessor;
public RouteConfiguration(SiemParserProcessor parser) {
this.parserProcessor = parser;
}
#Override
public void configure() throws Exception {
from("mina2:udp://10.31.0.32:514?disconnectOnNoReply=false&sync=false").to("log:edu.accs.siem.collector?level=DEBUG");
}
}
However, I can see this lines in the log:
2018-06-30 11:37:14.270 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Route: route1 started and consuming from: mina2://udp://10.31.0.32:514?disconnectOnNoReply=false&sync=false
2018-06-30 11:37:14.270 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Total 1 routes, of which 1 are started
2018-06-30 11:37:14.271 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.185 seconds
It is working without using Spring. So I guess there is some configuration issue.
Can anybody tell me what I am missing?
PS: I checked out netty, but it seems not working even when not using Spring.
I got it working.
Actually, this was processing,
But somehow the logging wasn't displaying.

Testing Spring Boot Eureka Server 404

I'm trying to test authentication in my Spring Boot Eureka Server. To do so, I perform a GET on /eureka/apps. I get a 404 instead of 200.
#RunWith(SpringRunner.class)
#WebAppConfiguration
#SpringBootTest(classes = Application.class)
public class GlobalSecurityTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private FilterChainProxy springSecurityFilterChain;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(springSecurityFilterChain).build();
}
#Test
public void givenRoleDiscoveryClient_whenGetEureka_then200() throws Exception {
mockMvc.perform(get("/eureka/apps").header(HttpHeaders.AUTHORIZATION, TOKEN_DISCOVERY_CLIENT)
.andExpect(status().isOk());
}
}
Eureka starts correctly as the logs prove:
2018-04-12 23:07:39.308 INFO 80833 --- [ Thread-12] e.s.EurekaServerInitializerConfiguration : Started Eureka Server
2018-04-12 23:07:39.315 INFO 80833 --- [ main] GlobalSecurityTest : Started GlobalSecurityTest in 7.255 seconds (JVM running for 8.007)
...
2018-04-12 23:07:39.822 DEBUG 80833 --- [ main] o.s.security.web.FilterChainProxy : /eureka/apps/REGISTRY reached end of additional filter chain; proceeding with original chain
2018-04-12 23:07:39.831 DEBUG 80833 --- [ main] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl#0: Authentication: StateTokenAuthentication{principalTokenState=be.charliebravo.ibpt.qos3.commons.security.models.ClientState#50b624da, tokenStates={}}' stored to HttpSession: 'org.springframework.mock.web.MockHttpSession#50b4e7b2
2018-04-12 23:07:39.833 DEBUG 80833 --- [ main] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2018-04-12 23:07:39.833 DEBUG 80833 --- [ main] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
java.lang.AssertionError: Status
Expected :200
Actual :404
My security config:
#Configuration
public class WebSecurityConfig {
#Configuration
#Order(3)
public static class DiscoveryClientSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private StateTokenHttpSecurityConfigurer stateTokenHttpSecurityConfigurer;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/eureka/**").authorizeRequests()
.anyRequest().hasRole(Role.DISCOVERY_CLIENT.toString())
.and().exceptionHandling().authenticationEntryPoint(new Http401UnauthorizedEntryPoint());
stateTokenHttpSecurityConfigurer.configure(http);
}
}
}
The Eureka server works fine when I run the application instead of the test.
Don't use MockMvc, because it is limited to testing the web layer, but Eureka mappings aren't registered there. Instead, use TestRestTemplate.
Remove #WebAppConfiguration and add weEnvironment setting in #SpringBootTest
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Autowire TestRestTemplate and local server port
#Autowired
private TestRestTemplate restTemplate;
#LocalServerPort
private int localServerPort;
Perform the request
#Test
public void givenRoleDiscoveryClient_whenGetEurekaPage_then200() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, TOKEN_DISCOVERY_CLIENT);
HttpEntity entity = new HttpEntity<>(null, headers);
String endpoint = "https://localhost:" + localServerPort + "/eureka/apps";
ResponseEntity responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, entity, String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
And off you go.

Spring Boot 1.5.2 FreeMarker change from DEBUG mode to RETHROW mode

How do I change the FreeMarker "DEBUG" mode to the "RETHROW" mode in Spring Boot 1.5.2. I'm getting the following message in my browser when an exception occurs:
FreeMarker template error (DEBUG mode; use RETHROW in production!)
I've tried adding the following property to application.properties file:
spring.freemarker.template_exception_handler=rethrow
according to the following site: http://blog.64p.org/entry/2016/03/24/175906
but that didn't work.
Edit:
I saw there is a class called FreeMarkerProperties that has a class definition like the following:
#ConfigurationProperties(prefix = "spring.freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
I assume this class should be filled with all the properties that starts with "spring.freemarker"
It has a method called getSettings. I decided to see what is returns if I autowire FreeMarkerProperties into my CommandLineRunner.
I changed my class that implements CommandLineRunner to the following:
#Component
public class ApplicationLoader implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(ApplicationLoader.class);
...
#Autowired
FreeMarkerProperties properties;
#Override
#Transactional
public void run(String... strings) throws Exception {
StringBuilder sb = new StringBuilder();
for (String option : strings) {
sb.append(" ").append(option);
}
sb = sb.length() == 0 ? sb.append("No Options Specified") : sb;
logger.info(String.format("WAR launched with following options: %s", sb.toString()));
logger.info("FREEMARKER PROPERTIES");
for(String path : properties.getTemplateLoaderPath()) {
logger.info(path);
}
for(String setting : properties.getSettings().keySet()) {
logger.info("Freemarker: " + setting);
}
Which output the following:
2017-03-22 09:58:19.257 INFO 6635 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-03-22 09:58:19.292 INFO 6635 --- [ main] com.example.ApplicationLoader : WAR launched with following options: No Options Specified
2017-03-22 09:58:19.292 INFO 6635 --- [ main] com.example.ApplicationLoader : FREEMARKER PROPERTIES
2017-03-22 09:58:19.292 INFO 6635 --- [ main] com.example.ApplicationLoader : classpath:/templates/
2017-03-22 09:58:19.852 INFO 6635 --- [ main] com.example.DemoApplication : Started DemoApplication in 11.67 seconds (JVM running for 12.339)
So it seems like the FreemarkerProperties's getSettings method returns an empty list of settings. My application.properties:
# Spring Boot configuration.
# Uncomment below line to enable mobile device detection.
#spring.mobile.devicedelegatingviewresolver.enabled: true
spring.metrics.export.delay-millis=10000
spring.datasource.url=jdbc:postgresql://localhost:5432/**COMMENTED OUT***
spring.datasource.username=*
spring.datasource.password=*
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=create
server.session.timeout=1800
spring.freemarker.template_exception_handler=rethrow
Am I doing something wrong here? Why is the settings not populated in the FreemarkerProperties class?
In your application.properties try using
spring.freemarker.settings.template_exception_handler=rethrow
In the Spring Boot Module of one of my apps I'm loading the Freemarker Properties file with a #PropertySource annotation.
#SpringBootApplication
#PropertySource("classpath:/standalone.properties")
public class MailLauncher {
public static void main(String[] args) {
ApplicationContext ctx = new
AnnotationConfigApplicationContext("com.nixmash.blog.mail",
"com.nixmash.blog.jpa");
MailDemo demo = ctx.getBean(MailDemo.class);
demo.init();
((ConfigurableApplicationContext) ctx).close();
}
}
I'm not extending AbstractTemplateViewResolverProperties but rather using a config Bean
#Bean
public FreeMarkerViewResolver freemarkerViewResolver() {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setPrefix("");
resolver.setCache(false);
resolver.setOrder(3);
return resolver;
}
Here's the .properties file.
spring.freemarker.enabled=false
spring.freemarker.template-loader-path=classpath:/freemarker/
spring.freemarker.charset=UTF-8
spring.freemarker.cache=false
spring.freemarker.check-template-location=false
spring.freemarker.settings.locale=en_US
If your application includes multiple modules and application.properties files it could also be a matter of one module .properties file overriding your FreeMarker module .properties file. Renaming the FreeMarker module .properties file and using #PropertySource would expose the properties, in that case.

Resources