/**
* Copyright 2015-2016 Red Hat, Inc, and individual contributors.
*
* Licensed 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.wildfly.swarm.arquillian.daemon.protocol;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.util.logging.Logger;
import org.jboss.arquillian.container.test.spi.ContainerMethodExecutor;
import org.jboss.arquillian.test.spi.TestMethodExecutor;
import org.jboss.arquillian.test.spi.TestResult;
/**
* {@link ContainerMethodExecutor} implementation which executes tests on the remote JVM Arquillian Server Daemon and
* returns the {@link TestResult} it returns.
*
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
*/
public class DaemonMethodExecutor implements ContainerMethodExecutor {
DaemonMethodExecutor(final DeploymentContext context) {
if (context == null) {
throw new IllegalArgumentException("deployment context must be specified");
}
this.context = context;
}
/**
* {@inheritDoc}
*
* @see org.jboss.arquillian.container.test.spi.ContainerMethodExecutor#invoke(org.jboss.arquillian.test.spi.TestMethodExecutor)
*/
@Override
public TestResult invoke(final TestMethodExecutor testMethodExecutor) {
assert testMethodExecutor != null : "Test method executor is required";
// Build the String request according to the wire protocol
final StringBuilder builder = new StringBuilder();
builder.append(WireProtocol.COMMAND_TEST_PREFIX);
builder.append(testMethodExecutor.getInstance().getClass().getName());
builder.append(SPACE);
builder.append(testMethodExecutor.getMethod().getName());
builder.append(WireProtocol.COMMAND_EOF_DELIMITER);
final String testCommand = builder.toString();
final PrintWriter writer = this.context.getWriter();
// Request
writer.write(testCommand);
writer.flush();
try {
// Read response
final ObjectInputStream response = new ObjectInputStream(
new NoCloseInputStream(context.getSocketInstream()));
final TestResult testResult = (TestResult) response.readObject();
response.close();
return testResult;
} catch (final IOException ioe) {
throw new RuntimeException("Could not get test results", ioe);
} catch (final ClassNotFoundException cnfe) {
throw new RuntimeException("test result not on the client classpath", cnfe);
}
}
@SuppressWarnings("unused")
private static final Logger log = Logger.getLogger(DaemonMethodExecutor.class.getName());
private static final String SPACE = " ";
private final DeploymentContext context;
/**
* Wrapper which does forwards all operations except {@link InputStream#close()} to the delegate
*
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
*/
private static final class NoCloseInputStream extends InputStream {
NoCloseInputStream(final InputStream delegate) {
assert delegate != null : "delegate must be specified";
this.delegate = delegate;
}
/**
* Do not propagate {@link InputStream#close()}
*
* @see java.io.InputStream#close()
*/
@Override
public void close() throws IOException {
// NOOP
}
/**
* @return
* @throws IOException
* @see java.io.InputStream#read()
*/
@Override
public int read() throws IOException {
return delegate.read();
}
/**
* @return
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return delegate.hashCode();
}
/**
* @param b
* @return
* @throws IOException
* @see java.io.InputStream#read(byte[])
*/
@Override
public int read(byte[] b) throws IOException {
return delegate.read(b);
}
/**
* @param obj
* @return
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
/**
* @param b
* @param off
* @param len
* @return
* @throws IOException
* @see java.io.InputStream#read(byte[], int, int)
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
return delegate.read(b, off, len);
}
/**
* @param n
* @return
* @throws IOException
* @see java.io.InputStream#skip(long)
*/
@Override
public long skip(long n) throws IOException {
return delegate.skip(n);
}
/**
* @return
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return delegate.toString();
}
/**
* @return
* @throws IOException
* @see java.io.InputStream#available()
*/
@Override
public int available() throws IOException {
return delegate.available();
}
/**
* @param readlimit
* @see java.io.InputStream#mark(int)
*/
@Override
public void mark(int readlimit) {
delegate.mark(readlimit);
}
/**
* @throws IOException
* @see java.io.InputStream#reset()
*/
@Override
public void reset() throws IOException {
delegate.reset();
}
/**
* @return
* @see java.io.InputStream#markSupported()
*/
@Override
public boolean markSupported() {
return delegate.markSupported();
}
private final InputStream delegate;
}
}