'mockMvc can't save session in redis repository

I am new to redis. Currently, I am trying to apply it to SpringScurity. There is a lot of information on the internet on how to manually test and go directly to redis to check if the spring:session:sessions key exists. The problem arose when I was trying to create a test code that runs automatically.

    @GetMapping("/sessionid")
    @ResponseBody
    public String getSessionId(HttpSession httpSession) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        List<SessionInformation> allSessions = springSessionBackedSessionRegistry.getAllSessions(authentication.getPrincipal(), false);
        
        log.info("========= redis Session test controller==========");
        if(allSessions.isEmpty()) {
            log.info("redis session is empty!");
        }   
        
        //it works on application connection
        //but do not work on test
        for(SessionInformation sessionInfo : allSessions) {
            log.info("session id saved in redis : {}", sessionInfo.getSessionId());
        }
        

        return httpSession.getId();
    }
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {

    String username() default "mockUser";
    String password() default "mock1234";
    String email() default "[email protected]";
    Role[] roles() default {Role.ORDERER}; 
}

@Slf4j
@SpringBootTest
public class RedisSessionTest {
    
    @Autowired
    private SpringSessionBackedSessionRegistry<? extends Session> springSessionBackedSessionRegistry;
    
    @Autowired
    private WebApplicationContext applicationContext;
    
    private MockMvc mock;

    
    @BeforeEach
    void beforeEach() {
        mock = MockMvcBuilders.webAppContextSetup(applicationContext).build();
    }
    
    @Test
    @WithMockCustomUser
    @DisplayName("redis session have to have session loged in by mockUser")
    void redisSessionTest() throws Exception {
        
        mock.perform(get("/sessionid")).andExpect(status().isOk());
        
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        UserDetails userDetails = (UserDetails)principal;
        log.info("==============Redis Session test=============");
        log.info("user name in Security Context : {}",userDetails.getUsername());
        
        //not work in this test
        //the console result is always "redis session is empty"
        //My guess is that SpringSecurity context in mockMvc is not stored in redis.
        List<SessionInformation> sessionInformations = springSessionBackedSessionRegistry.getAllSessions(principal, true);
        
        if(sessionInformations.isEmpty()) {
            log.info("redis session is empty");
        }   
        for(SessionInformation sessionInformation : sessionInformations) {
            UserDetails userDetails2 = (UserDetails)sessionInformation.getPrincipal();
            User user = userDetails2 .getUser();
            log.info("user name in redis session : {}", user.getUsername());
            
        }
}
            

This is the code that confuses me. If I run the application and connect to /sessionid, it can be seen as the sessionid stored in redis. becaule I can get the string "session id saved in redis : ~~~~" on console result. On the other hand, when the test code is run, the id stored in redis is not displayed in the controller, and the user name stored in redis is not displayed in the test code.

========= redis Session test controller==========
redis session is empty!
==============Redis Session test=============
user name in Security Context : mockUser
redis session is empty

I have studied security filter and expect that SecurityContextPersistenceFilter will serve to save security context in redis. Then, if you automatically save the SecurityContext including the Authentication object in the ScurityContextHolder in the test code when using the @WithMockCustomUser annotation, it is expected that the SecurityContextPersistenceFilter will save the SecurityContext in redis at the time of response. However, when testing, it seems that the session is not saved in redis as you can see the output.

it is saved when just connecting to the application, and not saved when using mockMvc. I have no idea why.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source