blob: 183ebb8d9c50f9189bafae78afaaed4037ef0f5b [file] [log] [blame]
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.incubator.http.internal.websocket;
import org.testng.SkipException;
import org.testng.annotations.Test;
import jdk.incubator.http.internal.websocket.Frame.Opcode;
import java.io.IOException;
import java.net.ProtocolException;
import jdk.incubator.http.WebSocket;
import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static jdk.incubator.http.internal.websocket.TestSupport.Expectation.ifExpect;
import static jdk.incubator.http.internal.websocket.TestSupport.assertCompletesExceptionally;
import static jdk.incubator.http.internal.websocket.TestSupport.checkExpectations;
import static org.testng.Assert.assertSame;
/*
* Examines sendPing/onPing contracts
*/
public final class PingTest {
/*
* sendPing(message) is invoked. If the `message` argument is illegal, then
* the method must throw an appropriate exception. Otherwise no exception
* must be thrown.
*/
// @Test(dataProvider = "outgoingData", dataProviderClass = DataProviders.class)
public void testSendPingArguments(ByteBuffer message) {
WebSocket ws = newWebSocket();
ifExpect(
message == null,
NullPointerException.class::isInstance)
.orExpect(
message != null && message.remaining() > 125,
IllegalArgumentException.class::isInstance)
.assertThrows(
() -> ws.sendPing(message)
);
}
/*
* sendPing(message) with a legal argument has been invoked, then:
*
* 1. A Ping message with the same payload appears on the wire
* 2. The CF returned from the method completes normally with the same
* WebSocket that sendPing has been called on
*/
@Test(dataProvider = "outgoingData", dataProviderClass = DataProviders.class)
public void testSendPingWysiwyg(ByteBuffer message) throws ExecutionException, InterruptedException {
if (message == null || message.remaining() > 125) {
return;
}
ByteBuffer snapshot = copy(message);
MockChannel channel = new MockChannel.Builder()
.expectPing(snapshot::equals)
.build();
WebSocket ws = newWebSocket(channel);
CompletableFuture<WebSocket> cf = ws.sendPing(message);
WebSocket ws1 = cf.join();
assertSame(ws1, ws); // (2)
checkExpectations(channel); // (1)
}
/*
* If an I/O error occurs while Ping messages is being sent, then:
*
* 1. The CF returned from sendPing completes exceptionally with this I/O
* error as the cause
*/
// @Test
public void testSendPingIOException() {
MockChannel ch = new MockChannel.Builder()
// .provideWriteException(IOException::new)
.build();
WebSocket ws = newWebSocket(ch);
CompletableFuture<WebSocket> cf = ws.sendPing(ByteBuffer.allocate(16));
assertCompletesExceptionally(IOException.class, cf);
}
/*
* If an incorrect Ping frame appears on the wire, then:
*
* 1. onError with the java.net.ProtocolException is invoked
* 1. A Close frame with status code 1002 appears on the wire
*/
// @Test(dataProvider = "incorrectFrame", dataProviderClass = DataProviders.class)
public void testOnPingIncorrect(boolean fin, boolean rsv1, boolean rsv2,
boolean rsv3, ByteBuffer data) {
if (fin && !rsv1 && !rsv2 && !rsv3 && data.remaining() <= 125) {
throw new SkipException("Correct frame");
}
CompletableFuture<WebSocket> webSocket = new CompletableFuture<>();
MockChannel channel = new MockChannel.Builder()
.provideFrame(fin, rsv1, rsv2, rsv3, Opcode.PING, data)
.expectClose((code, reason) ->
Integer.valueOf(1002).equals(code) && "".equals(reason))
.build();
MockListener listener = new MockListener.Builder()
.expectOnOpen((ws) -> true)
.expectOnError((ws, error) -> error instanceof ProtocolException)
.build();
webSocket.complete(newWebSocket(channel, listener));
checkExpectations(500, TimeUnit.MILLISECONDS, channel, listener);
}
/*
* If a Ping message has been read off the wire, then:
*
* 1. onPing is invoked with the data and the WebSocket the listener has
* been attached to
* 2. A Pong message with the same contents will be sent in reply
*/
@Test(dataProvider = "incomingData", dataProviderClass = DataProviders.class)
public void testOnPingReply(ByteBuffer data) {
CompletableFuture<WebSocket> webSocket = new CompletableFuture<>();
MockChannel channel = new MockChannel.Builder()
.provideFrame(true, false, false, false, Opcode.PING, data)
.expectPong(data::equals)
.build();
MockListener listener = new MockListener.Builder()
.expectOnOpen((ws) -> true) // maybe should capture with a CF?
.expectOnPing((ws, bb) -> data.equals(bb))
.build();
webSocket.complete(newWebSocket(channel, listener));
checkExpectations(500, TimeUnit.MILLISECONDS, channel, listener);
}
/*
* If onPing throws an exception or CS returned from it completes
* exceptionally, then:
*
* 1. onError is invoked with this particular exception as the cause and the
* WebSocket the listener has been attached to
*/
public void testOnPingExceptions() {
}
/*
* If a Ping message has been read off the wire and an I/O error occurs
* while WebSocket sends a Pong reply to it, then:
*
* 1. onError is invoked with this error as the cause and the WebSocket this
* listener has been attached to
*/
public void testOnPingReplyIOException() {
}
private WebSocket newWebSocket() {
return newWebSocket(new MockChannel.Builder().build());
}
private WebSocket newWebSocket(RawChannel ch) {
return newWebSocket(ch, new WebSocket.Listener() { });
}
private WebSocket newWebSocket(RawChannel ch, WebSocket.Listener l) {
// WebSocketImpl ws = new WebSocketImpl("", ch, l, Executors.newCachedThreadPool());
// ws.();
// ws.request(Long.MAX_VALUE);
return null; // FIXME
}
public static ByteBuffer copy(ByteBuffer src) {
int pos = src.position();
ByteBuffer b = ByteBuffer.allocate(src.remaining()).put(src).flip();
src.position(pos);
return b;
}
}