71 private static void assertFails(Class<? extends Throwable> clazz, |
70 private static void assertFails(Class<? extends Throwable> clazz, |
72 CompletionStage<?> stage) { |
71 CompletionStage<?> stage) { |
73 Support.assertCompletesExceptionally(clazz, stage); |
72 Support.assertCompletesExceptionally(clazz, stage); |
74 } |
73 } |
75 |
74 |
76 private DummyWebSocketServer server; |
|
77 private WebSocket webSocket; |
|
78 |
|
79 @AfterTest |
|
80 public void cleanup() { |
|
81 System.out.println("AFTER TEST"); |
|
82 if (server != null) |
|
83 server.close(); |
|
84 if (webSocket != null) |
|
85 webSocket.abort(); |
|
86 } |
|
87 |
|
88 @Test |
75 @Test |
89 public void illegalArgument() throws IOException { |
76 public void illegalArgument() throws IOException { |
90 server = new DummyWebSocketServer(); |
77 try (var server = new DummyWebSocketServer()) { |
91 server.open(); |
78 server.open(); |
92 webSocket = newBuilder().proxy(NO_PROXY).build() |
79 var webSocket = newBuilder().proxy(NO_PROXY).build() |
93 .newWebSocketBuilder() |
80 .newWebSocketBuilder() |
94 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
81 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
95 .join(); |
82 .join(); |
96 |
83 try { |
97 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(126))); |
84 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(126))); |
98 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(127))); |
85 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(127))); |
99 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(128))); |
86 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(128))); |
100 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(129))); |
87 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(129))); |
101 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(256))); |
88 assertFails(IAE, webSocket.sendPing(ByteBuffer.allocate(256))); |
102 |
89 |
103 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(126))); |
90 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(126))); |
104 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(127))); |
91 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(127))); |
105 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(128))); |
92 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(128))); |
106 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(129))); |
93 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(129))); |
107 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(256))); |
94 assertFails(IAE, webSocket.sendPong(ByteBuffer.allocate(256))); |
108 |
95 |
109 assertFails(IOE, webSocket.sendText(Support.incompleteString(), true)); |
96 assertFails(IOE, webSocket.sendText(Support.incompleteString(), true)); |
110 assertFails(IOE, webSocket.sendText(Support.incompleteString(), false)); |
97 assertFails(IOE, webSocket.sendText(Support.incompleteString(), false)); |
111 assertFails(IOE, webSocket.sendText(Support.malformedString(), true)); |
98 assertFails(IOE, webSocket.sendText(Support.malformedString(), true)); |
112 assertFails(IOE, webSocket.sendText(Support.malformedString(), false)); |
99 assertFails(IOE, webSocket.sendText(Support.malformedString(), false)); |
113 |
100 |
114 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124))); |
101 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124))); |
115 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125))); |
102 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125))); |
116 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128))); |
103 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128))); |
117 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256))); |
104 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256))); |
118 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257))); |
105 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257))); |
119 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1))); |
106 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1))); |
120 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.malformedString())); |
107 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.malformedString())); |
121 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.incompleteString())); |
108 assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.incompleteString())); |
122 |
109 |
123 assertFails(IAE, webSocket.sendClose(-2, "a reason")); |
110 assertFails(IAE, webSocket.sendClose(-2, "a reason")); |
124 assertFails(IAE, webSocket.sendClose(-1, "a reason")); |
111 assertFails(IAE, webSocket.sendClose(-1, "a reason")); |
125 assertFails(IAE, webSocket.sendClose(0, "a reason")); |
112 assertFails(IAE, webSocket.sendClose(0, "a reason")); |
126 assertFails(IAE, webSocket.sendClose(1, "a reason")); |
113 assertFails(IAE, webSocket.sendClose(1, "a reason")); |
127 assertFails(IAE, webSocket.sendClose(500, "a reason")); |
114 assertFails(IAE, webSocket.sendClose(500, "a reason")); |
128 assertFails(IAE, webSocket.sendClose(998, "a reason")); |
115 assertFails(IAE, webSocket.sendClose(998, "a reason")); |
129 assertFails(IAE, webSocket.sendClose(999, "a reason")); |
116 assertFails(IAE, webSocket.sendClose(999, "a reason")); |
130 assertFails(IAE, webSocket.sendClose(1002, "a reason")); |
117 assertFails(IAE, webSocket.sendClose(1002, "a reason")); |
131 assertFails(IAE, webSocket.sendClose(1003, "a reason")); |
118 assertFails(IAE, webSocket.sendClose(1003, "a reason")); |
132 assertFails(IAE, webSocket.sendClose(1006, "a reason")); |
119 assertFails(IAE, webSocket.sendClose(1006, "a reason")); |
133 assertFails(IAE, webSocket.sendClose(1007, "a reason")); |
120 assertFails(IAE, webSocket.sendClose(1007, "a reason")); |
134 assertFails(IAE, webSocket.sendClose(1009, "a reason")); |
121 assertFails(IAE, webSocket.sendClose(1009, "a reason")); |
135 assertFails(IAE, webSocket.sendClose(1010, "a reason")); |
122 assertFails(IAE, webSocket.sendClose(1010, "a reason")); |
136 assertFails(IAE, webSocket.sendClose(1012, "a reason")); |
123 assertFails(IAE, webSocket.sendClose(1012, "a reason")); |
137 assertFails(IAE, webSocket.sendClose(1013, "a reason")); |
124 assertFails(IAE, webSocket.sendClose(1013, "a reason")); |
138 assertFails(IAE, webSocket.sendClose(1015, "a reason")); |
125 assertFails(IAE, webSocket.sendClose(1015, "a reason")); |
139 assertFails(IAE, webSocket.sendClose(5000, "a reason")); |
126 assertFails(IAE, webSocket.sendClose(5000, "a reason")); |
140 assertFails(IAE, webSocket.sendClose(32768, "a reason")); |
127 assertFails(IAE, webSocket.sendClose(32768, "a reason")); |
141 assertFails(IAE, webSocket.sendClose(65535, "a reason")); |
128 assertFails(IAE, webSocket.sendClose(65535, "a reason")); |
142 assertFails(IAE, webSocket.sendClose(65536, "a reason")); |
129 assertFails(IAE, webSocket.sendClose(65536, "a reason")); |
143 assertFails(IAE, webSocket.sendClose(Integer.MAX_VALUE, "a reason")); |
130 assertFails(IAE, webSocket.sendClose(Integer.MAX_VALUE, "a reason")); |
144 assertFails(IAE, webSocket.sendClose(Integer.MIN_VALUE, "a reason")); |
131 assertFails(IAE, webSocket.sendClose(Integer.MIN_VALUE, "a reason")); |
145 |
132 |
146 assertThrows(IAE, () -> webSocket.request(Integer.MIN_VALUE)); |
133 assertThrows(IAE, () -> webSocket.request(Integer.MIN_VALUE)); |
147 assertThrows(IAE, () -> webSocket.request(Long.MIN_VALUE)); |
134 assertThrows(IAE, () -> webSocket.request(Long.MIN_VALUE)); |
148 assertThrows(IAE, () -> webSocket.request(-1)); |
135 assertThrows(IAE, () -> webSocket.request(-1)); |
149 assertThrows(IAE, () -> webSocket.request(0)); |
136 assertThrows(IAE, () -> webSocket.request(0)); |
150 |
137 |
151 server.close(); |
138 } finally { |
|
139 webSocket.abort(); |
|
140 } |
|
141 } |
152 } |
142 } |
153 |
143 |
154 @Test |
144 @Test |
155 public void partialBinaryThenText() throws IOException { |
145 public void partialBinaryThenText() throws IOException { |
156 server = new DummyWebSocketServer(); |
146 try (var server = new DummyWebSocketServer()) { |
157 server.open(); |
147 server.open(); |
158 webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
148 var webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
159 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
149 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
160 .join(); |
150 .join(); |
161 webSocket.sendBinary(ByteBuffer.allocate(16), false).join(); |
151 try { |
162 assertFails(ISE, webSocket.sendText("text", false)); |
152 webSocket.sendBinary(ByteBuffer.allocate(16), false).join(); |
163 assertFails(ISE, webSocket.sendText("text", true)); |
153 assertFails(ISE, webSocket.sendText("text", false)); |
164 // Pings & Pongs are fine |
154 assertFails(ISE, webSocket.sendText("text", true)); |
165 webSocket.sendPing(ByteBuffer.allocate(125)).join(); |
155 // Pings & Pongs are fine |
166 webSocket.sendPong(ByteBuffer.allocate(125)).join(); |
156 webSocket.sendPing(ByteBuffer.allocate(125)).join(); |
167 server.close(); |
157 webSocket.sendPong(ByteBuffer.allocate(125)).join(); |
|
158 } finally { |
|
159 webSocket.abort(); |
|
160 } |
|
161 } |
168 } |
162 } |
169 |
163 |
170 @Test |
164 @Test |
171 public void partialTextThenBinary() throws IOException { |
165 public void partialTextThenBinary() throws IOException { |
172 server = new DummyWebSocketServer(); |
166 try (var server = new DummyWebSocketServer()) { |
173 server.open(); |
167 server.open(); |
174 webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
168 var webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
175 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
169 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
176 .join(); |
170 .join(); |
177 |
171 try { |
178 webSocket.sendText("text", false).join(); |
172 webSocket.sendText("text", false).join(); |
179 assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), false)); |
173 assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), false)); |
180 assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), true)); |
174 assertFails(ISE, webSocket.sendBinary(ByteBuffer.allocate(16), true)); |
181 // Pings & Pongs are fine |
175 // Pings & Pongs are fine |
182 webSocket.sendPing(ByteBuffer.allocate(125)).join(); |
176 webSocket.sendPing(ByteBuffer.allocate(125)).join(); |
183 webSocket.sendPong(ByteBuffer.allocate(125)).join(); |
177 webSocket.sendPong(ByteBuffer.allocate(125)).join(); |
184 server.close(); |
178 } finally { |
|
179 webSocket.abort(); |
|
180 } |
|
181 } |
185 } |
182 } |
186 |
183 |
187 @Test |
184 @Test |
188 public void sendMethodsThrowIOE1() throws IOException { |
185 public void sendMethodsThrowIOE1() throws IOException { |
189 server = new DummyWebSocketServer(); |
186 try (var server = new DummyWebSocketServer()) { |
190 server.open(); |
187 server.open(); |
191 webSocket = newBuilder().proxy(NO_PROXY).build() |
188 var webSocket = newBuilder().proxy(NO_PROXY).build() |
192 .newWebSocketBuilder() |
189 .newWebSocketBuilder() |
193 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
190 .buildAsync(server.getURI(), new WebSocket.Listener() { }) |
194 .join(); |
191 .join(); |
195 |
192 try { |
196 webSocket.sendClose(NORMAL_CLOSURE, "ok").join(); |
193 webSocket.sendClose(NORMAL_CLOSURE, "ok").join(); |
197 |
194 |
198 assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok")); |
195 assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok")); |
199 |
196 |
200 assertFails(IOE, webSocket.sendText("", true)); |
197 assertFails(IOE, webSocket.sendText("", true)); |
201 assertFails(IOE, webSocket.sendText("", false)); |
198 assertFails(IOE, webSocket.sendText("", false)); |
202 assertFails(IOE, webSocket.sendText("abc", true)); |
199 assertFails(IOE, webSocket.sendText("abc", true)); |
203 assertFails(IOE, webSocket.sendText("abc", false)); |
200 assertFails(IOE, webSocket.sendText("abc", false)); |
204 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true)); |
201 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true)); |
205 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false)); |
202 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false)); |
206 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true)); |
203 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true)); |
207 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false)); |
204 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false)); |
208 |
205 |
209 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125))); |
206 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125))); |
210 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124))); |
207 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124))); |
211 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1))); |
208 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1))); |
212 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0))); |
209 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0))); |
213 |
210 |
214 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125))); |
211 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125))); |
215 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
212 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
216 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
213 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
217 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
214 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
218 |
215 } finally { |
219 server.close(); |
216 webSocket.abort(); |
|
217 } |
|
218 } |
220 } |
219 } |
221 |
220 |
222 @DataProvider(name = "sequence") |
221 @DataProvider(name = "sequence") |
223 public Object[][] data1() { |
222 public Object[][] data1() { |
224 int[] CLOSE = { |
223 int[] CLOSE = { |
249 |
248 |
250 @Test(dataProvider = "sequence") |
249 @Test(dataProvider = "sequence") |
251 public void listenerSequentialOrder(int[] binary, long requestSize) |
250 public void listenerSequentialOrder(int[] binary, long requestSize) |
252 throws IOException |
251 throws IOException |
253 { |
252 { |
254 |
253 try (var server = Support.serverWithCannedData(binary)) { |
255 server = Support.serverWithCannedData(binary); |
254 server.open(); |
256 server.open(); |
255 |
257 |
256 CompletableFuture<Void> violation = new CompletableFuture<>(); |
258 CompletableFuture<Void> violation = new CompletableFuture<>(); |
257 |
259 |
258 MockListener listener = new MockListener(requestSize) { |
260 MockListener listener = new MockListener(requestSize) { |
259 |
261 |
260 final AtomicBoolean guard = new AtomicBoolean(); |
262 final AtomicBoolean guard = new AtomicBoolean(); |
261 |
263 |
262 private <T> T checkRunExclusively(Supplier<T> action) { |
264 private <T> T checkRunExclusively(Supplier<T> action) { |
263 if (guard.getAndSet(true)) { |
265 if (guard.getAndSet(true)) { |
|
266 violation.completeExceptionally(new RuntimeException()); |
|
267 } |
|
268 try { |
|
269 return action.get(); |
|
270 } finally { |
|
271 if (!guard.getAndSet(false)) { |
|
272 violation.completeExceptionally(new RuntimeException()); |
264 violation.completeExceptionally(new RuntimeException()); |
273 } |
265 } |
274 } |
266 try { |
275 } |
267 return action.get(); |
276 |
268 } finally { |
277 @Override |
269 if (!guard.getAndSet(false)) { |
278 public void onOpen(WebSocket webSocket) { |
270 violation.completeExceptionally(new RuntimeException()); |
279 checkRunExclusively(() -> { |
271 } |
280 super.onOpen(webSocket); |
272 } |
281 return null; |
273 } |
282 }); |
274 |
283 } |
275 @Override |
284 |
276 public void onOpen(WebSocket webSocket) { |
285 @Override |
277 checkRunExclusively(() -> { |
286 public CompletionStage<?> onText(WebSocket webSocket, |
278 super.onOpen(webSocket); |
287 CharSequence data, |
279 return null; |
288 boolean last) { |
280 }); |
289 return checkRunExclusively( |
281 } |
290 () -> super.onText(webSocket, data, last)); |
282 |
291 } |
283 @Override |
292 |
284 public CompletionStage<?> onText(WebSocket webSocket, |
293 @Override |
285 CharSequence data, |
294 public CompletionStage<?> onBinary(WebSocket webSocket, |
286 boolean last) { |
295 ByteBuffer data, |
287 return checkRunExclusively( |
296 boolean last) { |
288 () -> super.onText(webSocket, data, last)); |
297 return checkRunExclusively( |
289 } |
298 () -> super.onBinary(webSocket, data, last)); |
290 |
299 } |
291 @Override |
300 |
292 public CompletionStage<?> onBinary(WebSocket webSocket, |
301 @Override |
293 ByteBuffer data, |
302 public CompletionStage<?> onPing(WebSocket webSocket, |
294 boolean last) { |
303 ByteBuffer message) { |
295 return checkRunExclusively( |
304 return checkRunExclusively( |
296 () -> super.onBinary(webSocket, data, last)); |
305 () -> super.onPing(webSocket, message)); |
297 } |
306 } |
298 |
307 |
299 @Override |
308 @Override |
300 public CompletionStage<?> onPing(WebSocket webSocket, |
309 public CompletionStage<?> onPong(WebSocket webSocket, |
301 ByteBuffer message) { |
310 ByteBuffer message) { |
302 return checkRunExclusively( |
311 return checkRunExclusively( |
303 () -> super.onPing(webSocket, message)); |
312 () -> super.onPong(webSocket, message)); |
304 } |
313 } |
305 |
314 |
306 @Override |
315 @Override |
307 public CompletionStage<?> onPong(WebSocket webSocket, |
316 public CompletionStage<?> onClose(WebSocket webSocket, |
308 ByteBuffer message) { |
317 int statusCode, |
309 return checkRunExclusively( |
318 String reason) { |
310 () -> super.onPong(webSocket, message)); |
319 return checkRunExclusively( |
311 } |
320 () -> super.onClose(webSocket, statusCode, reason)); |
312 |
321 } |
313 @Override |
322 |
314 public CompletionStage<?> onClose(WebSocket webSocket, |
323 @Override |
315 int statusCode, |
324 public void onError(WebSocket webSocket, Throwable error) { |
316 String reason) { |
325 checkRunExclusively(() -> { |
317 return checkRunExclusively( |
326 super.onError(webSocket, error); |
318 () -> super.onClose(webSocket, statusCode, reason)); |
327 return null; |
319 } |
328 }); |
320 |
329 } |
321 @Override |
330 }; |
322 public void onError(WebSocket webSocket, Throwable error) { |
331 |
323 checkRunExclusively(() -> { |
332 webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
324 super.onError(webSocket, error); |
333 .buildAsync(server.getURI(), listener) |
325 return null; |
334 .join(); |
326 }); |
335 |
327 } |
336 |
328 }; |
337 listener.invocations(); |
329 |
338 violation.complete(null); // won't affect if completed exceptionally |
330 var webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
339 violation.join(); |
331 .buildAsync(server.getURI(), listener) |
340 |
332 .join(); |
341 server.close(); |
333 try { |
|
334 listener.invocations(); |
|
335 violation.complete(null); // won't affect if completed exceptionally |
|
336 violation.join(); |
|
337 } finally { |
|
338 webSocket.abort(); |
|
339 } |
|
340 } |
342 } |
341 } |
343 |
342 |
344 @Test |
343 @Test |
345 public void sendMethodsThrowIOE2() throws Exception { |
344 public void sendMethodsThrowIOE2() throws Exception { |
346 server = Support.serverWithCannedData(0x88, 0x00); |
345 try (var server = Support.serverWithCannedData(0x88, 0x00)) { |
347 server.open(); |
346 server.open(); |
348 CompletableFuture<Void> onCloseCalled = new CompletableFuture<>(); |
347 |
349 CompletableFuture<Void> canClose = new CompletableFuture<>(); |
348 CompletableFuture<Void> onCloseCalled = new CompletableFuture<>(); |
350 |
349 CompletableFuture<Void> canClose = new CompletableFuture<>(); |
351 WebSocket.Listener listener = new WebSocket.Listener() { |
350 |
352 @Override |
351 WebSocket.Listener listener = new WebSocket.Listener() { |
353 public CompletionStage<?> onClose(WebSocket webSocket, |
352 @Override |
354 int statusCode, |
353 public CompletionStage<?> onClose(WebSocket webSocket, |
355 String reason) { |
354 int statusCode, |
356 System.out.printf("onClose(%s, '%s')%n", statusCode, reason); |
355 String reason) { |
357 onCloseCalled.complete(null); |
356 System.out.printf("onClose(%s, '%s')%n", statusCode, reason); |
358 return canClose; |
357 onCloseCalled.complete(null); |
359 } |
358 return canClose; |
360 |
359 } |
361 @Override |
360 |
362 public void onError(WebSocket webSocket, Throwable error) { |
361 @Override |
363 System.out.println("onError(" + error + ")"); |
362 public void onError(WebSocket webSocket, Throwable error) { |
364 onCloseCalled.completeExceptionally(error); |
363 System.out.println("onError(" + error + ")"); |
365 } |
364 onCloseCalled.completeExceptionally(error); |
366 }; |
365 } |
367 |
366 }; |
368 webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
367 |
369 .buildAsync(server.getURI(), listener) |
368 var webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() |
370 .join(); |
369 .buildAsync(server.getURI(), listener) |
371 |
370 .join(); |
372 onCloseCalled.join(); // Wait for onClose to be called |
371 try { |
373 canClose.complete(null); // Signal to the WebSocket it can close the output |
372 onCloseCalled.join(); // Wait for onClose to be called |
374 TimeUnit.SECONDS.sleep(5); // Give canClose some time to reach the WebSocket |
373 canClose.complete(null); // Signal to the WebSocket it can close the output |
375 |
374 TimeUnit.SECONDS.sleep(5); // Give canClose some time to reach the WebSocket |
376 assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok")); |
375 |
377 |
376 assertFails(IOE, webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok")); |
378 assertFails(IOE, webSocket.sendText("", true)); |
377 |
379 assertFails(IOE, webSocket.sendText("", false)); |
378 assertFails(IOE, webSocket.sendText("", true)); |
380 assertFails(IOE, webSocket.sendText("abc", true)); |
379 assertFails(IOE, webSocket.sendText("", false)); |
381 assertFails(IOE, webSocket.sendText("abc", false)); |
380 assertFails(IOE, webSocket.sendText("abc", true)); |
382 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true)); |
381 assertFails(IOE, webSocket.sendText("abc", false)); |
383 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false)); |
382 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), true)); |
384 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true)); |
383 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(0), false)); |
385 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false)); |
384 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), true)); |
386 |
385 assertFails(IOE, webSocket.sendBinary(ByteBuffer.allocate(1), false)); |
387 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125))); |
386 |
388 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124))); |
387 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(125))); |
389 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1))); |
388 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(124))); |
390 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0))); |
389 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(1))); |
391 |
390 assertFails(IOE, webSocket.sendPing(ByteBuffer.allocate(0))); |
392 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125))); |
391 |
393 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
392 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(125))); |
394 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
393 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(124))); |
395 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
394 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(1))); |
396 |
395 assertFails(IOE, webSocket.sendPong(ByteBuffer.allocate(0))); |
397 server.close(); |
396 } finally { |
|
397 webSocket.abort(); |
|
398 } |
|
399 } |
398 } |
400 } |
399 |
401 |
400 // Used to verify a server requiring Authentication |
402 // Used to verify a server requiring Authentication |
401 private static final String USERNAME = "chegar"; |
403 private static final String USERNAME = "chegar"; |
402 private static final String PASSWORD = "a1b2c3"; |
404 private static final String PASSWORD = "a1b2c3"; |
456 0x80, 0x00, // ] |
458 0x80, 0x00, // ] |
457 0x88, 0x00 // <CLOSE> |
459 0x88, 0x00 // <CLOSE> |
458 }; |
460 }; |
459 CompletableFuture<List<byte[]>> actual = new CompletableFuture<>(); |
461 CompletableFuture<List<byte[]>> actual = new CompletableFuture<>(); |
460 |
462 |
461 server = serverSupplier.apply(binary); |
463 try (var server = serverSupplier.apply(binary)) { |
462 server.open(); |
464 server.open(); |
463 |
465 |
464 WebSocket.Listener listener = new WebSocket.Listener() { |
466 WebSocket.Listener listener = new WebSocket.Listener() { |
465 |
467 |
466 List<byte[]> collectedBytes = new ArrayList<>(); |
468 List<byte[]> collectedBytes = new ArrayList<>(); |
467 ByteBuffer buffer = ByteBuffer.allocate(1024); |
469 ByteBuffer buffer = ByteBuffer.allocate(1024); |
468 |
470 |
469 @Override |
471 @Override |
470 public CompletionStage<?> onBinary(WebSocket webSocket, |
472 public CompletionStage<?> onBinary(WebSocket webSocket, |
471 ByteBuffer message, |
473 ByteBuffer message, |
472 boolean last) { |
474 boolean last) { |
473 System.out.printf("onBinary(%s, %s)%n", message, last); |
475 System.out.printf("onBinary(%s, %s)%n", message, last); |
474 webSocket.request(1); |
476 webSocket.request(1); |
475 |
477 |
476 append(message); |
478 append(message); |
477 if (last) { |
479 if (last) { |
478 buffer.flip(); |
480 buffer.flip(); |
479 byte[] bytes = new byte[buffer.remaining()]; |
481 byte[] bytes = new byte[buffer.remaining()]; |
480 buffer.get(bytes); |
482 buffer.get(bytes); |
481 buffer.clear(); |
483 buffer.clear(); |
482 processWholeBinary(bytes); |
484 processWholeBinary(bytes); |
483 } |
485 } |
484 return null; |
486 return null; |
485 } |
487 } |
486 |
488 |
487 private void append(ByteBuffer message) { |
489 private void append(ByteBuffer message) { |
488 if (buffer.remaining() < message.remaining()) { |
490 if (buffer.remaining() < message.remaining()) { |
489 assert message.remaining() > 0; |
491 assert message.remaining() > 0; |
490 int cap = (buffer.capacity() + message.remaining()) * 2; |
492 int cap = (buffer.capacity() + message.remaining()) * 2; |
491 ByteBuffer b = ByteBuffer.allocate(cap); |
493 ByteBuffer b = ByteBuffer.allocate(cap); |
492 b.put(buffer.flip()); |
494 b.put(buffer.flip()); |
493 buffer = b; |
495 buffer = b; |
494 } |
496 } |
495 buffer.put(message); |
497 buffer.put(message); |
496 } |
498 } |
497 |
499 |
498 private void processWholeBinary(byte[] bytes) { |
500 private void processWholeBinary(byte[] bytes) { |
499 String stringBytes = new String(bytes, UTF_8); |
501 String stringBytes = new String(bytes, UTF_8); |
500 System.out.println("processWholeBinary: " + stringBytes); |
502 System.out.println("processWholeBinary: " + stringBytes); |
501 collectedBytes.add(bytes); |
503 collectedBytes.add(bytes); |
502 } |
504 } |
503 |
505 |
504 @Override |
506 @Override |
505 public CompletionStage<?> onClose(WebSocket webSocket, |
507 public CompletionStage<?> onClose(WebSocket webSocket, |
506 int statusCode, |
508 int statusCode, |
507 String reason) { |
509 String reason) { |
508 actual.complete(collectedBytes); |
510 actual.complete(collectedBytes); |
509 return null; |
511 return null; |
510 } |
512 } |
511 |
513 |
512 @Override |
514 @Override |
513 public void onError(WebSocket webSocket, Throwable error) { |
515 public void onError(WebSocket webSocket, Throwable error) { |
514 actual.completeExceptionally(error); |
516 actual.completeExceptionally(error); |
515 } |
517 } |
516 }; |
518 }; |
517 |
519 |
518 webSocket = newBuilder() |
520 var webSocket = newBuilder() |
519 .proxy(NO_PROXY) |
521 .proxy(NO_PROXY) |
520 .authenticator(new WSAuthenticator()) |
522 .authenticator(new WSAuthenticator()) |
521 .build().newWebSocketBuilder() |
523 .build().newWebSocketBuilder() |
522 .buildAsync(server.getURI(), listener) |
524 .buildAsync(server.getURI(), listener) |
523 .join(); |
525 .join(); |
524 |
526 try { |
525 List<byte[]> a = actual.join(); |
527 List<byte[]> a = actual.join(); |
526 assertEquals(a, expected); |
528 assertEquals(a, expected); |
527 |
529 } finally { |
528 server.close(); |
530 webSocket.abort(); |
|
531 } |
|
532 } |
529 } |
533 } |
530 |
534 |
531 @Test(dataProvider = "servers") |
535 @Test(dataProvider = "servers") |
532 public void simpleAggregatingTextMessages |
536 public void simpleAggregatingTextMessages |
533 (Function<int[],DummyWebSocketServer> serverSupplier) |
537 (Function<int[],DummyWebSocketServer> serverSupplier) |
637 0x80, 0x00, // " |
643 0x80, 0x00, // " |
638 0x88, 0x00 // <CLOSE> |
644 0x88, 0x00 // <CLOSE> |
639 }; |
645 }; |
640 CompletableFuture<List<String>> actual = new CompletableFuture<>(); |
646 CompletableFuture<List<String>> actual = new CompletableFuture<>(); |
641 |
647 |
642 server = serverSupplier.apply(binary); |
648 try (var server = serverSupplier.apply(binary)) { |
643 server.open(); |
649 server.open(); |
644 |
650 |
645 WebSocket.Listener listener = new WebSocket.Listener() { |
651 WebSocket.Listener listener = new WebSocket.Listener() { |
646 |
652 |
647 List<CharSequence> parts = new ArrayList<>(); |
653 List<CharSequence> parts = new ArrayList<>(); |
648 /* |
654 /* |
649 * A CompletableFuture which will complete once the current |
655 * A CompletableFuture which will complete once the current |
650 * message has been fully assembled. Until then the listener |
656 * message has been fully assembled. Until then the listener |
651 * returns this instance for every call. |
657 * returns this instance for every call. |
652 */ |
658 */ |
653 CompletableFuture<?> currentCf = new CompletableFuture<>(); |
659 CompletableFuture<?> currentCf = new CompletableFuture<>(); |
654 List<String> collected = new ArrayList<>(); |
660 List<String> collected = new ArrayList<>(); |
655 |
661 |
656 @Override |
662 @Override |
657 public CompletionStage<?> onText(WebSocket webSocket, |
663 public CompletionStage<?> onText(WebSocket webSocket, |
658 CharSequence message, |
664 CharSequence message, |
659 boolean last) { |
665 boolean last) { |
660 parts.add(message); |
666 parts.add(message); |
661 if (!last) { |
667 if (!last) { |
662 webSocket.request(1); |
668 webSocket.request(1); |
663 } else { |
669 } else { |
664 this.currentCf.thenRun(() -> webSocket.request(1)); |
670 this.currentCf.thenRun(() -> webSocket.request(1)); |
665 CompletableFuture<?> refCf = this.currentCf; |
671 CompletableFuture<?> refCf = this.currentCf; |
666 processWholeMessage(new ArrayList<>(parts), refCf); |
672 processWholeMessage(new ArrayList<>(parts), refCf); |
667 currentCf = new CompletableFuture<>(); |
673 currentCf = new CompletableFuture<>(); |
668 parts.clear(); |
674 parts.clear(); |
669 return refCf; |
675 return refCf; |
670 } |
676 } |
671 return currentCf; |
677 return currentCf; |
672 } |
678 } |
673 |
679 |
674 @Override |
680 @Override |
675 public CompletionStage<?> onClose(WebSocket webSocket, |
681 public CompletionStage<?> onClose(WebSocket webSocket, |
676 int statusCode, |
682 int statusCode, |
677 String reason) { |
683 String reason) { |
678 actual.complete(collected); |
684 actual.complete(collected); |
679 return null; |
685 return null; |
680 } |
686 } |
681 |
687 |
682 @Override |
688 @Override |
683 public void onError(WebSocket webSocket, Throwable error) { |
689 public void onError(WebSocket webSocket, Throwable error) { |
684 actual.completeExceptionally(error); |
690 actual.completeExceptionally(error); |
685 } |
691 } |
686 |
692 |
687 public void processWholeMessage(List<CharSequence> data, |
693 public void processWholeMessage(List<CharSequence> data, |
688 CompletableFuture<?> cf) { |
694 CompletableFuture<?> cf) { |
689 StringBuilder b = new StringBuilder(); |
695 StringBuilder b = new StringBuilder(); |
690 data.forEach(b::append); |
696 data.forEach(b::append); |
691 String s = b.toString(); |
697 String s = b.toString(); |
692 System.out.println(s); |
698 System.out.println(s); |
693 cf.complete(null); |
699 cf.complete(null); |
694 collected.add(s); |
700 collected.add(s); |
695 } |
701 } |
696 }; |
702 }; |
697 |
703 |
698 webSocket = newBuilder() |
704 var webSocket = newBuilder() |
699 .proxy(NO_PROXY) |
705 .proxy(NO_PROXY) |
700 .authenticator(new WSAuthenticator()) |
706 .authenticator(new WSAuthenticator()) |
701 .build().newWebSocketBuilder() |
707 .build().newWebSocketBuilder() |
702 .buildAsync(server.getURI(), listener) |
708 .buildAsync(server.getURI(), listener) |
703 .join(); |
709 .join(); |
704 |
710 try { |
705 List<String> a = actual.join(); |
711 List<String> a = actual.join(); |
706 assertEquals(a, expected); |
712 assertEquals(a, expected); |
707 |
713 } finally { |
708 server.close(); |
714 webSocket.abort(); |
|
715 } |
|
716 } |
709 } |
717 } |
710 |
718 |
711 // -- authentication specific tests |
719 // -- authentication specific tests |
712 |
720 |
713 /* |
721 /* |