From e2a988f8fc3686b29b067a7e3dce839263dd363d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 25 Oct 2012 15:46:57 +0200 Subject: [PATCH] HTTP client: tests on external synchronization. --- .../eclipse/jetty/client/HttpDestination.java | 8 +- .../client/HttpClientSynchronizationTest.java | 108 ++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 5b4b6047124..405314fb68d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -192,8 +192,12 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable RequestPair pair = requests.poll(); if (pair != null) { - requestNotifier.notifyFailure(pair.request, x); - responseNotifier.notifyComplete(pair.listener, new Result(pair.request, x, null)); + Request request = pair.request; + requestNotifier.notifyFailure(request, x); + Response.Listener listener = pair.listener; + HttpResponse response = new HttpResponse(request, listener); + responseNotifier.notifyFailure(listener, response, x); + responseNotifier.notifyComplete(listener, new Result(request, x, response, x)); } } }); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java new file mode 100644 index 00000000000..2011c162597 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.client; + +import java.net.ConnectException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +/** + * Verifies that synchronization performed from outside HttpClient does not cause deadlocks + */ +public class HttpClientSynchronizationTest extends AbstractHttpClientServerTest +{ + public HttpClientSynchronizationTest(SslContextFactory sslContextFactory) + { + super(sslContextFactory); + } + + @Test + public void testSynchronizationOnException() throws Exception + { + start(new EmptyServerHandler()); + int port = connector.getLocalPort(); + server.stop(); + + int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + for (int i = 0; i < count; ++i) + { + Request request = client.newRequest("localhost", port) + .scheme(scheme); + + synchronized (this) + { + request.send(new Response.Listener.Empty() + { + @Override + public void onFailure(Response response, Throwable failure) + { + synchronized (HttpClientSynchronizationTest.this) + { + Assert.assertThat(failure, Matchers.instanceOf(ConnectException.class)); + latch.countDown(); + } + } + }); + } + } + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testSynchronizationOnComplete() throws Exception + { + start(new EmptyServerHandler()); + + int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + for (int i = 0; i < count; ++i) + { + Request request = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme); + + synchronized (this) + { + request.send(new Response.Listener.Empty() + { + @Override + public void onComplete(Result result) + { + synchronized (HttpClientSynchronizationTest.this) + { + Assert.assertFalse(result.isFailed()); + latch.countDown(); + } + } + }); + } + } + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } +}