/* * JBoss, Home of Professional Open Source * Copyright 2009, Red Hat, Inc., and others contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.jboss.narayana.blacktie.jatmibroker.xatmi; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import junit.framework.TestCase; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jboss.narayana.blacktie.jatmibroker.xatmi.Connection; import org.jboss.narayana.blacktie.jatmibroker.xatmi.ConnectionFactory; public abstract class CSControl extends TestCase { static final Logger log = LogManager.getLogger(CSControl.class); // the byte pattern written by a server to indicate that it has advertised // its services private static final byte[] HANDSHAKE = { 83, 69, 82, 86, 73, 67, 69, 83, 32, 82, 69, 65, 68, 89 }; private ProcessBuilder serverBuilder; private ProcessBuilder clientBuilder; private TestProcess server; private String CS_EXE; private String REPORT_DIR; private static int sid = 1; private Connection connection; protected boolean isSunOS = false; protected boolean isWinOS = false; static String nextSid() { return Integer.toString(sid % 10); } public void tearDown() { log.info("tearDown"); try { if (server != null) { log.debug("destroying server process"); server.interrupt(); log.debug("send shutdown command to the BTDomainAdmin"); X_OCTET sendbuf = (X_OCTET) connection.tpalloc("X_OCTET", null); sendbuf.setByteArray("shutdown,testsui,0,".getBytes()); connection.tpcall("BTDomainAdmin", sendbuf, 0); log.debug("destroyed server process"); server.getProcess().waitFor(); } log.debug("waited for server process"); } catch (Throwable e) { throw new RuntimeException("Server shutdown error: ", e); } } public void setUp() throws Exception { log.info("setUp"); String osName = (System.getProperty("os.name")); isSunOS = (osName != null && "SunOS".equals(osName)); isWinOS = (osName != null && osName.toLowerCase().indexOf("win") >= 0); REPORT_DIR = System.getProperty("TEST_REPORTS_DIR", "."); CS_EXE = System.getProperty("CLIENT_SERVER_EXE", "./cs"); clientBuilder = new ProcessBuilder(); serverBuilder = new ProcessBuilder(); // clientBuilder.redirectErrorStream(true); // serverBuilder.redirectErrorStream(true); java.util.Map<String, String> environment = serverBuilder.environment(); // environment.clear(); environment.put("LD_LIBRARY_PATH", System.getenv("LD_LIBRARY_PATH")); environment.put("BLACKTIE_CONFIGURATION_DIR", System.getenv("BLACKTIE_CONFIGURATION_DIR")); environment.put("BLACKTIE_SCHEMA_DIR", System.getenv("BLACKTIE_SCHEMA_DIR")); environment.put("JBOSSAS_IP_ADDR", System.getenv("JBOSSAS_IP_ADDR")); environment.put("PATH", System.getenv("PATH")); clientBuilder.environment().putAll(environment); environment.put("LOG4CXXCONFIG", "log4cxx-CSTest-server.properties"); clientBuilder.environment().put("LOG4CXXCONFIG", "log4cxx-CSTest-client.properties"); if (connection == null) { ConnectionFactory cf = ConnectionFactory.getConnectionFactory(); connection = cf.getConnection(); } } public void runServer(String name) { try { log.info("start server process: " + name); String property = System.getProperty("USE_VALGRIND"); String[] command = null; String nextSid = nextSid(); if (property != null && new Boolean(property)) { command = ("valgrind --tool=memcheck --leak-check=full --log-file=server-" + name + "-valgrind.log -v -d --track-origins=yes --leak-resolution=low --num-callers=40 " + CS_EXE + " -s testsui -p 12342 -i " + nextSid).split(" "); } else { command = (CS_EXE + " -s testsui -p 12342 -i " + nextSid).split(" "); } serverBuilder.command(command); server = startServer(name, serverBuilder); } catch (IOException e) { throw new RuntimeException("Server io exception: ", e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Server interrupted: ", e); } } public void runTest(String name) { if ((isWinOS && ("2121".equals(name) || "9".equals(name))) || (isSunOS && ("213".equals(name) || "4".equals(name)))) { log.info("skipping test " + name); return; } try { log.info("waiting for test " + name); String property = System.getProperty("USE_VALGRIND"); String[] command = null; if (property != null && new Boolean(property)) { command = ("valgrind --tool=memcheck --leak-check=full --log-file=client-" + name + "-valgrind.log -v -d --track-origins=yes --leak-resolution=low --num-callers=40 " + CS_EXE + " " + name).split(" "); } else { command = (CS_EXE + " " + name).split(" "); } clientBuilder.command(command); TestProcess client = startClient(name, clientBuilder); int res = client.exitValue(); log.info("test " + name + (res == 0 ? " passed " : " failed ") + res); assertTrue(res == 0); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } } private TestProcess startClient(String testname, ProcessBuilder builder) throws IOException, InterruptedException { String runTime = new SimpleDateFormat("yyMMddHHmmss").format(new Date()); FileOutputStream ostream = new FileOutputStream(REPORT_DIR + "/test-" + testname + "-" + runTime + "-out.txt"); FileOutputStream estream = new FileOutputStream(REPORT_DIR + "/test-" + testname + "-" + runTime + "-err.txt"); TestProcess client = new TestProcess(ostream, estream, "client", builder); Thread thread = new Thread(client); thread.start(); log.debug("startClient: waiting to join with client thread ..."); thread.join(); log.debug("startClient: joined - waiting for client process to exit"); client.getProcess().waitFor(); log.debug("startClient: done"); return client; } private TestProcess startServer(String testname, ProcessBuilder builder) throws IOException, InterruptedException { String runTime = new SimpleDateFormat("yyMMddHHmmss").format(new Date()); FileOutputStream ostream = new FileOutputStream(REPORT_DIR + "/server-" + testname + "-" + runTime + "-out.txt"); FileOutputStream estream = new FileOutputStream(REPORT_DIR + "/server-" + testname + "-" + runTime + "-err.txt"); TestProcess server = new TestProcess(ostream, estream, "server", builder); Thread thread = new Thread(server); synchronized (server) { // start the C server and wait for it to indicate that it has // advertised its services thread.start(); log.debug("startServer waiting for process to finish ..."); server.wait(); } return server; } class TestProcess implements Runnable { private String type; private Process proc; private FileOutputStream ostream; private FileOutputStream estream; private Thread thread; private ProcessBuilder builder; TestProcess(FileOutputStream ostream, FileOutputStream estream, String type, ProcessBuilder builder) { this.ostream = ostream; this.estream = estream; this.type = type; this.builder = builder; } Process getProcess() { return proc; } int exitValue() { return proc.exitValue(); } void interrupt() { if (thread != null) thread.interrupt(); } public void run() { thread = Thread.currentThread(); try { proc = builder.start(); InputStream is = proc.getInputStream(); InputStream es = proc.getErrorStream(); byte[] buf = new byte[1024]; int len; int match = -1; /* * redirect the process I/O to a file - if it is a server then notify any waiters when the server outputs a * magic sequence indicating that it has advertised its services */ if ("server".equals(type)) { // assume the HANDSHAKE sequence can be read in one go /* * while ((len = is.read(buf)) > 0) { if (match == -1 && (match = KMPMatch.indexOf(buf, HANDSHAKE, len)) != * -1) { synchronized (this) { this.notify(); } } * * ostream.write(buf, 0, len); } */ log.debug("server monitoring process I/O ..."); int pos = 0; while ((len = is.read(buf, pos, buf.length - pos)) > 0) { ostream.write(buf, pos, len); if (match == -1) { pos += len; if ((match = KMPMatch.indexOf(buf, HANDSHAKE, pos)) != -1) { synchronized (this) { this.notify(); } pos = 0; } else if (pos == buf.length) { ostream.write("missing synchronization sequence from service - force notify".getBytes(StandardCharsets.UTF_8)); log.warn("missing synchronization sequence from service"); synchronized (this) { this.notify(); } pos = 0; match = 0; } } else { pos = 0; } } } else { while ((len = is.read(buf)) > 0) ostream.write(buf, 0, len); } while ((len = es.read(buf)) > 0) estream.write(buf, 0, len); } catch (IOException e) { if (!Thread.interrupted()) log.warn(builder.command() + ": IO error on stream write: " + e); } log.debug("server process: read termination byte sequence"); try { ostream.close(); estream.close(); } catch (IOException e) { } } } }