blob: 4ef65c9fa1021105ede7ac42772dd46490492cb8 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.edgent.test.connectors.wsclient.javax.websocket;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.edgent.connectors.wsclient.WebSocketClient;
import org.apache.edgent.connectors.wsclient.javax.websocket.Jsr356WebSocketClient;
import org.apache.edgent.test.connectors.common.ConnectorTestBase;
import org.apache.edgent.test.connectors.common.TestRepoPath;
import org.apache.edgent.topology.TSink;
import org.apache.edgent.topology.TStream;
import org.apache.edgent.topology.Topology;
import org.apache.edgent.topology.json.JsonFunctions;
import org.apache.edgent.topology.plumbing.PlumbingStreams;
import org.apache.edgent.topology.tester.Condition;
import org.junit.After;
import org.junit.Test;
import com.google.gson.JsonObject;
//@Ignore("There seem to be issues with SSL related tests")
public class WebSocketClientTest extends ConnectorTestBase {
private final static int SEC_TMO = 5;
WebSocketServerEcho wsServer;
boolean isExternalServer;// = true;
int wsServerPort = !isExternalServer ? 0 : 49460;
String wsUriPath = "/echo"; // match what WsServerEcho is using
private final static String str1 = "one";
private final static String str2 = "two";
private final static String str3 = "three-post-reconnect";
private final static String str4 = "four";
public String getStr1() {
return str1;
}
public String getStr2() {
return str2;
}
public String getStr3() {
return str3;
}
public String getStr4() {
return str4;
}
@After
public void cleanup() {
if (wsServer != null)
wsServer.stop();
wsServer = null;
}
private enum ServerMode { WS, SSL, SSL_CLIENT_AUTH }
private void startEchoer() {
startEchoer(ServerMode.WS);
}
private void startEchoer(ServerMode mode) {
try {
if (!isExternalServer) {
URI uri;
if (mode==ServerMode.WS) {
uri = new URI("ws://localhost:0");
wsServer = new WebSocketServerEcho();
}
else {
uri = new URI("wss://localhost:0");
wsServer = new WebSocketServerEcho();
}
wsServer.start(uri, mode==ServerMode.SSL_CLIENT_AUTH);
wsServerPort = wsServer.getPort();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException("startEchoer",e );
}
}
private void restartEchoer(int secDelay) {
wsServer.restart(secDelay);
}
Properties getConfig() {
return getWsConfig();
}
Properties getWsConfig() {
Properties config = new Properties();
config.setProperty("ws.uri", getWsUri());
return config;
}
Properties getWssConfig() {
Properties config = new Properties();
config.setProperty("ws.uri", getWssUri());
config.setProperty("ws.trustStore", getStorePath("clientTrustStore.jks"));
config.setProperty("ws.trustStorePassword", "passw0rd");
config.setProperty("ws.keyStore", getStorePath("clientKeyStore.jks"));
config.setProperty("ws.keyStorePassword", "passw0rd");
// default: expect key to have the default alias
return config;
}
String getWsUri() {
int port = wsServerPort==0 ? 8080 : wsServerPort;
return "ws://localhost:"+port+wsUriPath;
}
String getWssUri() {
int port = wsServerPort==0 ? 443 : wsServerPort;
return "wss://localhost:"+port+wsUriPath;
}
private String getStorePath(String storeLeaf) {
return TestRepoPath.getPath("keystores/" + storeLeaf);
}
@Test
public void testBasicStaticStuff() {
Topology t = newTopology("testBasicStaticStuff");
Properties config = getConfig();
WebSocketClient wsClient1 = new Jsr356WebSocketClient(t, config);
TStream<String> s1 = wsClient1.receiveString();
assertNotNull("s1", s1);
TSink<String> sink1 = wsClient1.sendString(t.strings(getStr1(), getStr2()));
assertNotNull("sink1", sink1);
WebSocketClient wsClient2 = new Jsr356WebSocketClient(t, config);
TStream<String> s2 = wsClient2.receiveString();
assertNotSame("s1 s2", s1, s2);
TSink<String> sink2 = wsClient2.sendString(t.strings(getStr1(), getStr2()));
assertNotSame("sink1 sink2", sink1, sink2);
}
@Test(expected = IllegalArgumentException.class)
public void testMissingWsUri() {
Topology t = newTopology("testMissingWsUri");
new Jsr356WebSocketClient(t, new Properties());
}
@Test(expected = IllegalArgumentException.class)
public void testMalformedWsUri() {
Topology t = newTopology("testMalformedWsUri");
Properties config = new Properties();
config.setProperty("ws.uri", "localhost"); // missing scheme
new Jsr356WebSocketClient(t, config);
}
@Test(expected = IllegalArgumentException.class)
public void testNotWsUri() {
Topology t = newTopology("testNotWsUri");
Properties config = new Properties();
config.setProperty("ws.uri", "tcp://localhost");
new Jsr356WebSocketClient(t, config);
}
@Test(expected = IllegalArgumentException.class)
public void testWssTrustStorePasswordNeg() {
Topology t = newTopology("testWssTrustStorePasswordNeg");
Properties config = new Properties();
config.setProperty("ws.uri", getWssUri());
config.setProperty("ws.trustStore", "xyzzy"); // not checked till runtime
// missing trustStorePassword
new Jsr356WebSocketClient(t, config);
}
@Test(expected = IllegalArgumentException.class)
public void testWssKeyStorePasswordNeg() {
Topology t = newTopology("testWssKeyStorePasswordNeg");
Properties config = new Properties();
config.setProperty("ws.uri", getWssUri());
config.setProperty("ws.keyStore", "xyzzy"); // not checked till runtime
// missing keyStorePassword
new Jsr356WebSocketClient(t, config);
}
@Test
public void testWssConfig() {
Topology t = newTopology("testWssConfig");
Properties config = new Properties();
config.setProperty("ws.uri", getWssUri());
config.setProperty("ws.trustStore", "xyzzy"); // not checked till runtime
config.setProperty("ws.trustStorePassword", "xyzzy"); // not checked till runtime
new Jsr356WebSocketClient(t, config);
}
@Test(expected = IllegalStateException.class)
public void testTooManySendersNeg() {
Topology t = newTopology("testTooManySendersNeg");
TStream<String> s1 = t.strings(getStr1(), getStr2());
TStream<String> s2 = t.strings(getStr1(), getStr2());
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
wsClient.sendString(s1);
wsClient.sendString(s2); // should throw
}
@Test(expected = IllegalStateException.class)
public void testTooManyReceiversNeg() {
Topology t = newTopology("testTooManyReceiversNeg");
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
@SuppressWarnings("unused")
TStream<String> s1 = wsClient.receiveString();
@SuppressWarnings("unused")
TStream<String> s2 = wsClient.receiveString(); // should throw
}
@Test
public void testJson() throws Exception {
Topology t = newTopology("testJson");
System.out.println("===== "+t.getName());
startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] {
"{\"id\":\"" + getStr1() + "\",\"value\":27}",
"{\"id\":\"" + getStr2() + "\",\"value\":13}"
};
TStream<JsonObject> s = t.strings(expected)
.map(JsonFunctions.fromString());
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.send(s);
TStream<String> rcvd = wsClient.receive()
.map(JsonFunctions.asString());
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testString() throws Exception {
Topology t = newTopology("testString");
System.out.println("===== "+t.getName());
startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testBytes() throws Exception {
Topology t = newTopology("testBytes");
System.out.println("===== "+t.getName());
startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<byte[]> s = t.strings(expected)
.map(tup -> tup.getBytes(StandardCharsets.UTF_8));
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendBytes(s);
TStream<String> rcvd = wsClient.receiveBytes()
.map(tup -> new String(tup, StandardCharsets.UTF_8));
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testReconnect() throws Exception {
/*
* It's becomming apparent that the reconnect series of tests
* aren't reliable so skip them for ci. See jira EDGENT-122 for
* more info.
*/
assumeTrue(!Boolean.getBoolean("edgent.build.ci"));
Topology t = newTopology("testReconnect");
System.out.println("===== "+t.getName());
startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2(), getStr3(), getStr4() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
// send one, two, restart the server to force reconnect, send the next
AtomicInteger numSent = new AtomicInteger();
int restartAfterTupleCnt = 2;
CountDownLatch latch = new CountDownLatch(restartAfterTupleCnt);
s = s.filter(tuple -> {
if (numSent.getAndIncrement() != restartAfterTupleCnt )
return true;
else {
// to keep validation sane/simple wait till the tuples are rcvd before restarting
try { latch.await(); } catch (Exception e) {};
restartEchoer(2/*secDelay*/);
return true;
}
});
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString()
.peek(tuple -> latch.countDown());
completeAndValidate("", t, rcvd, SEC_TMO + 10, expected);
}
@Test
public void testReconnectBytes() throws Exception {
/*
* It's becomming apparent that the reconnect series of tests
* aren't reliable so skip them for ci. See jira EDGENT-122 for
* more info.
*/
assumeTrue(!Boolean.getBoolean("edgent.build.ci"));
Topology t = newTopology("testReconnectBytes");
System.out.println("===== "+t.getName());
startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2(), getStr3(), getStr4() };
TStream<byte[]> s = t.strings(expected).map(tup -> tup.getBytes(StandardCharsets.UTF_8));
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
// send one, two, restart the server to force reconnect, send the next
AtomicInteger numSent = new AtomicInteger();
int restartAfterTupleCnt = 2;
CountDownLatch latch = new CountDownLatch(restartAfterTupleCnt);
s = s.filter(tuple -> {
if (numSent.getAndIncrement() != restartAfterTupleCnt )
return true;
else {
// to keep validation sane/simple wait till the tuples are rcvd before restarting
try { latch.await(); } catch (Exception e) {};
restartEchoer(2/*secDelay*/);
return true;
}
});
wsClient.sendBytes(s);
TStream<String> rcvd = wsClient.receiveBytes()
.peek(tuple -> latch.countDown())
.map(tup -> new String(tup, StandardCharsets.UTF_8));
completeAndValidate("", t, rcvd, SEC_TMO + 10, expected);
}
private class SslSystemPropMgr {
private final Map<String,String> origProps = new HashMap<>();
public void set() {
set("javax.net.ssl.trustStore", getStorePath("clientTrustStore.jks"));
set("javax.net.ssl.trustStorePassword", "passw0rd");
set("javax.net.ssl.keyStore", getStorePath("clientKeyStore.jks"));
set("javax.net.ssl.keyStorePassword", "passw0rd");
}
private void set(String prop, String defaultVal) {
origProps.put(prop, System.setProperty(prop, defaultVal));
}
public void restore() {
restore("javax.net.ssl.trustStore");
restore("javax.net.ssl.trustStorePassword");
restore("javax.net.ssl.keyStore");
restore("javax.net.ssl.keyStorePassword");
}
private void restore(String prop) {
String origValue = origProps.get(prop);
if (origValue == null)
System.getProperties().remove(prop);
else
System.setProperty(prop, origValue);
}
}
@Test
public void testSslSystemProperty() throws Exception {
Topology t = newTopology("testSslSystemProperty");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL); // before getConfig() so it gets the port
Properties config = getConfig(); // no SSL config stuff
config.setProperty("ws.uri", getWssUri());
SslSystemPropMgr sslProps = new SslSystemPropMgr();
try {
// a trust store that contains the server's cert
sslProps.set();
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
finally {
sslProps.restore();
}
}
@Test
public void testSslClientAuthSystemProperty() throws Exception {
Topology t = newTopology("testSslClientAuthSystemProperty");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
Properties config = getConfig(); // no SSL config stuff
config.setProperty("ws.uri", getWssUri());
SslSystemPropMgr sslProps = new SslSystemPropMgr();
try {
// a trust store that contains the server's cert
sslProps.set();
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
finally {
sslProps.restore();
}
}
@Test
public void testSsl() throws Exception {
Topology t = newTopology("testSsl");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL); // before getConfig() so it gets the port
Properties config = getWssConfig();
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslReconnect() throws Exception {
/*
* It's becomming apparent that the reconnect series of tests
* aren't reliable so skip them for ci. See jira EDGENT-122 for
* more info.
*/
assumeTrue(!Boolean.getBoolean("edgent.build.ci"));
Topology t = newTopology("testSslReconnect");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL); // before getConfig() so it gets the port
Properties config = getWssConfig();
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2(), getStr3(), getStr4() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
// send one, two, restart the server to force reconnect, send the next
AtomicInteger numSent = new AtomicInteger();
int restartAfterTupleCnt = 2;
CountDownLatch latch = new CountDownLatch(restartAfterTupleCnt);
s = s.filter(tuple -> {
if (numSent.getAndIncrement() != restartAfterTupleCnt )
return true;
else {
// to keep validation sane/simple wait till the tuples are rcvd before restarting
try { latch.await(); } catch (Exception e) {};
restartEchoer(2/*secDelay*/);
return true;
}
});
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString()
.peek(tuple -> latch.countDown());
completeAndValidate("", t, rcvd, SEC_TMO + 10, expected);
}
@Test
public void testSslNeg() throws Exception {
Topology t = newTopology("testSslNeg");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL); // before getConfig() so it gets the port
// since our server uses a self-signed cert, if we don't have
// a truststore setup with it in it, the client will fail to connect
// and ultimately the connect will fail and the test will
// receive nothing.
Properties config = getConfig(); // no SSL config stuff
config.setProperty("ws.uri", getWssUri());
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString(); // rcv nothing
// in this case there's no useful condition that we can check for
// to validate this is behaving properly other than the connector doesn't
// blow up and that nothing is rcvd, so just wait a short time
// before verifying nothing was rcvd.
// Don't use the complete() TMO for successful termination.
Condition<List<String>> rcvdContent = t.getTester().streamContents(rcvd, new String[0]);
Condition<Object> tc = newWaitTimeCondition(3);
complete(t, tc, SEC_TMO, TimeUnit.SECONDS);
assertTrue("rcvd: "+rcvdContent.getResult(), rcvdContent.valid());
}
@Test
public void testSslClientAuth() throws Exception {
Topology t = newTopology("testSslClientAuth");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
Properties config = getWssConfig();
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslClientAuthDefault() throws Exception {
Topology t = newTopology("testSslClientAuthDefault");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
// explicitly specify client's "default" certificate
Properties config = getWssConfig();
config.setProperty("ws.keyCertificateAlias", "default");
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslClientAuthMy2ndCertNeg() throws Exception {
Topology t = newTopology("testSslClientAuthMy2ndCertNeg");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
// explicitly specify client's "my2ndcert" certificate - unknown to server
Properties config = getWssConfig();
config.setProperty("ws.keyCertificateAlias", "my2ndcert");
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString(); // rcv nothing
// in this case there's no useful condition that we can check for
// to validate this is behaving properly other than the connector doesn't
// blow up and that nothing is rcvd, so just wait a short time
// before verifying nothing was rcvd.
// Don't use the complete() TMO for successful termination.
Condition<List<String>> rcvdContent = t.getTester().streamContents(rcvd, new String[0]);
Condition<Object> tc = newWaitTimeCondition(3);
complete(t, tc, SEC_TMO, TimeUnit.SECONDS);
assertTrue("rcvd: "+rcvdContent.getResult(), rcvdContent.valid());
}
@Test
public void testSslClientAuthMy3rdCert() throws Exception {
Topology t = newTopology("testSslClientAuthMy3rdCert");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
// explicitly specify client's "my3rdcert" certificate
Properties config = getWssConfig();
config.setProperty("ws.keyCertificateAlias", "my3rdcert");
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslClientAuthNeg() throws Exception {
Topology t = newTopology("testSslClientAuthNeg");
System.out.println("===== "+t.getName());
startEchoer(ServerMode.SSL_CLIENT_AUTH); // before getConfig() so it gets the port
// since our server will require client auth, if we don't have
// a keystore setup with it in it, the client will fail to connect
// and ultimately the connect will fail and the test will
// receive nothing.
Properties config = getConfig(); // no SSL config stuff
config.setProperty("ws.uri", getWssUri());
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString(); // rcv nothing
// in this case there's no useful condition that we can check for
// to validate this is behaving properly other than the connector doesn't
// blow up and that nothing is rcvd, so just wait a short time
// before verifying nothing was rcvd.
// Don't use the complete() TMO for successful termination.
Condition<List<String>> rcvdContent = t.getTester().streamContents(rcvd, new String[0]);
Condition<Object> tc = newWaitTimeCondition(3);
complete(t, tc, SEC_TMO, TimeUnit.SECONDS);
assertTrue("rcvd: "+rcvdContent.getResult(), rcvdContent.valid());
}
private void skipTestIfCantConnect(Properties config) throws Exception {
String wsUri = config.getProperty("ws.uri");
// Skip tests if the WebSocket server can't be contacted.
try {
URI uri = new URI(wsUri);
int port = uri.getPort();
if (port == -1)
port = uri.getScheme().equals("ws") ? 80 : 443;
Socket s = new Socket();
s.connect(new InetSocketAddress(uri.getHost(), port), 5*1000/*cn-timeout-msec*/);
s.close();
} catch (Exception e) {
System.err.println("Unable to connect to WebSocket server "+wsUri+" : "+e.getMessage());
e.printStackTrace();
assumeTrue(false);
}
}
@Test
public void testPublicServer() throws Exception {
Topology t = newTopology("testPublicServer");
System.out.println("===== "+t.getName());
// startEchoer(); // before getConfig() so it gets the port
Properties config = getConfig();
config.setProperty("ws.uri", "ws://echo.websocket.org");
skipTestIfCantConnect(config);
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslPublicServer() throws Exception {
Topology t = newTopology("testSslPublicServer");
System.out.println("===== "+t.getName());
// startEchoer(); // before getConfig() so it gets the port
// Check operation against a trusted CA signed server certificate.
//
// this public wss echo server should "just work" if you have
// connectivity. no additional ssl trustStore config is needed
// as the site has a certificate signed by a recognized CA.
Properties config = getConfig();
config.setProperty("ws.uri", "wss://echo.websocket.org");
skipTestIfCantConnect(config);
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString();
completeAndValidate("", t, rcvd, SEC_TMO, expected);
}
@Test
public void testSslPublicServerBadTrustStoreSystemPropertyNeg() throws Exception {
Topology t = newTopology("testSslPublicServerBadTrustStoreSystemPropertyNeg");
System.out.println("===== "+t.getName());
// startEchoer(); // before getConfig() so it gets the port
// this public wss echo server should "just work" if you have
// connectivity. no additional ssl trustStore config is needed
// as the site has a certificate signed by a recognized CA.
// Set a trust store that doesn't contain the public server's cert nor CAs
// and ultimately the connect will fail and the test will
// receive nothing.
Properties config = getConfig();
config.setProperty("ws.uri", "wss://echo.websocket.org");
skipTestIfCantConnect(config);
SslSystemPropMgr sslProps = new SslSystemPropMgr();
try {
sslProps.set();
// System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
WebSocketClient wsClient = new Jsr356WebSocketClient(t, config);
String[] expected = new String[] { getStr1(), getStr2() };
TStream<String> s = t.strings(expected);
s = PlumbingStreams.blockingOneShotDelay(s, 2, TimeUnit.SECONDS);
wsClient.sendString(s);
TStream<String> rcvd = wsClient.receiveString(); // rcv nothing
// in this case there's no useful condition that we can check for
// to validate this is behaving properly other than the connector doesn't
// blow up and that nothing is rcvd, so just wait a short time
// before verifying nothing was rcvd.
// Don't use the complete() TMO for successful termination.
Condition<List<String>> rcvdContent = t.getTester().streamContents(rcvd, new String[0]);
Condition<Object> tc = newWaitTimeCondition(3);
complete(t, tc, SEC_TMO, TimeUnit.SECONDS);
assertTrue("rcvd: "+rcvdContent.getResult(), rcvdContent.valid());
}
finally {
sslProps.restore();
}
}
}