Skip to content

ConcurrentModificationException in MockMvc.perform #7224

Closed
@mmyersDE

Description

@mmyersDE

Summary

When using mockMvc.perform on MockMvcRequestBuilders.asyncDispatch with a Spring Security configured applicationContext we receive a ConcurrentModificationException in approximately every 10th test-run.
The Exception can be prevented by @DirtiesContext, but this slows down the test alot and can not be used when calling mockMvc.perform multiple times in a single test-method.

Actual Behavior

java.util.ConcurrentModificationException
	at java.base/java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:719)
	at java.base/java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:741)
	at org.springframework.mock.web.HeaderValueHolder.getByName(HeaderValueHolder.java:98)
	at org.springframework.mock.web.MockHttpServletResponse.doAddHeaderValue(MockHttpServletResponse.java:617)
	at org.springframework.mock.web.MockHttpServletResponse.setHeaderValue(MockHttpServletResponse.java:579)
	at org.springframework.mock.web.MockHttpServletResponse.setHeader(MockHttpServletResponse.java:557)
	at javax.servlet.http.HttpServletResponseWrapper.setHeader(HttpServletResponseWrapper.java:165)
	at org.springframework.security.web.firewall.FirewalledResponse.setHeader(FirewalledResponse.java:50)
	at javax.servlet.http.HttpServletResponseWrapper.setHeader(HttpServletResponseWrapper.java:165)
	at org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.writeHeaders(XFrameOptionsHeaderWriter.java:94)
	at org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterResponse.writeHeaders(HeaderWriterFilter.java:109)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
	at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
	at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:182)

Expected Behavior

Test finishes without error.

Version

springBootVersion = '2.1.7.RELEASE'

Sample

@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = Controller.class)
public class ControllerTest {

    @Autowired
    protected WebApplicationContext wac;

    @Test
    public void test() throws Exception {
        MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(wac).apply(SecurityMockMvcConfigurers.springSecurity()).build();
        MvcResult result = mockMvc.perform(get("/test"))
                .andExpect(request().asyncStarted()).andReturn();
        mockMvc.perform(asyncDispatch(result)).andExpect(status().isOk());
    }
}
@SpringBootApplication
@RestController
public class Controller extends WebSecurityConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(Controller.class, args);
    }

    @GetMapping("/test")
    public ResponseEntity<StreamingResponseBody> test() {
        return new ResponseEntity<>(outputStream -> outputStream.write("content".getBytes()), OK);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll();
    }
}

Metadata

Metadata

Assignees

Labels

for: external-projectFor an external project and not something we can fix

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions