38 |
38 |
39 /** |
39 /** |
40 * @test |
40 * @test |
41 * @bug 8178147 |
41 * @bug 8178147 |
42 * @summary Ensures that small timeouts do not cause hangs due to race conditions |
42 * @summary Ensures that small timeouts do not cause hangs due to race conditions |
43 * @run main/othervm SmallTimeout |
43 * @run main/othervm -Djdk.incubator.http.internal.common.DEBUG=true SmallTimeout |
44 */ |
44 */ |
45 |
45 |
46 // To enable logging use. Not enabled by default as it changes the dynamics |
46 // To enable logging use. Not enabled by default as it changes the dynamics |
47 // of the test. |
47 // of the test. |
48 // @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all SmallTimeout |
48 // @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all SmallTimeout |
50 public class SmallTimeout { |
50 public class SmallTimeout { |
51 |
51 |
52 static int[] TIMEOUTS = {2, 1, 3, 2, 100, 1}; |
52 static int[] TIMEOUTS = {2, 1, 3, 2, 100, 1}; |
53 |
53 |
54 // A queue for placing timed out requests so that their order can be checked. |
54 // A queue for placing timed out requests so that their order can be checked. |
55 static LinkedBlockingQueue<HttpRequest> queue = new LinkedBlockingQueue<>(); |
55 static LinkedBlockingQueue<HttpResult> queue = new LinkedBlockingQueue<>(); |
|
56 |
|
57 static final class HttpResult { |
|
58 final HttpRequest request; |
|
59 final Throwable failed; |
|
60 HttpResult(HttpRequest request, Throwable failed) { |
|
61 this.request = request; |
|
62 this.failed = failed; |
|
63 } |
|
64 |
|
65 static HttpResult of(HttpRequest request) { |
|
66 return new HttpResult(request, null); |
|
67 } |
|
68 |
|
69 static HttpResult of(HttpRequest request, Throwable t) { |
|
70 return new HttpResult(request, t); |
|
71 } |
|
72 |
|
73 } |
56 |
74 |
57 static volatile boolean error; |
75 static volatile boolean error; |
58 |
76 |
59 public static void main(String[] args) throws Exception { |
77 public static void main(String[] args) throws Exception { |
60 HttpClient client = HttpClient.newHttpClient(); |
78 HttpClient client = HttpClient.newHttpClient(); |
74 |
92 |
75 final HttpRequest req = requests[i]; |
93 final HttpRequest req = requests[i]; |
76 CompletableFuture<HttpResponse<Object>> response = client |
94 CompletableFuture<HttpResponse<Object>> response = client |
77 .sendAsync(req, discard(null)) |
95 .sendAsync(req, discard(null)) |
78 .whenComplete((HttpResponse<Object> r, Throwable t) -> { |
96 .whenComplete((HttpResponse<Object> r, Throwable t) -> { |
|
97 Throwable cause = null; |
79 if (r != null) { |
98 if (r != null) { |
80 out.println("Unexpected response: " + r); |
99 out.println("Unexpected response: " + r); |
|
100 cause = new RuntimeException("Unexpected response"); |
81 error = true; |
101 error = true; |
82 } |
102 } |
83 if (t != null) { |
103 if (t != null) { |
84 if (!(t.getCause() instanceof HttpTimeoutException)) { |
104 if (!(t.getCause() instanceof HttpTimeoutException)) { |
85 out.println("Wrong exception type:" + t.toString()); |
105 out.println("Wrong exception type:" + t.toString()); |
86 Throwable c = t.getCause() == null ? t : t.getCause(); |
106 Throwable c = t.getCause() == null ? t : t.getCause(); |
87 c.printStackTrace(); |
107 c.printStackTrace(); |
|
108 cause = c; |
88 error = true; |
109 error = true; |
89 } else { |
110 } else { |
90 out.println("Caught expected timeout: " + t.getCause()); |
111 out.println("Caught expected timeout: " + t.getCause()); |
91 } |
112 } |
92 } |
113 } |
93 if (t == null && r == null) { |
114 if (t == null && r == null) { |
94 out.println("Both response and throwable are null!"); |
115 out.println("Both response and throwable are null!"); |
|
116 cause = new RuntimeException("Both response and throwable are null!"); |
95 error = true; |
117 error = true; |
96 } |
118 } |
97 queue.add(req); |
119 queue.add(HttpResult.of(req,cause)); |
98 }); |
120 }); |
99 } |
121 } |
100 System.out.println("All requests submitted. Waiting ..."); |
122 System.out.println("All requests submitted. Waiting ..."); |
101 |
123 |
102 checkReturn(requests); |
124 checkReturn(requests); |
116 .GET() |
138 .GET() |
117 .build(); |
139 .build(); |
118 |
140 |
119 final HttpRequest req = requests[i]; |
141 final HttpRequest req = requests[i]; |
120 executor.execute(() -> { |
142 executor.execute(() -> { |
|
143 Throwable cause = null; |
121 try { |
144 try { |
122 client.send(req, discard(null)); |
145 client.send(req, discard(null)); |
123 } catch (HttpTimeoutException e) { |
146 } catch (HttpTimeoutException e) { |
124 out.println("Caught expected timeout: " + e); |
147 out.println("Caught expected timeout: " + e); |
125 queue.offer(req); |
148 } catch (Throwable ee) { |
126 } catch (IOException | InterruptedException ee) { |
|
127 Throwable c = ee.getCause() == null ? ee : ee.getCause(); |
149 Throwable c = ee.getCause() == null ? ee : ee.getCause(); |
128 c.printStackTrace(); |
150 c.printStackTrace(); |
|
151 cause = c; |
129 error = true; |
152 error = true; |
|
153 } finally { |
|
154 queue.offer(HttpResult.of(req, cause)); |
130 } |
155 } |
131 }); |
156 }); |
132 } |
157 } |
133 System.out.println("All requests submitted. Waiting ..."); |
158 System.out.println("All requests submitted. Waiting ..."); |
134 |
159 |
137 executor.shutdownNow(); |
162 executor.shutdownNow(); |
138 |
163 |
139 if (error) |
164 if (error) |
140 throw new RuntimeException("Failed. Check output"); |
165 throw new RuntimeException("Failed. Check output"); |
141 |
166 |
142 } finally { |
|
143 ((ExecutorService) client.executor()).shutdownNow(); |
|
144 } |
167 } |
145 } |
168 } |
146 |
169 |
147 static void checkReturn(HttpRequest[] requests) throws InterruptedException { |
170 static void checkReturn(HttpRequest[] requests) throws InterruptedException { |
148 // wait for exceptions and check order |
171 // wait for exceptions and check order |
|
172 boolean ok = true; |
149 for (int j = 0; j < TIMEOUTS.length; j++) { |
173 for (int j = 0; j < TIMEOUTS.length; j++) { |
150 HttpRequest req = queue.take(); |
174 HttpResult res = queue.take(); |
151 out.println("Got request from queue " + req + ", order: " + getRequest(req, requests)); |
175 HttpRequest req = res.request; |
|
176 out.println("Got request from queue " + req + ", order: " + getRequest(req, requests) |
|
177 + (res.failed == null ? "" : " failed: " + res.failed)); |
|
178 ok = ok && res.failed == null; |
152 } |
179 } |
153 out.println("Return ok"); |
180 out.println("Return " + (ok ? "ok" : "nok")); |
154 } |
181 } |
155 |
182 |
156 /** Returns the index of the request in the array. */ |
183 /** Returns the index of the request in the array. */ |
157 static String getRequest(HttpRequest req, HttpRequest[] requests) { |
184 static String getRequest(HttpRequest req, HttpRequest[] requests) { |
158 for (int i=0; i<requests.length; i++) { |
185 for (int i=0; i<requests.length; i++) { |