Spring Boot Microservices JUnit Test- Controller Test- JWT JwtGrantedAuthoritiesConverter Issue - java

I tried to implement some controller test with the usage of jwt in Spring Boot Microservices.
When I run the test method shown below, I got this error
java.lang.NoClassDefFoundError: org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter
Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter
Here is the code snippets shown below.
#Test
public void test_WhenPlaceOrderWithWrongAccess_thenThrow403() throws Exception {
OrderRequest orderRequest = getMockOrderRequest();
MvcResult mvcResult
= mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder")
.with(jwt().authorities(new SimpleGrantedAuthority("ADMIN"))) // HERE IS THE ERROR LINE
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(orderRequest))
).andExpect(MockMvcResultMatchers.status().isForbidden())
.andReturn();
}
Even if I added spring-security-oauth2-resource-server dependency in pom.xml of order service, It didn't help me fix the issue.
Here are the issue shown below after adding spring-security-oauth2-resource-server dependency in pom.xml of order service.
java.lang.NoClassDefFoundError: org/springframework/security/oauth2/jwt/Jwt$Builder
Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.jwt.Jwt$Builder
How can I fix the issue?
Here is the link of example : Link

Probably, you only need the dependencies
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
but not spring-security-oauth2-resource-server

Double check that spring-security-oauth2-resource-server dependency is correctly declared: scope compile (must be there at runtime and test) and version 5.2 or above (JwtGrantedAuthoritiesConverter was not there before). You might pull it as transitive dependency of spring-boot-starter-oauth2-resource-server. So basically, check that:
spring-boot-starter-oauth2-resource-server is declared dependency for each resource-server module
security-configuration is there for each resource-server module
JwtDecoder is mocked for each unit-test (#WebMvcTest) and integration test with mocked authentication (#SpringBootTest with #AutoConfigureMockMvc)
Sorry to tell you that, but your code is a mess:
no parent pom to manage modules versions (had to manually mvn install modules in the right order.
you test security rules in modules with no security configuration
some resource-servers do not pull spring-boot-starter-oauth2-resource-server (products service for instance)
you write integration tests (#SpringBootTest) to unit test controllers (should be #WebMvcTest with #MockBean dependencies)
have to run configuration server for test to run (you should configure unit-tests to run in isolation from the rest of the world, starting with external services like cloud-config)
...
Cleanup your mess before asking us to look into your code.
For now, all I can tell you is to follow those tutorials. It covers in details resource-servers security configuration and testing. It also demoes how to use annotations in place of jwt() MockMvc post-processor. Annotations are more readable to me and also enable to setup security context when testing secured services:
#WithMockJwtAuth("ROLE_USER")
#Test
public void test_WhenPlaceOrder_DoPayment_Success() throws Exception {
OrderRequest orderRequest = getMockOrderRequest();
MvcResult mvcResult
= mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(orderRequest))
).andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
...
}

Related

Spring Framework upgrade 5.X leads to error class file for org.springframework.context.SmartLifecycle not found

I have been upgrading one of the app to spring framwork 5.X from 3.X, one of the problem I am failing to resolve it error is following - this makes a use of spring-jms
cannot access org.springframework.context.SmartLifecycle [ERROR]
class file for org.springframework.context.SmartLifecycle not found
I can see last version the exact same code works with Spring 4.3.9 (last of 4.X release) and breaks with Spring 5.0.0 (First of 5.X releases)
I don't see my code exposing the class SmartLifecycle but I have suspicion that DefaultMessageListenerContainer instance is at a fault.
public class Factory {
private DefaultMessageListenerContainer testListnerService;
public void start() {
final TestMessageListener testMessageListener = new TestMessageListener();
testListnerService = new DefaultMessageListenerContainer(); <-- This is where compilation breaks
testListnerService.setMessageListener(testMessageListener);
testListnerService.setSessionTransacted(true);
testListnerService.afterPropertiesSet();
}
I have created minimal example here https://github.com/milandesai47/com.jms.test/blob/master/pom.xml#L33
Am I missing anything obvious in terms of spring dependencies?
You need to add the following dependency to your pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>

How to inject dependecies using Governator within TestNG test cases?

I'm working on a test automation framework which use TestNG. I decided to use Dependency Injection pattern in order to implement more readable, reusable page objects and tests.
I've chosen Google Guice due to TestNG provides built-in support to inject test objects with Guice Modules. I only had to specify my Guice Modules as you can see at next code snippet:
#Guice(modules = CommModule.class)
public class CommunicationTest {
#Inject
private Communication comms;
#Test
public void testSendMessage() {
Assertions.assertThat(comms.sendMessage("Hello World!")).isTrue();
}
}
So far so good, although I'm going to need more advance DI features such as:
Lifecycle management
Configuration to field mapping
Generic binding annotations
Therefore, I'd like to use Netflix/Governator since it enhance Google Guice with these features. In order to trigger Governator features I must create the Injector through it instead of TestNG. e.g:
Injector injector = LifecycleInjector.builder()
.withModules(CommModules.class).build().createInjector();
And I'd like to do it mostly transparent as possible like TestNG does it.
I would like to know if:
Is it possible to provide my own Injector instance to TestNG in order to reuse #Guice annotation approach ?
Do you know any library for integrating Governator with TestNG ?
You can find in here what I've done so far.
This was not possible until now. I have fixed this in the latest snapshot version of TestNG. It should be available in the upcoming version of TestNG (Any version greater than 7.0.0)
The issue that I created to track this : https://github.com/cbeust/testng/issues/2199
In a nutshell, you can do the following :
Implement the interface org.testng.IInjectorFactory
Plugin the fully qualified class name of the newly created implementation via the command line argument -dependencyinjectorfactory
Since Allow user to provide DI Injector TestNG feature is going to be present in versions greater than 7.0.0. I implemented a solution using TestNG version 7.0.0 listeners.
Firstly, I created a module called autopilot-testng-runner with the following dependencies:
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.governator</groupId>
<artifactId>governator</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
</dependencies>
This module contains the artifacts described at next:
#AutopilotTest: Custom annotation for declaring which Guice modules must be used for creating the Injector with LifecycleInjector.builder(). I couldn't reuse #Guice annotation due to TestNG also will create its Injector and declared dependencies will be created twice.
AutopilotSuiteListener: Implementation of ISuiteListener for creating the parent Injector, Governator's LifecycleManager instance and bind configuration properties before Suite starts. Therefore each Suite is going to have a parent Injector built with Governator and a life-cycle manager.
AutopilotTestListener: ITestListener implementation in charge of injecting dependencies in the running test case.
META-INF/services/org.testng.ITestNGListener: Service provider configuration file containing the fully qualified names of both ITestNGListener implementations.
Then, I added autopilot-testng-runner as a maven dependency in my project
<dependency>
<groupId>com.github.eljaiek.playground</groupId>
<artifactId>autopilot-testng-runner</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
And finally, I replaced #Guice annotation with #AutopilotTest
#AutopilotTest(modules = CommModule.class)
public class CommunicationTest {
#Inject
private Communication comms;
#Test
public void testSendMessage() {
Assertions.assertThat(comms.sendMessage("Hello World!")).isTrue();
}
}

Caused by: java.lang.NoSuchMethodError: org.springframework.data.mongodb.core.MongoTemplate.<init>(Lcom/mongodb/Mongo;Ljava/lang/String;)V

While trying to run Spring-boot application (v2.1.0) getting below error:
Description:
An attempt was made to call the method org.springframework.data.mongodb.core.MongoTemplate.(Lcom/mongodb/Mongo;Ljava/lang/String;)V but it does not exist. Its class, org.springframework.data.mongodb.core.MongoTemplate, is available from the following locations:
file:/C:/Users/npatil/.m2/repository/org/springframework/data/spring-data-mongodb/2.1.2.RELEASE/spring-data-mongodb-2.1.2.RELEASE.jar!/org/springframework/data/mongodb/core/MongoTemplate.class
It was loaded from the following location:
file:/C:/Users/npatil/.m2/repository/org/springframework/data/spring-data-mongodb/2.1.2.RELEASE/spring-data-mongodb-2.1.2.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.data.mongodb.core.MongoTemplate
Below is a snnipet from my pom:
<dependencies>
.
.
<dependency>
<groupId>com.github.mongobee</groupId>
<artifactId>mongobee</artifactId>
<version>0.13</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
.
.
</dependencies>
Version of some of the jars that could help are:
spring-data-mongodb : 2.1.2.RELEASE
spring-web : 5.1.2.RELEASE
mongo-java-driver : 3.8.2.RELEASE
Deleted .m2 and did mvn clean install, but even that did not resolve the issue. Any help would be greatly appreciated.
Looks like jar is corrupted or missing,
check all spring related jar are 4.x or higher version
if that doent work then:
Mongobee depends on Spring 4.x jars which may conflicts with Spring boot 2.x
try the below way
#Bean
public Mongobee mongobee(){
Mongobee mongobee = new Mongobee("mongodb://localhost:27017/seed");
mongobee.setChangeLogsScanPackage(InitialData.class.getPackageName());
mongobee.setMongoTemplate(template);
return mongobee;
}
You need change Mongobee by Mongock if you use Springboot 2. The syntax is almost the same because the Mongock project is the continuation of the Mongobee project.
Springboot:
#Bean
public SpringBootMongock mongock(ApplicationContext springContext, MongoClient mongoClient) {
return (SpringBootMongock) new SpringBootMongockBuilder(mongoClient, "yourDbName", "com.package.to.be.scanned.for.changesets")
.setApplicationContext(springContext)
.setLockQuickConfig()
.build();
}
Spring:
#Bean
public SpringMongock mongock() {
MongoClient mongoclient = new MongoClient(new MongoClientURI("yourDbName", yourMongoClientBuilder));
return new SpringMongockBuilder(mongoclient, "yourDbName", "com.package.to.be.scanned.for.changesets")
.setLockQuickConfig()
.build();
}

Seems my Junit test runs in runtime, the datasource missing

I used a H2 database in unit test, use java configuration:
#Configuration #EnableJpaRepositories(basePackageClasses = AdvertisementRepository.class) public class EmbeddedDatabaseConfig {
/**
* Creates DataSource for an embedded Database (H2).
*/
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
and set scope to test in pom.xml:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.184</version>
<scope>test</scope>
</dependency>
It's successfully build and in JUnit test, but when I run it on server, it reports error:
java.lang.ClassNotFoundException: org.h2.Driver
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1274)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1108)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
at org.springframework.jdbc.datasource.embedded.H2EmbeddedDatabaseConfigurer.getInstance(H2EmbeddedDatabaseConfigurer.java:48)
at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseConfigurerFactory.getConfigurer(EmbeddedDatabaseConfigurerFactory.java:39)
... 51 more
I'm confused: the junit test won't run in runtime, right? why my code automatically read the java config class, and not found driver class?
While I will not be able to point out the exact issue, the problem you are facing is that org.h2.Driver is not available while trying to run the test. As mentioned in one of the comments make sure that jar is available in the classpath.
PS: If you are using an Ant build and trying to run test before deploying to production, make sure the jar is available before ANT runs your tests.

Problems with Testing Spring Boot Application with Multi Maven Project Setup

I am currently running into some problems with spring boot and multi maven project structure. I am using Spring Boot 4.3.1.
My project structure looks as follows:
parent
-- pom.xml
-- application
-- pom.xml
-- src
-- main
-- java
-- Application.java (annotated with #SpringBootApplication)
-- test
-- java
-- MyApplicationTest.java (annotated with #SpringBootTest)
-- library
-- pom.xml
-- src
-- main
-- java (...)
-- test
-- java
-- MyLibraryTest.java (annotated with #SpringBootTest)
application module has a dependency on library.
MyApplicationTest works perfectly fine, but running MyLibraryTest instead, I fail with the following error:
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test at org.springframework.util.Assert.state(Assert.java:392)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.getOr FindConfigurationClasses(SpringBootTestContextBootstrapper.java:173)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.processMergedContextConfiguration(SpringBootTestContextBootstrapper.java:133)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:409)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:305)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:112)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:78)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:120)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
My first guess is that library needs a dependency on application, but this causes a cycle.
Is there any solution to that problem?
How can I structure my application correctly?
thanks a lot for suggestions.
MyLibraryTest looks as follow:
#RunWith(SpringRunner.class)
#SpringBootTest
#Transactional
public class MyLibraryTest {
#Autowired
private MyService service;
#Test
public void testMyService_Save() {...}
}
You need to make sure that the library module's pom.xml includes -
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
which is required for the module to use the #SpringBootTest annotation. You might already be using the same in your app module but is not included in the library module.
Well post the Edit, found the question to be possibly a duplicate of Unable to find a #SpringBootConfiguration when doing a JpaTest
Also quoting from Thomas's answer from the same thread, here
The thing about #DataJpaTest and a few other annotations is that they
look for a #SpringBootConfiguration annotation in the current package,
and if they cannot find it there, they traverse the package hierarchy
until they find it.
For example, if the fully qualified name for your test class was
com.example.test.JpaTest and the one for your application was
com.example.Application, then your test class would be able to find
the #SpringBootApplication (and therein, the
#SpringBootConfiguration).
If the application resided in a different branch of the package
hierarchy, however, like com.example.application.Application, it would
not find it.
which seems to be the case for you, where you are trying to test an application in a different module itself. Hence the error that you see.

Categories