<javax.portlet.version>2.0</javax.portlet.version> | <javax.portlet.version>2.0</javax.portlet.version> | ||||
<vaadin.sass.version>0.9.13</vaadin.sass.version> | <vaadin.sass.version>0.9.13</vaadin.sass.version> | ||||
<!-- Note that this should be kept in sync with the class Constants --> | <!-- Note that this should be kept in sync with the class Constants --> | ||||
<atmosphere.runtime.version>2.4.24.vaadin1</atmosphere.runtime.version> | |||||
<atmosphere.runtime.version>2.4.30.vaadin1</atmosphere.runtime.version> | |||||
<!-- OSGi --> | <!-- OSGi --> | ||||
<osgi.execution.environment>JavaSE-1.8</osgi.execution.environment> | <osgi.execution.environment>JavaSE-1.8</osgi.execution.environment> | ||||
<artifactId>jetty-proxy</artifactId> | <artifactId>jetty-proxy</artifactId> | ||||
<version>${jetty.version}</version> | <version>${jetty.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jcraft</groupId> | |||||
<artifactId>jsch</artifactId> | |||||
<version>0.1.52</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>org.eclipse.jgit</groupId> | <groupId>org.eclipse.jgit</groupId> | ||||
<artifactId>org.eclipse.jgit</artifactId> | <artifactId>org.eclipse.jgit</artifactId> |
+ "================================================================="; | + "================================================================="; | ||||
// Keep the version number in sync with pom.xml | // Keep the version number in sync with pom.xml | ||||
static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.4.24.vaadin1"; | |||||
static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.4.30.vaadin1"; | |||||
static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n" | static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n" | ||||
+ "=================================================================\n" | + "=================================================================\n" |
<scope>provided</scope> | <scope>provided</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jcraft</groupId> | |||||
<artifactId>jsch</artifactId> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>commons-codec</groupId> | <groupId>commons-codec</groupId> | ||||
<artifactId>commons-codec</artifactId> | <artifactId>commons-codec</artifactId> |
import org.openqa.selenium.By; | import org.openqa.selenium.By; | ||||
import org.openqa.selenium.WebElement; | import org.openqa.selenium.WebElement; | ||||
import com.jcraft.jsch.JSchException; | |||||
import com.vaadin.testbench.elements.ButtonElement; | import com.vaadin.testbench.elements.ButtonElement; | ||||
import com.vaadin.testbench.parallel.TestCategory; | |||||
import com.vaadin.tests.tb3.MultiBrowserTestWithProxy; | import com.vaadin.tests.tb3.MultiBrowserTestWithProxy; | ||||
@TestCategory("needs-ssh") | |||||
import java.io.IOException; | |||||
public class ReconnectDialogUITest extends MultiBrowserTestWithProxy { | public class ReconnectDialogUITest extends MultiBrowserTestWithProxy { | ||||
@Test | @Test | ||||
public void reconnectTogglesBodyStyle() throws JSchException { | |||||
public void reconnectTogglesBodyStyle() throws IOException { | |||||
openTestURL(); | openTestURL(); | ||||
getButton().click(); | getButton().click(); | ||||
disconnectProxy(); | disconnectProxy(); | ||||
} | } | ||||
@Test | @Test | ||||
public void reconnectDialogShownAndDisappears() throws JSchException { | |||||
public void reconnectDialogShownAndDisappears() throws IOException { | |||||
openTestURL(); | openTestURL(); | ||||
getButton().click(); | getButton().click(); | ||||
assertEquals("1. Hello from the server", getLogRow(0)); | assertEquals("1. Hello from the server", getLogRow(0)); |
public class PushVersionInfoTest extends SingleBrowserTest { | public class PushVersionInfoTest extends SingleBrowserTest { | ||||
@Test | @Test | ||||
public void testDisabledPush() { | |||||
public void testDisabledPush() throws InterruptedException { | |||||
setDebug(true); | setDebug(true); | ||||
openTestURL(); | openTestURL(); | ||||
selectInfoTab(); | selectInfoTab(); | ||||
Thread.sleep(500); | |||||
assertNull("Found push info server string for disabled Push", | assertNull("Found push info server string for disabled Push", | ||||
getPushRowValue("Push server version")); | getPushRowValue("Push server version")); | ||||
assertNull("Found push info client string for disabled Push", | assertNull("Found push info client string for disabled Push", | ||||
} | } | ||||
@Test | @Test | ||||
public void testEnabledPush() { | |||||
public void testEnabledPush() throws InterruptedException { | |||||
setDebug(true); | setDebug(true); | ||||
openTestURL("enablePush=true"); | openTestURL("enablePush=true"); | ||||
selectInfoTab(); | selectInfoTab(); | ||||
Thread.sleep(500); | |||||
WebElement pushRow = getPushRowValue("Push server version"); | WebElement pushRow = getPushRowValue("Push server version"); | ||||
String atmVersion = findElement(By.className("atmosphere-version")) | String atmVersion = findElement(By.className("atmosphere-version")) | ||||
.getText(); | .getText(); |
import org.junit.Test; | import org.junit.Test; | ||||
import org.openqa.selenium.By; | import org.openqa.selenium.By; | ||||
import org.openqa.selenium.NoSuchElementException; | |||||
import org.openqa.selenium.WebElement; | import org.openqa.selenium.WebElement; | ||||
import com.vaadin.testbench.parallel.TestCategory; | import com.vaadin.testbench.parallel.TestCategory; | ||||
} | } | ||||
protected void waitUntilClientCounterChanges(final int expectedValue) { | protected void waitUntilClientCounterChanges(final int expectedValue) { | ||||
waitUntil( | |||||
input -> BasicPushTest | |||||
.getClientCounter(BasicPushTest.this) == expectedValue, | |||||
waitUntil(input -> { | |||||
try { | |||||
return BasicPushTest | |||||
.getClientCounter(BasicPushTest.this) == expectedValue; | |||||
} catch (NoSuchElementException e) { | |||||
return false; | |||||
} | |||||
}, | |||||
10); | 10); | ||||
} | } | ||||
package com.vaadin.tests.push; | package com.vaadin.tests.push; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.openqa.selenium.NoSuchElementException; | |||||
import org.openqa.selenium.WebElement; | import org.openqa.selenium.WebElement; | ||||
import com.jcraft.jsch.JSchException; | |||||
import com.vaadin.tests.tb3.MultiBrowserTestWithProxy; | import com.vaadin.tests.tb3.MultiBrowserTestWithProxy; | ||||
import java.io.IOException; | |||||
public abstract class ReconnectTest extends MultiBrowserTestWithProxy { | public abstract class ReconnectTest extends MultiBrowserTestWithProxy { | ||||
@Override | @Override | ||||
} | } | ||||
@Test | @Test | ||||
public void messageIsQueuedOnDisconnect() throws JSchException { | |||||
public void messageIsQueuedOnDisconnect() throws IOException { | |||||
disconnectProxy(); | disconnectProxy(); | ||||
clickButtonAndWaitForTwoReconnectAttempts(); | clickButtonAndWaitForTwoReconnectAttempts(); | ||||
@Test | @Test | ||||
public void messageIsNotSentBeforeConnectionIsEstablished() | public void messageIsNotSentBeforeConnectionIsEstablished() | ||||
throws JSchException, InterruptedException { | |||||
throws IOException, InterruptedException { | |||||
disconnectProxy(); | disconnectProxy(); | ||||
waitForNextReconnectionAttempt(); | waitForNextReconnectionAttempt(); | ||||
waitForDebugMessage("Reopening push connection"); | waitForDebugMessage("Reopening push connection"); | ||||
} | } | ||||
private void connectAndVerifyConnectionEstablished() throws JSchException { | |||||
private void connectAndVerifyConnectionEstablished() throws IOException { | |||||
connectProxy(); | connectProxy(); | ||||
waitUntilServerCounterChanges(); | waitUntilServerCounterChanges(); | ||||
} | } | ||||
private void waitUntilServerCounterChanges() { | private void waitUntilServerCounterChanges() { | ||||
final int counter = BasicPushTest.getServerCounter(this); | final int counter = BasicPushTest.getServerCounter(this); | ||||
waitUntil(input -> BasicPushTest | |||||
.getServerCounter(ReconnectTest.this) > counter, 30); | |||||
waitUntil(input -> { | |||||
try { | |||||
return BasicPushTest | |||||
.getServerCounter(ReconnectTest.this) > counter; | |||||
} catch (NoSuchElementException e) { | |||||
return false; | |||||
} | |||||
}, 30); | |||||
} | } | ||||
private void waitUntilClientCounterChanges(final int expectedValue) { | private void waitUntilClientCounterChanges(final int expectedValue) { |
protected void openDebugLogTab() { | protected void openDebugLogTab() { | ||||
waitUntil(input -> { | waitUntil(input -> { | ||||
WebElement element = getDebugLogButton(); | |||||
return element != null; | |||||
try { | |||||
WebElement element = getDebugLogButton(); | |||||
return element != null; | |||||
} catch (NoSuchElementException e) { | |||||
return false; | |||||
} | |||||
}, 15); | }, 15); | ||||
getDebugLogButton().click(); | getDebugLogButton().click(); | ||||
} | } |
package com.vaadin.tests.tb3; | package com.vaadin.tests.tb3; | ||||
import java.io.File; | |||||
import java.util.concurrent.atomic.AtomicInteger; | |||||
import com.vaadin.testbench.parallel.TestCategory; | |||||
import org.junit.After; | import org.junit.After; | ||||
import com.jcraft.jsch.JSch; | |||||
import com.jcraft.jsch.JSchException; | |||||
import com.jcraft.jsch.Session; | |||||
import com.vaadin.testbench.parallel.TestCategory; | |||||
import java.io.IOException; | |||||
import java.util.concurrent.atomic.AtomicInteger; | |||||
@TestCategory("push") | @TestCategory("push") | ||||
public abstract class MultiBrowserTestWithProxy extends MultiBrowserTest { | public abstract class MultiBrowserTestWithProxy extends MultiBrowserTest { | ||||
private static AtomicInteger availablePort = new AtomicInteger(2000); | private static AtomicInteger availablePort = new AtomicInteger(2000); | ||||
private Session proxySession; | |||||
private SimpleProxy proxySession; | |||||
private Integer proxyPort = null; | private Integer proxyPort = null; | ||||
private JSch jsch; | |||||
private static String sshDir = System.getProperty("user.home") + "/.ssh/"; | |||||
private String[] publicKeys = { System.getProperty("sshkey.file"), | |||||
sshDir + "id_rsa", sshDir + "id_dsa", sshDir + "id_rsa2" }; | |||||
@Override | @Override | ||||
public void setup() throws Exception { | public void setup() throws Exception { | ||||
/** | /** | ||||
* Ensure the proxy is active. Does nothing if the proxy is already active. | * Ensure the proxy is active. Does nothing if the proxy is already active. | ||||
*/ | */ | ||||
protected void connectProxy() throws JSchException { | |||||
protected void connectProxy() throws IOException { | |||||
if (proxySession != null) { | if (proxySession != null) { | ||||
return; | return; | ||||
} | } | ||||
try { | try { | ||||
createProxy(getProxyPort()); | createProxy(getProxyPort()); | ||||
break; | break; | ||||
} catch (JSchException e) { | |||||
} catch (IOException e) { | |||||
sleep(500); | sleep(500); | ||||
if (i == 9) { | if (i == 9) { | ||||
throw new RuntimeException( | throw new RuntimeException( | ||||
} | } | ||||
} | } | ||||
private void createProxy(int proxyPort) throws JSchException { | |||||
if (jsch == null) { | |||||
jsch = new JSch(); | |||||
String keyFile = null; | |||||
for (String publicKey : publicKeys) { | |||||
if (publicKey != null) { | |||||
if (new File(publicKey).exists()) { | |||||
keyFile = publicKey; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
jsch.addIdentity(keyFile); | |||||
} | |||||
proxySession = jsch.getSession("localhost"); | |||||
proxySession.setConfig("StrictHostKeyChecking", "no"); | |||||
proxySession.setPortForwardingL("0.0.0.0", proxyPort, | |||||
super.getDeploymentHostname(), super.getDeploymentPort()); | |||||
proxySession.connect(); | |||||
private void createProxy(int proxyPort) throws IOException { | |||||
proxySession = new SimpleProxy(proxyPort, getDeploymentHostname(), | |||||
getDeploymentPort()); | |||||
proxySession.start(); | |||||
} | } | ||||
@Override | @Override |
package com.vaadin.tests.tb3; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.OutputStream; | |||||
import java.net.InetAddress; | |||||
import java.net.ServerSocket; | |||||
import java.net.Socket; | |||||
import java.net.SocketException; | |||||
import java.util.Queue; | |||||
import java.util.concurrent.ConcurrentLinkedQueue; | |||||
public class SimpleProxy extends Thread { | |||||
private final ThreadGroup proxyThreads; | |||||
private final Queue<Socket> sockets = new ConcurrentLinkedQueue<>(); | |||||
private final ServerSocket serverSocket; | |||||
private final String remoteHost; | |||||
private final int remotePort; | |||||
public SimpleProxy(int localPort, String remoteHost, int remotePort) | |||||
throws IOException { | |||||
super(new ThreadGroup("proxy " + localPort), "server"); | |||||
this.remoteHost = remoteHost; | |||||
this.remotePort = remotePort; | |||||
proxyThreads = getThreadGroup(); | |||||
serverSocket = new ServerSocket(localPort, 100, | |||||
InetAddress.getByName("0.0.0.0")); | |||||
setDaemon(true); | |||||
} | |||||
@Override | |||||
public void run() { | |||||
try { | |||||
while (!isInterrupted() && !serverSocket.isClosed()) { | |||||
try { | |||||
Socket proxySocket = serverSocket.accept(); | |||||
sockets.add(proxySocket); | |||||
Socket remoteSocket = new Socket(remoteHost, remotePort); | |||||
sockets.add(remoteSocket); | |||||
new CopySocket(proxyThreads, proxySocket, remoteSocket) | |||||
.start(); | |||||
new CopySocket(proxyThreads, remoteSocket, proxySocket) | |||||
.start(); | |||||
} catch (SocketException e) { | |||||
if (!serverSocket.isClosed()) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} catch (IOException e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
} finally { | |||||
disconnect(); | |||||
} | |||||
} | |||||
public void disconnect() { | |||||
proxyThreads.interrupt(); | |||||
for (Socket socket : sockets) { | |||||
try { | |||||
socket.close(); | |||||
} catch (IOException ignored) { | |||||
} | |||||
} | |||||
try { | |||||
serverSocket.close(); | |||||
} catch (IOException ignored) { | |||||
} | |||||
} | |||||
private class CopySocket extends Thread { | |||||
private final InputStream inputStream; | |||||
private final OutputStream outputStream; | |||||
private CopySocket(ThreadGroup proxyThreads, Socket srcSocket, | |||||
Socket dstSocket) throws IOException { | |||||
super(proxyThreads, "proxy worker"); | |||||
setDaemon(true); | |||||
inputStream = srcSocket.getInputStream(); | |||||
outputStream = dstSocket.getOutputStream(); | |||||
} | |||||
@Override | |||||
public void run() { | |||||
try { | |||||
for (int b; (b = inputStream.read()) >= 0;) { | |||||
outputStream.write(b); | |||||
} | |||||
} catch (SocketException ignored) { | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
try { | |||||
inputStream.close(); | |||||
} catch (IOException ignored) { | |||||
} | |||||
try { | |||||
outputStream.close(); | |||||
} catch (IOException ignored) { | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |