blob: bd65788a0f28a88f8c4a1efa050d67204900817b (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
//
// ========================================================================
// 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 static org.junit.Assert.assertNull;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
/* ------------------------------------------------------------ */
/**
* @version $Revision$ $Date$
*/
public class AsyncCallbackHttpExchangeTest
{
/* ------------------------------------------------------------ */
/**
* If the HttpExchange callbacks are called holding the lock on HttpExchange,
* it will be impossible for the callback to perform some work asynchronously
* and contemporarly accessing the HttpExchange instance synchronized state.
* This test verifies that this situation does not happen.
*
* @throws Exception if the test fails
*/
@Test
public void testAsyncCallback() throws Exception
{
ExecutorService executor = Executors.newCachedThreadPool();
try
{
AtomicReference<Exception> failure = new AtomicReference<Exception>();
TestHttpExchange exchange = new TestHttpExchange(executor, failure);
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
exchange.setStatus(HttpExchange.STATUS_SENDING_REQUEST);
// This status change triggers onRequestCommitted()
exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
assertNull(failure.get());
}
finally
{
executor.shutdown();
}
}
/* ------------------------------------------------------------ */
private class TestHttpExchange extends HttpExchange
{
private final ExecutorService executor;
private final AtomicReference<Exception> failure;
/* ------------------------------------------------------------ */
private TestHttpExchange(ExecutorService executor, AtomicReference<Exception> failure)
{
this.executor = executor;
this.failure = failure;
}
/* ------------------------------------------------------------ */
@Override
protected void onRequestCommitted() throws IOException
{
Future<Integer> future = executor.submit(new Callable<Integer>()
{
/* ------------------------------------------------------------ */
public Integer call() throws Exception
{
// Method getStatus() reads synchronized state
return TestHttpExchange.this.getStatus();
}
});
// We're waiting for the future to complete, thus never exiting
// this method; if this method is called with the lock held,
// this method never completes
try
{
future.get(1000, TimeUnit.MILLISECONDS);
// Test green here
}
catch (Exception x)
{
// Timed out, the test did not pass
failure.set(x);
}
}
}
}
|