Java tutorial
/** * Copyright 2014 Andy Godwin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package uk.co.sdev.async.http; import com.github.tomakehurst.wiremock.verification.LoggedRequest; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.junit.Test; import uk.co.sdev.async.HandOff; import uk.co.sdev.async.Tuple2; import uk.co.sdev.async.http.model.Denominator; import uk.co.sdev.async.http.model.Numerator; import uk.co.sdev.async.http.model.Quotient; import java.io.IOException; import java.math.BigDecimal; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import static com.github.tomakehurst.wiremock.client.WireMock.findAll; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static uk.co.sdev.async.Futures.none; import static uk.co.sdev.async.Futures.parallel; import static uk.co.sdev.async.Futures.sequential; public abstract class AbstractParallel2SequentialCompletableFutureTest extends CompletableFutureClientTestSupport { protected abstract CompletableFuture<Optional<Numerator>> getNumerator() throws IOException; protected abstract CompletableFuture<Optional<Denominator>> getDenominator() throws IOException; protected abstract CompletableFuture<Optional<Quotient>> divide(Numerator numerator, Denominator denominator) throws IOException; private Function<Tuple2<Optional<Numerator>, Optional<Denominator>>, CompletableFuture<Optional<Quotient>>> divideFunc = tuple -> { if (tuple.a().isPresent() && tuple.b().isPresent()) { try { return divide(tuple.a().get(), tuple.b().get()); } catch (IOException ioe) { return none(); } } else { return none(); } }; @Test public void shouldDivide() throws Exception { stubGet("/numerator", new Numerator(new BigDecimal("12.4"))); stubGet("/denominator", new Denominator(new BigDecimal("3.2"))); stubGet("/divide/12.4/3.2", new Quotient(new BigDecimal("3.875"))); HandOff<Optional<Quotient>> handOff = new HandOff<>(); sequential(parallel(getNumerator(), getDenominator()), divideFunc) .whenComplete((quotient, throwable) -> handOff.put(quotient)); Optional<Quotient> quotient = handOff.get(3); assertThat(quotient.isPresent(), is(true)); assertThat(quotient.get().getValue(), is(new BigDecimal("3.875"))); List<LoggedRequest> gets = findAll(getRequestedFor(urlMatching(".*"))); for (LoggedRequest get : gets) { System.out.println(ReflectionToStringBuilder.toString(get)); } assertThat(gets.size(), is(3)); } @Test public void shouldReturnNoneIfNumeratorNotFound() throws Exception { stubGet("/numerator", 404); stubGet("/denominator", new Denominator(new BigDecimal("5.5"))); HandOff<Optional<Quotient>> handOff = new HandOff<>(); sequential(parallel(getNumerator(), getDenominator()), divideFunc) .whenComplete((quotient, throwable) -> handOff.put(quotient)); Optional<Quotient> quotient = handOff.get(3); assertThat(quotient.isPresent(), is(false)); List<LoggedRequest> gets = findAll(getRequestedFor(urlMatching(".*"))); for (LoggedRequest get : gets) { System.out.println(ReflectionToStringBuilder.toString(get)); } assertThat(gets.size(), is(2)); } @Test public void shouldReturnNoneIfGetDenominatorReturnsInternalServerError() throws Exception { stubGet("/numerator", new Numerator(new BigDecimal("6.2"))); stubGet("/denominator", 500); HandOff<Optional<Quotient>> handOff = new HandOff<>(); sequential(parallel(getNumerator(), getDenominator()), divideFunc) .whenComplete((quotient, throwable) -> handOff.put(quotient)); Optional<Quotient> quotient = handOff.get(3); assertThat(quotient.isPresent(), is(false)); List<LoggedRequest> gets = findAll(getRequestedFor(urlMatching(".*"))); for (LoggedRequest get : gets) { System.out.println(ReflectionToStringBuilder.toString(get)); } assertThat(gets.size(), is(2)); } @Test public void shouldReturnNoneIfDivideReturnsServiceUnavailable() throws Exception { stubGet("/numerator", new Numerator(new BigDecimal("7.2"))); stubGet("/denominator", new Denominator(new BigDecimal("2.5"))); stubGet("/divide/7.2/2.5", 503); HandOff<Optional<Quotient>> handOff = new HandOff<>(); sequential(parallel(getNumerator(), getDenominator()), divideFunc) .whenComplete((quotient, throwable) -> handOff.put(quotient)); Optional<Quotient> quotient = handOff.get(3); assertThat(quotient.isPresent(), is(false)); List<LoggedRequest> gets = findAll(getRequestedFor(urlMatching(".*"))); for (LoggedRequest get : gets) { System.out.println(ReflectionToStringBuilder.toString(get)); } assertThat(gets.size(), is(3)); } }