Spring Boot with Embedded Mongo : Cannot assign requested address: JVM_Bind - spring

I am trying to setup a JUnit test for a Spring Boot with embedded Mongo & Kafka :-
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
classes = {AccountingApplication.class})
#DataMongoTest
public class BaseEmbeddedTest {
#ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true);
#Autowired
private MongoTemplate mongoTemplate;
#Test
public void emptyTest(){
}
}
src/test/resources/application.yml :-
spring:
data:
mongodb:
port: 0
kafka:
bootstrap-servers: ${spring.embedded.kafka.brokers}
PROBLEM
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flapdoodle.embed.mongo.config.IMongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.net.BindException: Cannot assign requested address: JVM_Bind
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 140 more
Caused by: java.net.BindException: Cannot assign requested address: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:106)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:190)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at de.flapdoodle.embed.process.runtime.Network.getFreeServerPort(Network.java:80)
at org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.embeddedMongoConfiguration(EmbeddedMongoAutoConfiguration.java:147)
What am I doing wrong here ?
Version:-
dependencyManagementPluginVersion = '1.0.3.RELEASE'
springBootVersion = '1.5.6.RELEASE'
springCloudVersion = 'Dalston.SR2'
projectVersion = '0.0.1-SNAPSHOT'
javaVersion = 1.8
kotlinVersion = '1.1.4'

This annotation: #DataMongoTest causes Spring Boot to create an embedded Mongo instance. The exception messages tells us that the embedded Mongo instance cannot start because there is already a process running on the port it is trying to run on.
The embedded Mongo instance is configured by EmbeddedMongoAutoConfiguration and the strategy applied by Spring Boot - for port allocation - is as follows:
if configured Mongo port > 0 then
use the configured port
else
assign a random port
end
So, I suspect that your test context is configured with a non zero value for spring.data.mongodb.port. I know you posted your application.yml which implies that you are - correctly - assigning a zero value to spring.data.mongodb.port but if you put a breakpoint inside the EmbeddedMongoAutoConfiguration constructor and peek inside the properties parameter I think you'll see that the actual value in use by that configuration class is not zero. If the port value passed to EmbeddedMongoAutoConfiguration is actually zero but you are still getting the JVM_Bind error then that implies that this call: Network.getFreeServerPort(this.getHost()) is not returning a free port and that seems unlikely.
In order to fix this issue: as long as you configure your test context with spring.data.mongodb.port=0 then the embedded Mongo instance will be assigned a random port and this random port will be made known to other aspects of your Spring context (such as your MongoTemplate) which need to talk to that Mongo instance.

Related

Wildfly GraphQL Smallrye #Routingcontext

I have setup a Wildfly 27 server with GraphQL Featurepack.
I need to access the Request Headers to fetch a bearertoken.
I find no good doc on how to do this.
My assumption is that i should inject the RoutingContext like this.
#GraphQLApi
#ApplicationScoped
public class FilmResource {
#Inject
GalaxyService service;
#Inject
RoutingContext routingContext;
#Query("allFilms")
#Description("Get all Films from a galaxy far far away")
public List<Film> getAllFilms() {
return service.getAllFilms();
}
}
However this fails runtime with
ERROR [controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "cms-graph-ql-1.1.0-SNAPSHOT.war")]) - failure description:
{"WFLYCTL0080: Failed services" => {"jboss.deployment.unit."cms-graph-ql-1.1.0-SNAPSHOT.war".WeldStartService" => "Failed to start service
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type RoutingContext with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject com.scanreco.cms.microprofile.graphql.FilmResource.routingContext
at com.scanreco.cms.microprofile.graphql.FilmResource.routingContext(FilmResource.java:0)
I would be greatful for any help.
So i figured this one out.
Since i am using WF and not Quarkus i am forced to fetch the request headers via #Webfilter.
(Vert.x is not at all used for HTTP in my stack).
This is a minor inconvenince but quite alright.
#WebFilter(servletNames = {"SmallRyeGraphQLExecutionServlet"},
filterName = "CMS Azure AD Filter",
description = "Filter all ServletCalls for Azure AD Bearer token",
dispatcherTypes = {DispatcherType.REQUEST})
#RequestScoped
public class CmsGraphQlServletAzureAdFilter implements Filter {
The name of the executionservlet was found in their gitRepo.

No qualifying bean of type 'org.springframework.cloud.stream.binder.test.OutputDestination' available

I am trying to use spring cloud contracts for messaging.
I have a producer and a consumer who is publishing and consuming from rabbitmq.
they are working fine when I run both these spring boot applications.
however, when I try to mvn clean install , generated ContractVerifierTest fails with the error
2022-01-18 14:35:55.982 ERROR 62575 --- [ main] s.StreamOutputDestinationMessageReceiver : Exception occurred while trying to read a message from a channel with name [fraud]
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.stream.binder.test.OutputDestination' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) ~[spring-beans-5.3.14.jar:5.3.14]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[spring-beans-5.3.14.jar:5.3.14]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:43) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:55) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:30) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamStubMessages.receive(StreamStubMessages.java:59) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamStubMessages.receive(StreamStubMessages.java:31) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging.receive(ContractVerifierMessaging.java:65) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
I have spring-cloud-stream, spring-cloud-stream-binder-rabbit, spring-cloud-starter-contract-verifier, spring-cloud-stream:test-binder dependencies in my pom as well.
My spring boot application class is configured like this
#SpringBootApplication
#EnableBinding(Source.class)
public class ProducerApplication {
It is sending the message to the destination topic from tests as well. However, it fails to read it
#Test
public void validate_contract_name() throws Exception {
// when:
trigger(); // this happens fine
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("destination-name",
contract(this, "contract_name.yml")); // THIS FAILS
assertThat(response).isNotNull();
I have annotated my base test class with these
#SpringBootTest(classes = ProducerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
#ExtendWith(SpringExtension.class)
#AutoConfigureMessageVerifier
I have verified that OutputDestination class is available in the classpath.
I have org.springframework.cloud:spring-cloud-stream:test-jar:test-binder:3.2.1:test in the classpath.
spring-boot-starter-parent version is 2.6.2. spring cloud version is 2021.0.0
I have configured spring-cloud-contract-maven-plugin version 3.1.0 to use JUNIT5

Spring Test Wants To Connect to Database

I am trying to write some tests for my application and encountered following problem:
I defined a application-test.yml with folling content:
server:
port: 8085
spring:
security:
oauth2:
resourceserver:
jwt:
# change localhost:8081 with container name
issuer-uri: http://localhost:8081/auth/realms/drivingschool
jwk-set-uri: http://localhost:8081/auth/realms/drivingschool/protocol/openid-connect/certs
keycloak:
realm: drivingschool
auth-server-url: http://localhost:8081/auth
ssl-required: external
resource: client-interface
use-resource-role-mappings: true
credentials:
secret: xxx
bearer-only: true
My test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class StudentControllerTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private StudentService service;
#MockBean
private StudentRepository repository;
#Test
public void contextLoads(){}
//more tests
}
the test all pass green BUT in the log i can see, that my app tries to connect to a database configured in my (basic) application.yml.
ava.sql.SQLNonTransientConnectionException: Could not connect to address=(host=localhost)(port=9005)(type=master) : Socket fail to connect to host:localhost, port:9005. Verbindungsaufbau abgelehnt (Connection refused)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73) ~[mariadb-java-client-2.6.1.jar:na]
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:192) ~[mariadb-java-client-2.6.1.jar:na]
jpa:
database-platform: org.hibernate.dialect.MariaDBDialect
hibernate:
use-new-id-generator-mappings: false
ddl-auto: create
datasource:
url: jdbc:mariadb://localhost:9005/waterloo
username: waterloo
password: xxx
driver-class-name: org.mariadb.jdbc.Driver
when creating a application-prod.yml and moving all content from application.yml to application-prod.yml it tells me I have to configure a datasource URL
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
I have the following questions:
Do the application.yml files get layered (*-test.yml settings on top of application.yml)?
Why does Spring try to build a connection to my database when I am not setting a datasource on my application-test.yml AND mocking the repository on the test?
Is it normal that Spring trys to establish a connection at this part?
3.1) If not: How to i prevent it from doing so?
Thanks and kind regards!
Failed to determine a suitable driver class
You need to add mariadb driver dependency to your gradle or maven file.
https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/2.6.2
Make sure that dependency scope is suitable for test
If you already have and its still not working try to clean and rebuild your project.
Your Questions:
Do the application.yml files get layered (*-test.yml settings on top
of application.yml)?
If you add #ActiveProfiles("test") to you TestClass Spring will try to find an application-test.yml and overrrides application.yml properties with the given properties
Why does Spring try to build a connection to my database when I am not
setting a datasource on my application-test.yml AND mocking the
repository on the test?
Thats the magic of spring boot - it has default configurations for everything. You just need to set the Datasource properties and it will create the bean by itself.
Is it normal that Spring trys to establish a connection at this part? 3.1) If not: How to i prevent it from doing so?
You are starting the whole spring context with #SpringBootTest Annotation.
So it will startup all Repositories and try to establish connection to your database. If you don't want spring to startup the database layer you can just use #WebMvcTest
eg:
#RunWith(SpringRunner.class)
#WebMvcTest
#ActiveProfiles("test")
public class StudentControllerTests {
#Autowired
private MockMvc mockMvc;
#Test
public void contextLoads(){}
//more tests
}
Check this out: https://spring.io/guides/gs/testing-web/
If you need to startup the whole SpringContext you can also disable Spring Data AutoConfiguration with:
#SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
Check this out: https://www.baeldung.com/spring-data-disable-auto-config
missed following annotation:
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})

Unable to call Mapper.xml file by using junit testing for the application developed using Mybatis+Springboot

I'm very new to junit testing. How to write junit test real database call from mybatis.xml file.
Please find the below code.
#RunWith(SpringRunner.class)
//#MybatisTest
#SpringBootTest
public class HotelMapperTest {
#Autowired
private HotelMapper hotelMapper;
#Test
public void selectByCityIdTest() {
Hotel hotel = hotelMapper.selectByCityId(1);
assertThat(hotel.getName()).isEqualTo("Conrad Treasury Place");
assertThat(hotel.getAddress()).isEqualTo("William & George Streets");
assertThat(hotel.getZip()).isEqualTo("4001");
}
when i run the junit testing i'm getting below exception:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
Herer my question is how we'll test the real database, When enable the #MybatisTest it's looking for datasource, already we specified all properties in applicaiton.properties. In this time i'm getting below exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource':
You can config mybatis mapper location in spring configuration file (such as application.yml).
mybatis configuration:
mybatis:
mapper-locations:
- classpath*:mapper/*.xml

Failed to start bean 'org.springframework.amqp.rabbit.config.internalRabbitListenerEndpointRegistry'

I have a simple spring-boot application with a rabbit sender and a receiver. I want to write some receiver tests where I am running a rabbitmq docker instance as Junit Class Rule (RabbitContainerRule)and then sending a message using rabbitTemplate and the test verifies if the receiver receives the same message. But I am getting the following exception:
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.amqp.rabbit.config.internalRabbitListenerEndpointRegistry'; nested exception is org.springframework.amqp.AmqpIllegalStateException: Fatal exception on listener startup
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
Caused by: org.springframework.amqp.rabbit.listener.QueuesNotAvailableException: Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:599)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1424)
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'my-message-queue' in vhost '/', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
If I create the queue manually(by stopping at a breakpoint) in the docker instance using admin console, my test passes.
Also, if I test it manually using the docker rabbit instance, my spring boot application creates queue successfully. So what is causing it to not create in the test?
I am using spring-amqp 1.7.4 RELEASE
Receiver code:
#RabbitListener(bindings = #QueueBinding(
value = #Queue(value = "my-message-queue", durable = "true",
arguments = {
#Argument(name = "x-dead-letter-exchange", value = "my-message-exchange-dead-letter"),
#Argument(name = "x-dead-letter-routing-key", value = "my-message-queue")}),
exchange = #Exchange(value = "my-message-exchange", type = "topic", durable = "true"),
key = "my-message-rk")
)
public void handleMessage(MyMessage message) {
MESSAGE_LOG.info("Receiving message: " + message);
}
Also I am not creating any #Bean for my-message-queue in Configurations and rely on #RabbitListener to create one for me. But I am creating ConnectionFactory, RabbitTemplate and SimpleRabbitListenerContainerFactory beans in my config.
The #EnableRabbit is necessary on some #Configuration class to let your application context to parse #RabbitListener.
To let the application to create queues and exchanges and bindings between them automatically, and the RabbitAdmin bean must be present in the configuration.
See Reference Manual for more information: https://docs.spring.io/spring-amqp/docs/2.0.0.RELEASE/reference/html/
The class where you are building your queues should be annotated with #Configuration annotation, otherwise, spring will not be able to create the queues at the time of start up

Resources