Assertion error for testing Junit with reactive WebTestClient Status Expected :201 Actual :404 - reactive-programming

#ExtendWith(SpringExtension.class)
#WebFluxTest(controllers = EventsControllerTest.class)
class EventsControllerTest {
#MockBean
UserRepo repo;
#Autowired
private WebTestClient webClient;
#Test
void testAssignUserRoles() {
UserInfo user = new UserInfo();
user.setId(Long.valueOf(1));
user.setFirstname("Test");
user.setLastname("Test2");
user.setActiveuser(true);
user.setEmailid("tet#test.com");
user.setRolename("test");
user.setUserpassword("test");
Mockito.when(repo.save(user)).thenReturn(Mono.just(user));
webClient.post().uri("/assignRoles").contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(user)).exchange().expectStatus().isCreated();
Mockito.verify(repo, times(1)).save(user);
}
Controller
#RestController
public class EventsController {
#Autowired
UserInfoRepository userInfoRepository;
#PostMapping(value = "/saveRole")
public Mono<UserInfo> assignUserRoles(#RequestBody UserInfo userInfo) {
return userInfoRepository.save(userInfo).log();
}

Access URI should match value attribute of #PostMapping: saveRole.

Related

Spring boot test : How to test a controller with jpa data

I want to test a controller with jpa data.
How can i do it?
I have this controller :
#RestController
#RequestMapping("/api")
public class AuthenticateController {
#Autowired private AuthenticationManager authenticationManager;
#Autowired private ClientRepository client;
#Autowired private JwtUtil jwt;
#Autowired private UserDetailsService details;
#PostMapping("/authenticate") public ResponseEntity<?> createAuthenticationToken(#RequestBody AuthenticationRequest authenticate) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticate.getIdentification(), authenticate.getPassword()));
}
catch (BadCredentialsException e) { throw new Exception("Incorrect username or password", e); }
final UserDetails userDetails = details.loadUser(authenticate.getIdentification());
final String jwt = this.jwt.generateToken(userDetails);
final String identification = userDetails.getIdentification();
Client c = client.findByUsernameOrEmailOrPhone(identification, identification, identification).orElseThrow();
return ResponseEntity.ok(new AuthenticationResponse(jwt, c));
}
}
and this jpa data
public interface ClientRepository extends JpaRepository<Client, Integer> {
}

Test with Mockito for database delete method

I want to test my delete method in PersonDao class.
public class PersonDao {
private EntityManager em;
Person person1 = new Person(111, "Klara", "Bamp", "qwerty123");
public PersonDao() {
}
public PersonDao(EntityManager em) {
this.em = em;
}
public void delete(Person p) {
em.remove(p);
}
}
That's my test class:
public class UnitTests {
#Mock
EntityManager entityManagerMock;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void deletePersonTestWithMockito() {
//ARRANGE
PersonDao personDao = new PersonDao(entityManagerMock);
when(entityManagerMock.find(Person.class, person1.getId())).thenReturn(person1);
//ACT
personDao.delete(person1);
//ASSERT
verify(entityManagerMock, times(1)).remove(person1);
assertNull(entityManagerMock.find(Person.class, person1.getId()));
}
I realize, that personDao.delete(person1) does nothing, bcs I did not specify what entityManagerMock.remove should do. I tried to specify it as
when(entityManagerMock.remove(person1)).thenCallRealMethod();, but I received an error Required type: T; Provided: void

#TransactionalEventListener annotated method not invoked in #Transactional test

I'm trying to implement domain event publishing from an entity by following the examples mentioned on the post below:
Example for #DomainEvents and #AfterDomainEventsPublication
However I haven't managed to have Spring calling my method annotated with #TransactionalEventListener.
See below the entity, service, event listener and test code:
#Entity
public class Book extends AbstractAggregateRoot<Book>
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(unique = true)
private String isbn;
#Column
private String name;
public Book(String isbn, String name)
{
this.isbn = isbn;
this.name = name;
}
public void purchase()
{
registerEvent(new BookPurchasedEvent(id));
}
// getters omitted for brevity
}
Service:
#Service
#Transactional
public class BookService
{
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository)
{
this.bookRepository = bookRepository;
}
public void purchaseBook(Integer bookId)
{
Book book = bookRepository.findById(bookId)
.orElseThrow(NoSuchElementException::new);
book.purchase();
bookRepository.save(book);
}
}
Listener:
#Service
public class EventListener
{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#TransactionalEventListener
public void handleEvent(BookPurchasedEvent event)
{
logger.info("Received event {}", event);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#Transactional
public class BookEventsTest
{
#Autowired
private BookService bookService;
#Autowired
private EntityManager entityManager;
#Test
public void test()
{
Book book = new Book("abcd-efgh", "El Quijote");
book = entityManager.merge(book);
bookService.purchaseBook(book.getId());
}
}
The log message from the listener is not logged. It works though when deployed as a REST service and invoked e.g. via Postman
Got it. Since my test is annotated with #Transactional, the transaction wrapping the test method will be rolled back. Therefore the method annotated with #TransactionalEventListener won't be called, since by default it triggers at the phase TransactionPhase.AFTER_COMMIT (and I'm not interested in having it called unless the transaction is successful). So the working version of the test looks as follows:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BookEventsTest
{
#Autowired
private BookService bookService;
#Autowired
private BookRepository bookRepository;
#MockBean
private EventListener eventListener;
private Book book;
#Before
public void init() {
book = bookRepository.save(new Book("abcd-efgh", "El Quijote"));
}
#After
public void clean() {
bookRepository.deleteAll();
}
#Test
public void testService()
{
bookService.purchaseBook(book.getId());
then(eventListener)
.should()
.handleEvent(any(BookPurchasedEvent.class));
}
}

How to get oAuth2 access token when user call signup rest API in springboot?

currently I am working on Springboot security, its quite new for me. I followed youtube video tutorial Video
I am getting oauth2 access_token successfully when I use bellow code snippet:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, UserService service) throws Exception {
//Setup a default user if db is empty
User students = new User("stu1", "user", "user", "abc#gmail.com", "1234567890", "12th", "dwarka sec-12",
0, 0 , "may/29/2017", "", Arrays.asList(new Role("USER"), new Role("ACTUATOR")));
if (repository.count()==0){
service.save(students);
}
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
}
And Controller Class is:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/mathify/signup")
public User register(#RequestBody User user){
return userService.doSignup(user);
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
With above code snippet I can get access_token(/oauth/token), and I can also call other controller class private APIs without any issue.
but there is a problem with above code. What? In above code snippet User is hard coded, but when I want to get access_token at the time of user signup it's giving an exception.
2017-06-18 11:04:05.689 ERROR 8492 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object] with root cause
java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:196) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:133) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.apply(AuthenticationManagerBuilder.java:290) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.userDetailsService(AuthenticationManagerBuilder.java:187) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.techiesandeep.mathify.controller.LoginController.register(LoginController.java:40) ~[classes/:na]
for achieving above described feature I did some changes in my Application and Controller
Application Class is As:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
}
and Controller class is as:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#Autowired
AuthenticationManagerBuilder builder;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private UserRepository repository;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/user/signup")
public User register(#RequestBody User user) throws Exception {
User u = userService.doSignup(user);
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
return u;
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
Any help would be appreciable.thanks
You can call another POST request to get access token.
I am not sure it's the best way, but worked fine with me.
Example code snip inside Signup Request mapping:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", auth_header);
/*auth_header should be Autorization header value that captured from signup request, which is generated by Basic Auth with clientID and secret, for example, "Basic bXktdHJ1c3RlZC1jbGllbnQ6c2VjcmV0" */
HttpEntity<String> entity = new HttpEntity<String>("",headers);
String authURL = "http://localhost:8080/oauth/token?grant_type=password&username=yourusername&password=yourpassword";
ResponseEntity<String> response = restTemplate.postForEntity(authURL, entity, String.class);
System.out.println(response.getBody());

Unreachable security context using Feign RequestInterceptor

The goal is to attach some data from security context using RequestInterceptor, but the problem, that the calling SecurityContextHolder.getContext().getAuthentication() always returns null even though it is not null (I am sure 100%).
As I understand that's because the Interceptor is created and is being run in other thread.
How could I solve this problem and get actual data from security context?
My service:
#FeignClient(value = "api", configuration = { FeignConfig.class })
public interface DocumentService {
#RequestMapping(value = "/list", method = RequestMethod.GET)
DocumentListOperation list();
}
My FeignConfig class:
#Bean
public RequestInterceptor requestInterceptor() {
return new HeaderInterceptor(userService);
}
public class HeaderInterceptor implements RequestInterceptor {
private UserService userService;
public HeaderInterceptor(UserService userService) {
this.userService = userService;
}
#Override
public void apply(RequestTemplate requestTemplate) {
Authentication a = SecurityContextHolder.getContext().getAuthentication()
requestTemplate.header("authentication", a.toString());
}
}
I managed to figure it out, thanks to the article I found here
Firstly you need to initiliaze HystrixRequestContext HystrixRequestContext.initializeContext();.
You have to create your own Context in which you will store information you need to pass to Hystrix child threads.
Here is example:
public class UserHystrixRequestContext {
private static final HystrixRequestVariableDefault<User> userContextVariable = new HystrixRequestVariableDefault<>();
private UserHystrixRequestContext() {}
public static HystrixRequestVariableDefault<User> getInstance() {
return userContextVariable;
}
}
You have to register new concurrency strategy that would wrap Callable interface
#Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
public CustomHystrixConcurrencyStrategy() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}
#Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
return new HystrixContextWrapper<T>(callable);
}
public static class HystrixContextWrapper<V> implements Callable<V> {
private HystrixRequestContext hystrixRequestContext;
private Callable<V> delegate;
public HystrixContextWrapper(Callable<V> delegate) {
this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
this.delegate = delegate;
}
#Override
public V call() throws Exception {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
return this.delegate.call();
} finally {
HystrixRequestContext.setContextOnCurrentThread(existingState);
}
}
}
}
So before calling Callable object we set new thread's Context to parent's context.
After that is done you should be able to access your new defined context inside Hystrix child threads
User = UserHystrixRequestContext.getInstance().get();
Hope that will help someone.