markhobson/spring-rest-template-logger

Causes MockRestServiceServer response body's to be null in tests

Opened this issue · 2 comments

Hi,

This library works great for logging requests/ responses in dev/prod environments. Unfortunately, after installing this library and running my test suite, I got failures in all instances where I was mocking restTemplate responses.

In my Kotlin JUnit tests

import org.springframework.test.web.client.MockRestServiceServer

private var server: MockRestServiceServer? = null

@Autowired
lateinit var restTemplate: RestTemplate

@BeforeEach
fun setUp() {
  server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
}

@Test

fun someTest(){
val resource: Path = Paths.get(javaClass.classLoader.getResource("mockResponses/someResource.json").toURI())
val resourceJson: String = Files.lines(resource).collect(Collectors.joining())

server!!.expect(once(), requestTo("https://example.com/someResource.json"))
                .andExpect(method(HttpMethod.GET))
                .andExpect(header("Authorization", "Basic $myAccessToken"))
                .andRespond(MockRestResponseCreators.withSuccess(resourceJson, MediaType.APPLICATION_JSON))
}

// test something that ultimately invokes this stubbed endpoint

In these tests, I see the log lines for both the request and the response. The response logging actually shows the full json content of my stubbed response (ie what I've read from the file system as a stored json file), but for whatever reason, this doesn't actually get returned anymore.

For now, I've removed the logging capability from being used in tests by having a test version of the rest client and regular version otherwise using profiles. I'd really like to be able to use this in tests without my tests breaking because seeing the JSON request is quite useful since matching the .content in MockRestServiceServer only gives feedback that there was an exact match or there wasn't without any more info.

Hi @mistahenry, thanks for raising this issue. I haven't tried spring-rest-template-logger with MockRestServiceServer but I think this makes sense - the docs mention that it replaces the template's request factory:

In the preceding example, MockRestServiceServer (the central class for client-side REST tests) configures the RestTemplate with a custom ClientHttpRequestFactory that asserts actual requests against expectations and returns “stub” responses.

LoggingCustomizer also replaces the template's request factory, by wrapping it in a buffering implementation:

restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory()));

This buffering decorator is required so that the response body stream can be read multiple times - first time for logging, second time for actual processing. I'd guess that MockRestServiceServer is overwriting this buffering implementation which is why you're seeing a null response body.

The first step would be to create an IT for this MockRestServiceServer use-case, much like LoggingCustomizerIT does for RestTemplate. Would you like to give this a go?

I may be late to the party but I was facing the same issue although I did not use spring-rest-template-logger but instead my own logging interceptor.

As a workaround you can simply tell MockRestServiceServer to actually buffer the response bodies by setting the bufferContent option in its builder, e.g.

final var mockServer = MockRestServiceServer.bindTo(restTemplate).bufferContent().build();

Pretty sure this should work here as well.

See also spring-projects/spring-framework#19258.