package de.widdix.awsec2ssh;

import com.evanlennick.retry4j.CallExecutor;
import com.evanlennick.retry4j.CallResults;
import com.evanlennick.retry4j.RetryConfig;
import com.evanlennick.retry4j.RetryConfigBuilder;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.junit.Assert;

import java.time.temporal.ChronoUnit;
import java.util.concurrent.Callable;

public abstract class ATest {

    protected final <T> T retry(Callable<T> callable) {
        final Callable<T> wrapper = () -> {
            try {
                return callable.call();
            } catch (final Exception e) {
                System.out.println("retry[] exception: " + e.getMessage());
                e.printStackTrace();
                throw e;
            }
        };
        final RetryConfig config = new RetryConfigBuilder()
                .retryOnAnyException()
                .withMaxNumberOfTries(30)
                .withDelayBetweenTries(10, ChronoUnit.SECONDS)
                .withFixedBackoff()
                .build();
        final CallResults<Object> results = new CallExecutor(config).execute(wrapper);
        return (T) results.getResult();
    }

    public static final class User {
        public final String userName;
        public final byte[] sshPrivateKeyBlob;
        public final String sshPublicKeyId;
        public User(final String userName, final byte[] sshPrivateKeyBlob, final String sshPublicKeyId) {
            super();
            this.userName = userName;
            this.sshPrivateKeyBlob = sshPrivateKeyBlob;
            this.sshPublicKeyId = sshPublicKeyId;
        }
    }

    protected final void probeSSH(final String host, final User user) {
        final Callable<Boolean> callable = () -> {
            final JSch jsch = new JSch();
            final Session session = jsch.getSession(user.userName, host);
            jsch.addIdentity(user.userName, user.sshPrivateKeyBlob, null, null);
            jsch.setConfig("StrictHostKeyChecking", "no"); // for testing this should be fine. adding the host key seems to be only possible via a file which is not very useful here
            session.connect(10000);
            session.disconnect();
            return true;
        };
        Assert.assertTrue(this.retry(callable));
    }

}

@@ -23,16 +23,65 @@
 c2ssh;%0A%0A
+import com.amazonaws.services.ec2.model.KeyPair;%0A
 import c
@@ -285,16 +285,54 @@
 h.JSch;%0A
+import com.jcraft.jsch.JSchException;%0A
 import c
@@ -456,16 +456,66 @@
 allable;
+%0Aimport java.util.concurrent.atomic.AtomicInteger;
 %0A%0Apublic
@@ -571,16 +571,45 @@
 T retry(
+final Context context, final 
 Callable
@@ -620,24 +620,78 @@
 callable) %7B%0A
+        final AtomicInteger t = new AtomicInteger(0);%0A
         fina
@@ -864,16 +864,43 @@
 (%22retry%5B
+%22 + t.incrementAndGet() + %22
 %5D except
@@ -959,16 +959,64 @@
 ckTrace(
+System.out);%0A                System.out.println(
 );%0A     
@@ -1322,24 +1322,42 @@
   .build();%0A
+        try %7B%0A    
         fina
@@ -1435,24 +1435,28 @@
 r);%0A        
+    
 return (T) r
@@ -1471,24 +1471,137 @@
 etResult();%0A
+        %7D catch (final RuntimeException e) %7B%0A            context.reportFailure();%0A            throw e;%0A        %7D%0A
     %7D%0A%0A    p
@@ -1753,32 +1753,33 @@
 sshPublicKeyId;%0A
+%0A
         public U
@@ -2086,24 +2086,47 @@
 beSSH(final 
+Context context, final 
 String host,
@@ -2711,29 +2711,1484 @@
 rue(
-this.retry(callable))
+%22successful SSH connection%22, this.retry(context, callable));%0A    %7D%0A%0A    protected final void probeSSH(final Context context, final String host, final KeyPair key) %7B%0A        final Callable%3CBoolean%3E callable = () -%3E %7B%0A            final JSch jsch = new JSch();%0A            final Session session = jsch.getSession(%22ec2-user%22, host);%0A            jsch.addIdentity(key.getKeyName(), key.getKeyMaterial().getBytes(), null, null);%0A            jsch.setConfig(%22StrictHostKeyChecking%22, %22no%22); // for testing this should be fine. adding the host key seems to be only possible via a file which is not very useful here%0A            session.connect(10000);%0A            session.disconnect();%0A            return true;%0A        %7D;%0A        Assert.assertTrue(%22successful SSH connection%22, this.retry(context, callable));%0A    %7D%0A%0A    protected final Session tunnelSSH(final String host, final KeyPair key, final Integer localPort, final String remoteHost, final Integer remotePort) throws JSchException %7B%0A        final JSch jsch = new JSch();%0A        final Session session = jsch.getSession(%22ec2-user%22, host);%0A        jsch.addIdentity(key.getKeyName(), key.getKeyMaterial().getBytes(), null, null);%0A        jsch.setConfig(%22StrictHostKeyChecking%22, %22no%22); // for testing this should be fine. adding the host key seems to be only possible via a file which is not very useful here%0A        session.setPortForwardingL(localPort, remoteHost, remotePort);%0A        session.connect(10000);%0A        return session
 ;%0A  

improve test suite