2

In my production code I need to execute POST command to a controller which response StreamingResponseBody. A short example of such code is :

@RestController
@RequestMapping("/api")
public class DalaLakeRealController {

    @PostMapping(value = "/downloaddbcsv", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<StreamingResponseBody> downloadDBcsv(@Valid @RequestBody SearchQuery searchRequest) {
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, "application/csv")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=demoStream.csv")
                .body(
                        get3Lines()
                );
    }

    public StreamingResponseBody get3Lines() {
        StreamingResponseBody streamingResponseBody = new StreamingResponseBody() {
            @Override
            public void writeTo(OutputStream outputStream) throws IOException {
                outputStream.write("LineNumber111111111\n".getBytes());
                outputStream.write("LineNumber222222222\n".getBytes());
                outputStream.write("LineNumber333333333\n".getBytes());
            }
        };
        return streamingResponseBody;
    }
}

In the testing I would like to mock the response from this controller. I have read the following link : Using MockRestServiceServer to Test a REST Client to mock external controllers.
But in andRespond of mockServer it expects ClientHttpResponse or ResponseCreator

mockServer.expect(once(), requestTo("http://localhost:8080/api/downloaddbcsv"))
    .andRespond(withSuccess("{message : 'under construction'}", MediaType.APPLICATION_JSON));

How do I respond with StreamingResponseBody in MockRestServiceServer?

Ida Amit
  • 1,411
  • 2
  • 13
  • 27
  • `MockRestServiceServer` is used to test a REST client. I believe you want to test your REST service, `DalaLakeRealController`. Take a look at Spring's `MockMvc`. I think this is what you are looking for. – jpllosa May 07 '20 at 20:28
  • Wtih MockMvc you test your controller. The Stream controller doesn't belong to my micro-service, In my production code I initiate request to controller which returns Stream. I would like to test my request – Ida Amit May 11 '20 at 06:29

2 Answers2

0

I hope this will guide you...

@Test
public void whenTopicNotExistsThenTopicNotFound() throws IOException, NakadiException {
    when(eventTypeRepository.findByName(TEST_EVENT_TYPE_NAME)).thenThrow(NoSuchEventTypeException.class);

    final StreamingResponseBody responseBody = createStreamingResponseBody();

    final Problem expectedProblem = Problem.valueOf(NOT_FOUND, "topic not found");
    assertThat(responseToString(responseBody), TestUtils.JSON_TEST_HELPER.matchesObject(expectedProblem));
}

Got the above code from: https://www.programcreek.com/java-api-examples/index.php?api=org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody

The idea is to convert the StreamingResponseBody into a String. Then you can do something like:

mockServer.expect(once(), requestTo("http://localhost:8080/api/downloaddbcsv"))
.andRespond(withSuccess(responseToString(responseBody), MediaType.APPLICATION_JSON));

Furthermore, take a look here: https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBodyReturnValueHandlerTests.java

The streamingResponseBody() and responseEntity() test methods convert the response to aString.

jpllosa
  • 2,066
  • 1
  • 28
  • 30
0

Although this post is old, this answer might help someone looking for this nowdays.

The answer for the question is the Functional Interface (streamingResponseBody) shown in the code below combined with the mock return of the download in the cloudStorageService.

    @Test
    @WithUserDetailsMock(
        email = "participant@localhost",
        authorities = AuthoritiesConstants.USER,
        cashflowAuthorities = CashflowAuthoritiesConstants.PARTICIPANT
    )
    void testDownloadFileThenSuccess() throws Exception {
        Member loggedMember = memberService.getLoggedMember();
        File file = EntityBuilder.file(loggedMember.getGroup()).build(fileRepository::save);
        SubmittedPayment submittedPayment = EntityBuilder
            .submittedPayment(loggedMember)
            .with(SubmittedPayment::setFile, file)
            .build(submittedPaymentRepository::save);

        String endpoint = String.format("/api/payment/submit/%d/file", submittedPayment.getId());
        byte[] fileBytes = "some content".getBytes();
        StreamingResponseBody streamingResponseBody = objectStream -> {
            var mockInputStream = new ByteArrayInputStream(fileBytes);
            try (mockInputStream) {
                byte[] bytes = mockInputStream.readAllBytes();
                objectStream.write(bytes, 0, bytes.length);
            }
        };
        doReturn(streamingResponseBody).when(cloudStorageService).download(fileArgumentCaptor.capture());

        MvcResult response = restTransactionMockMvc.perform(get(endpoint)).andExpect(status().isOk()).andReturn();

        assertThat(file).isEqualTo(fileArgumentCaptor.getValue());
        assertThat(Arrays.equals(fileBytes, response.getResponse().getContentAsByteArray())).isTrue();
    }
Eli
  • 21
  • 4