package _4_blocking;

import com.diffplug.common.base.Errors;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.google.common.base.Stopwatch;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class HttpCallsTest {
    public static final int DELAY_MILLIS = 500;
    
    @Rule
    public WireMockRule service = new WireMockRule(WireMockConfiguration.options().jettyAcceptors(4));

    private CloseableHttpClient httpClient;

    private List<String> urls;

    @Test(timeout = 100 * DELAY_MILLIS)
    public void shouldName() throws Exception {
        int totalSerialDelay = urls.size() * DELAY_MILLIS;

        Stopwatch stopwatch = Stopwatch.createStarted();
        urls.stream()
                .parallel()
                .map(HttpGet::new)
                .map(Errors.rethrow().wrapFunction(httpClient::execute))
                .map(HttpResponse::getStatusLine)
                .forEach(System.out::println);
        stopwatch.stop();

        assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS), is(lessThan(totalSerialDelay)));
    }

    @Before
    public void setUp() throws Exception {
        httpClient = HttpClientBuilder.create()
                .setMaxConnTotal(8)
                .setMaxConnPerRoute(8)
                .build();

        service.stubFor(get(urlEqualTo("/slow")).willReturn(
                aResponse()
                        .withStatus(200)
                        .withFixedDelay(DELAY_MILLIS)));

        urls = Stream.generate(() -> String.format("http://localhost:%d/slow", service.port()))
                .limit(5)
                .collect(toList());
    }

    @After
    public void tearDown() throws Exception {
        httpClient.close();
    }

    static private <T extends Number, U extends Number> Matcher<T> lessThan(U value) {
        return new TypeSafeMatcher<T>() {
            @Override
            protected boolean matchesSafely(T item) {
                return Double.compare(item.doubleValue(), value.doubleValue()) < 0;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("less than ")
                        .appendValue(value);
            }
        };
    }

}

@@ -1144,20 +1144,65 @@
  = 500;%0A
+%0A
     
+public static final int NUMBER_OF_URLS = 5;%0A
 %0A    @Ru
@@ -1409,11 +1409,22 @@
 t = 
-100
+NUMBER_OF_URLS
  * D
@@ -1434,16 +1434,20 @@
 Y_MILLIS
+ * 2
 )%0A    pu
@@ -1466,12 +1466,700 @@
 ould
-Name
+ExecuteRequestsInParallel() throws Exception %7B%0A        int totalSerialDelay = urls.size() * DELAY_MILLIS;%0A%0A        Stopwatch stopwatch = Stopwatch.createStarted();%0A        urls.stream()%0A                .parallel()%0A                .map(url -%3E url + %22slow%22)%0A                .map(HttpGet::new)%0A                .map(Errors.rethrow().wrapFunction(httpClient::execute))%0A                .map(HttpResponse::getStatusLine)%0A                .forEach(System.out::println);%0A        stopwatch.stop();%0A%0A        assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS), is(lessThan(totalSerialDelay)));%0A    %7D%0A%0A    @Test(timeout = NUMBER_OF_URLS * DELAY_MILLIS * 2)%0A    public void shouldFailDueToBlockedOperations
 () t
@@ -2335,32 +2335,76 @@
     .parallel()%0A
+                .map(url -%3E url + %22slooow%22)%0A
                 
@@ -3109,24 +3109,236 @@
 MILLIS)));%0A%0A
+        service.stubFor(get(urlEqualTo(%22/slooow%22)).willReturn(%0A                aResponse()%0A                        .withStatus(200)%0A                        .withFixedDelay(((int) TimeUnit.HOURS.toMillis(1)))));%0A%0A
         urls
@@ -3397,20 +3397,16 @@
 host:%25d/
-slow
 %22, servi
@@ -3440,17 +3440,30 @@
  .limit(
-5
+NUMBER_OF_URLS
 )%0A      

Add very slow endpoint for blocking tests