All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fitnesse.testsystems.slim.SlimClientBuilder Maven / Gradle / Ivy

There is a newer version: 20240707
Show newest version
package fitnesse.testsystems.slim;

import fitnesse.FitNesseContext;
import fitnesse.slim.SlimPipeSocket;
import fitnesse.socketservice.*;
import fitnesse.testsystems.*;
import org.apache.commons.lang3.ArrayUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicInteger;

import static fitnesse.slim.SlimPipeSocket.STDERR_PREFIX;
import static fitnesse.slim.SlimPipeSocket.STDOUT_PREFIX;

public class SlimClientBuilder extends ClientBuilder {
  public static final String SLIM_PORT = "SLIM_PORT";
  public static final String SLIM_HOST = "SLIM_HOST";
  public static final String SLIM_FLAGS = "SLIM_FLAGS";
  private static final String SLIM_VERSION = "SLIM_VERSION";
  public static final String MANUALLY_START_TEST_RUNNER_ON_DEBUG = "MANUALLY_START_TEST_RUNNER_ON_DEBUG";
  public static final String MANUALLY_START_TEST_RUNNER = "MANUALLY_START_TEST_RUNNER";
  public static final String SLIM_SSL = "SLIM_SSL";
  public static final int SLIM_USE_PIPE_PORT = 1;

  private static final AtomicInteger slimPortOffset = new AtomicInteger(0);


  private int slimPort;

  public SlimClientBuilder(Descriptor descriptor) {
    super(descriptor);
    slimPort = getNextSlimPort();
  }

  @Override
  public SlimCommandRunningClient build() {
    CommandRunner commandRunner = determineCommandRunner();

    return new SlimCommandRunningClient(commandRunner, determineSlimHost(),
        getSlimPort(), determineTimeout(), getSlimVersion(),
        determineSocketFactory(commandRunner));

  }

  protected CommandRunner determineCommandRunner() {
    if (getSlimPort() == SLIM_USE_PIPE_PORT) {
      // Wrap executionLogListener
      return new CommandRunner(buildCommand(),
        createClasspathEnvironment(getClassPath()),
          getExecutionLogListener(), determineTimeout()) {

        @Override
        protected void redirectOutputs(Process process, final ExecutionLogListener executionLogListener) throws IOException {
          InputStream stderr = process.getErrorStream();
          new Thread(new OutputReadingRunnable(stderr, new OutputWriter() {
            @Override
            public void write(String output) {
              // Separate StdOut and StdErr and remove prefix"
              String originalMsg;
              originalMsg = extractOriginalMessage(output, STDOUT_PREFIX);
              if (originalMsg != null) {
                executionLogListener.stdOut(originalMsg);
              } else {
                originalMsg = extractOriginalMessage(output, STDERR_PREFIX);
                if (originalMsg != null) {
                  executionLogListener.stdErr(originalMsg);
                  setCommandErrorMessage(originalMsg);
                } else {
                  executionLogListener.stdOut(output);
                }
              }
            }

            /**
             * This reverts the wrap that the LoggingOutputStream.flush method
             * is doing.
             *
             * @param prefixedMessage
             * @param level
             * @return == null : the message is not prefixed with the given
             *         level != null : the original message content
             */
            private String extractOriginalMessage(String prefixedMessage,
                String level) {
              if (prefixedMessage.startsWith(level))
                return prefixedMessage.substring(level.length()
                    + SlimPipeSocket.FOLLOWING_LINE_PREFIX.length());
              return null;
            }

          }), "CommandRunner stdOutErr").start();

        }
      };

    } else if (useManualStartForTestSystem()) {
      return new MockCommandRunner(
          "Connection to running SlimService: " + determineSlimHost() + ":"
              + getSlimPort(), getExecutionLogListener(), determineTimeout());
    } else {
      return new CommandRunner(buildCommand(), createClasspathEnvironment(getClassPath()), getExecutionLogListener(), determineTimeout());
    }
  }

  protected ClientSocketFactory determineSocketFactory(CommandRunner commandRunner) {
    if (getSlimPort() == SLIM_USE_PIPE_PORT) {
      return new PipeBasedSocketFactory(commandRunner);
    } else if ((determineClientSSLParameterClass() != null)) {
      return new SslClientSocketFactory(determineHostSSLParameters());
    } else {
      return new PlainClientSocketFactory();
    }
  }

  protected String determineClientSSLParameterClass() {
      String sslParameterClassName = getVariable("slim.ssl");
      if (sslParameterClassName == null) {
    	  sslParameterClassName = getVariable(SLIM_SSL);
      }
      if (sslParameterClassName != null && sslParameterClassName.equalsIgnoreCase("false")) sslParameterClassName=null;
      return sslParameterClassName;
  }

  protected SslParameters determineHostSSLParameters() {
    String val = getVariable(FitNesseContext.SSL_PARAMETER_CLASS_PROPERTY);
    return SslParameters.createSslParameters(val);
  }

  public double getSlimVersion() {
    double version = SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION;
    try {
      String slimVersion = getVariable(SLIM_VERSION);
      if (slimVersion != null) {
        version = Double.valueOf(slimVersion);
      }
    } catch (NumberFormatException e) {
      // stick with default
    }
    return version;
  }

  @Override
  protected String defaultTestRunner() {
    return "fitnesse.slim.SlimService";
  }

  protected String[] buildCommand() {
    String[] slimArguments = buildArguments();
    String[] slimCommandPrefix = super.buildCommand(getCommandPattern(), getTestRunner(), getClassPath());
    return ArrayUtils.addAll(slimCommandPrefix, slimArguments);
  }

  protected String[] buildArguments() {
    String[] arguments = new String[] {};
    String useSSL =  determineClientSSLParameterClass();
    if (useSSL != null){
    	arguments = ArrayUtils.add(arguments, "-ssl");
    	arguments = ArrayUtils.add(arguments, useSSL);
    }
    String[] slimFlags = getSlimFlags();
    if (slimFlags != null)
    	for (String flag : slimFlags)
    		arguments = ArrayUtils.add(arguments, flag);

  	arguments = ArrayUtils.add(arguments, Integer.toString(getSlimPort()));

    return arguments;
  }

  public int getSlimPort() {
    return slimPort;
  }

  protected void setSlimPort(int slimPort) {
    this.slimPort = slimPort;
  }

  private int findFreePort() {
    int port;
    try {
      ServerSocket socket = new PlainServerSocketFactory().createServerSocket(0);
      port = socket.getLocalPort();
      socket.close();
    } catch (Exception e) {
      port = -1;
    }
    return port;
  }

  protected int getNextSlimPort() {
    final int base = getSlimPortBase();
    final int poolSize = getSlimPortPoolSize();

    if (base == 0) {
      return findFreePort();
    }
    if (base == SLIM_USE_PIPE_PORT)
      return SLIM_USE_PIPE_PORT;

    synchronized (SlimClientBuilder.class) {
      int offset = slimPortOffset.get();
      int port = offset + base;
      offset = (offset + 1) % poolSize;
      slimPortOffset.set(offset);
      // is port available??
      return port;
    }
  }

  public static void clearSlimPortOffset() {
    slimPortOffset.set(0);
  }

  private int getSlimPortBase() {
    try {
      String port = getVariable("slim.port");
      if (port == null) {
        port = getVariable(SLIM_PORT);
      }

      if (port != null) {
        return Integer.parseInt(port);
      }
    } catch (NumberFormatException e) {
      // stick with default
    }
    return SLIM_USE_PIPE_PORT;
  }

  private int getSlimPortPoolSize() {
    try {
      String poolSize = getVariable("slim.pool.size");
      if (poolSize != null) {
        return Integer.parseInt(poolSize);
      }
    } catch (NumberFormatException e) {
      // stick with default
    }
    return 10;
  }

  protected String determineSlimHost() {
    String slimHost = getVariable("slim.host");
    if (slimHost == null) {
      slimHost = getVariable(SLIM_HOST);
    }
    return slimHost == null ? "localhost" : slimHost;
  }

  protected String[] getSlimFlags() {
    String slimFlags = getVariable("slim.flags");
    if (slimFlags == null) {
      slimFlags = getVariable(SLIM_FLAGS);
    }
    return slimFlags == null ? new String[] {} : parseCommandLine(slimFlags);
  }

  protected int determineTimeout() {
    if (isDebug()) {
      try {
        String debugTimeout = getVariable("slim.debug.timeout");
        if (debugTimeout != null) {
          return Integer.parseInt(debugTimeout);
        }
      } catch (NumberFormatException e) {
        // stick with default
      }
    }
    try {
      String timeout = getVariable("slim.timeout");
      if (timeout != null) {
        return Integer.parseInt(timeout);
      }
    } catch (NumberFormatException e) {
      // stick with default
    }
    return 10;
  }

  private boolean useManualStartForTestSystem() {
    if (isDebug()) {
      String useManualStart = getVariable("manually.start.test.runner.on.debug");
      if (useManualStart == null) {
        useManualStart = getVariable(MANUALLY_START_TEST_RUNNER_ON_DEBUG);
      }
      if (useManualStart != null) {
        return "true".equalsIgnoreCase(useManualStart);
      }
    }
    String useManualStart = getVariable("manually.start.test.runner");
    if (useManualStart == null) {
      useManualStart = getVariable(MANUALLY_START_TEST_RUNNER);
    }
    return "true".equalsIgnoreCase(useManualStart);

  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy