39 import java.util.ArrayList; |
39 import java.util.ArrayList; |
40 import java.util.List; |
40 import java.util.List; |
41 import java.util.concurrent.CompletableFuture; |
41 import java.util.concurrent.CompletableFuture; |
42 import java.util.concurrent.CompletionStage; |
42 import java.util.concurrent.CompletionStage; |
43 import java.util.concurrent.TimeUnit; |
43 import java.util.concurrent.TimeUnit; |
|
44 import java.util.concurrent.atomic.AtomicBoolean; |
|
45 import java.util.function.Supplier; |
44 import java.util.stream.Collectors; |
46 import java.util.stream.Collectors; |
|
47 |
45 import static java.net.http.HttpClient.Builder.NO_PROXY; |
48 import static java.net.http.HttpClient.Builder.NO_PROXY; |
46 import static java.net.http.HttpClient.newBuilder; |
49 import static java.net.http.HttpClient.newBuilder; |
47 import static java.net.http.WebSocket.NORMAL_CLOSURE; |
50 import static java.net.http.WebSocket.NORMAL_CLOSURE; |
48 import static org.testng.Assert.assertEquals; |
51 import static org.testng.Assert.assertEquals; |
49 import static org.testng.Assert.assertThrows; |
52 import static org.testng.Assert.assertThrows; |
195 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
198 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
196 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
199 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
197 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
200 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
198 } |
201 } |
199 |
202 |
|
203 @DataProvider(name = "sequence") |
|
204 public Object[][] data1() { |
|
205 int[] CLOSE = { |
|
206 0x81, 0x00, // "" |
|
207 0x82, 0x00, // [] |
|
208 0x89, 0x00, // <PING> |
|
209 0x8a, 0x00, // <PONG> |
|
210 0x88, 0x00, // <CLOSE> |
|
211 }; |
|
212 int[] ERROR = { |
|
213 0x81, 0x00, // "" |
|
214 0x82, 0x00, // [] |
|
215 0x89, 0x00, // <PING> |
|
216 0x8a, 0x00, // <PONG> |
|
217 0x8b, 0x00, // 0xB control frame (causes an error) |
|
218 }; |
|
219 return new Object[][]{ |
|
220 {CLOSE, 1}, |
|
221 {CLOSE, 3}, |
|
222 {CLOSE, 4}, |
|
223 {CLOSE, Long.MAX_VALUE}, |
|
224 {ERROR, 1}, |
|
225 {ERROR, 3}, |
|
226 {ERROR, 4}, |
|
227 {ERROR, Long.MAX_VALUE}, |
|
228 }; |
|
229 } |
|
230 |
|
231 @Test(dataProvider = "sequence") |
|
232 public void listenerSequentialOrder(int[] binary, long requestSize) |
|
233 throws IOException |
|
234 { |
|
235 |
|
236 server = Support.serverWithCannedData(binary); |
|
237 server.open(); |
|
238 |
|
239 CompletableFuture<Void> violation = new CompletableFuture<>(); |
|
240 |
|
241 MockListener listener = new MockListener(requestSize) { |
|
242 |
|
243 final AtomicBoolean guard = new AtomicBoolean(); |
|
244 |
|
245 private <T> T checkRunExclusively(Supplier<T> action) { |
|
246 if (guard.getAndSet(true)) { |
|
247 violation.completeExceptionally(new RuntimeException()); |
|
248 } |
|
249 try { |
|
250 return action.get(); |
|
251 } finally { |
|
252 if (!guard.getAndSet(false)) { |
|
253 violation.completeExceptionally(new RuntimeException()); |
|
254 } |
|
255 } |
|
256 } |
|
257 |
|
258 @Override |
|
259 public void onOpen(WebSocket webSocket) { |
|
260 checkRunExclusively(() -> { |
|
261 super.onOpen(webSocket); |
|
262 return null; |
|
263 }); |
|
264 } |
|
265 |
|
266 @Override |
|
267 public CompletionStage<?> onText(WebSocket webSocket, |
|
268 CharSequence data, |
|
269 boolean last) { |
|
270 return checkRunExclusively( |
|
271 () -> super.onText(webSocket, data, last)); |
|
272 } |
|
273 |
|
274 @Override |
|
275 public CompletionStage<?> onBinary(WebSocket webSocket, |
|
276 ByteBuffer data, |
|
277 boolean last) { |
|
278 return checkRunExclusively( |
|
279 () -> super.onBinary(webSocket, data, last)); |
|
280 } |
|
281 |
|
282 @Override |
|
283 public CompletionStage<?> onPing(WebSocket webSocket, |
|
284 ByteBuffer message) { |
|
285 return checkRunExclusively( |
|
286 () -> super.onPing(webSocket, message)); |
|
287 } |
|
288 |
|
289 @Override |
|
290 public CompletionStage<?> onPong(WebSocket webSocket, |
|
291 ByteBuffer message) { |
|
292 return checkRunExclusively( |
|
293 () -> super.onPong(webSocket, message)); |
|
294 } |
|
295 |
|
296 @Override |
|
297 public CompletionStage<?> onClose(WebSocket webSocket, |
|
298 int statusCode, |
|
299 String reason) { |
|
300 return checkRunExclusively( |
|
301 () -> super.onClose(webSocket, statusCode, reason)); |
|
302 } |
|
303 |
|
304 @Override |
|
305 public void onError(WebSocket webSocket, Throwable error) { |
|
306 checkRunExclusively(() -> { |
|
307 super.onError(webSocket, error); |
|
308 return null; |
|
309 }); |
|
310 } |
|
311 }; |
|
312 |
|
313 webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
|
314 .buildAsync(server.getURI(), listener) |
|
315 .join(); |
|
316 |
|
317 |
|
318 listener.invocations(); |
|
319 violation.complete(null); // won't affect if completed exceptionally |
|
320 violation.join(); |
|
321 } |
|
322 |
200 @Test |
323 @Test |
201 public void sendMethodsThrowIOE2() throws Exception { |
324 public void sendMethodsThrowIOE2() throws Exception { |
202 server = Support.serverWithCannedData(0x88, 0x00); |
325 server = Support.serverWithCannedData(0x88, 0x00); |
203 server.open(); |
326 server.open(); |
204 CompletableFuture<Void> onCloseCalled = new CompletableFuture<>(); |
327 CompletableFuture<Void> onCloseCalled = new CompletableFuture<>(); |