package org.zalando.riptide.stream; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.restdriver.clientdriver.ClientDriverRule; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.http.client.ClientHttpResponse; import org.zalando.riptide.Rest; import java.io.IOException; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NON_PRIVATE; import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; import static com.github.restdriver.clientdriver.RestClientDriver.giveEmptyResponse; import static com.github.restdriver.clientdriver.RestClientDriver.giveResponseAsBytes; import static com.github.restdriver.clientdriver.RestClientDriver.onRequestTo; import static com.google.common.io.Resources.getResource; import static java.util.Collections.singletonList; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.stream.Collectors.toList; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertThat; import static org.springframework.http.HttpStatus.Series.SUCCESSFUL; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.zalando.riptide.Bindings.on; import static org.zalando.riptide.Navigators.reasonPhrase; import static org.zalando.riptide.Navigators.series; import static org.zalando.riptide.RestBuilder.simpleRequestFactory; import static org.zalando.riptide.Route.pass; import static org.zalando.riptide.stream.Streams.streamConverter; import static org.zalando.riptide.stream.Streams.streamOf; public final class StreamIOTest { @Rule public final ClientDriverRule driver = new ClientDriverRule(); public final ExpectedException exception = ExpectedException.none(); @JsonAutoDetect(fieldVisibility = NON_PRIVATE) static class User { String login; public String getLogin() { return login; } } private final ExecutorService executor = newSingleThreadExecutor(); private final Rest rest = Rest.builder() .baseUrl(driver.getBaseUrl()) .configure(simpleRequestFactory(newSingleThreadExecutor())) .converter(streamConverter(new ObjectMapper().disable(FAIL_ON_UNKNOWN_PROPERTIES), singletonList(APPLICATION_JSON))) .build(); @After public void shutdownExecutor() { executor.shutdown(); } @Test public void shouldReadContributors() throws IOException { driver.addExpectation(onRequestTo("/repos/zalando/riptide/contributors"), giveResponseAsBytes(getResource("contributors.json").openStream(), "application/json")); final AtomicReference<Stream<User>> reference = new AtomicReference<>(); rest.get("/repos/{org}/{repo}/contributors", "zalando", "riptide") .dispatch(series(), on(SUCCESSFUL).call(streamOf(User.class), reference::set)).join(); final List<String> users = reference.get() .map(User::getLogin) .collect(toList()); assertThat(users, hasItems("jhorstmann", "lukasniemeier-zalando", "whiskeysierra")); } @Test public void shouldCancelRequest() throws IOException { driver.addExpectation(onRequestTo("/repos/zalando/riptide/contributors"), giveResponseAsBytes(getResource("contributors.json").openStream(), "application/json")); final CompletableFuture<Void> future = rest.get("/repos/{org}/{repo}/contributors", "zalando", "riptide") .dispatch(series(), on(SUCCESSFUL).call(pass())); future.cancel(true); try { future.join(); } catch (final CancellationException e) { // expected } // we don't care whether the request was actually made or not, but by default the driver will verify // all expectations after every tests driver.reset(); } @Test public void shouldFailOnResponse() throws IOException { driver.addExpectation(onRequestTo("/repos/zalando/riptide/contributors"), giveResponseAsBytes(getResource("contributors.json").openStream(), "application/json") .after(1, TimeUnit.SECONDS)); exception.expect(CompletionException.class); exception.expectCause(instanceOf(IOException.class)); rest.get("/repos/{org}/{repo}/contributors", "zalando", "riptide") .dispatch(reasonPhrase(), on("OK").call(ClientHttpResponse::close)).join(); } @Test public void shouldReadEmptyResponse() { driver.addExpectation(onRequestTo("/repos/zalando/riptide/contributors"), giveEmptyResponse().withStatus(200)); rest.get("/repos/{org}/{repo}/contributors", "zalando", "riptide") .dispatch(reasonPhrase(), on("OK").call(ClientHttpResponse::close)).join(); } }