/* * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package support; import com.sun.btrace.BTraceFunctionalTests; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.StringTokenizer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.junit.Assert; /** * * @author Jaroslav Bachorik */ abstract public class RuntimeTest { protected static interface ResultValidator { void validate(String stdout, String stderr, int retcode); } private static String cp = null; private static String java = null; private static String btraceExtPath = null; public static void setup() { URL url = BTraceFunctionalTests.class.getClassLoader().getResource("com/sun/btrace/client/Main.class"); try { File f = new File(url.toURI()); while (f != null) { if (f.getName().equals("build")) { break; } f = f.getParentFile(); } if (f != null) { btraceExtPath = f.getAbsolutePath() + "/btrace-client.jar"; } Assert.assertNotNull(btraceExtPath); } catch (URISyntaxException e) { throw new Error(e); } String toolsjar = null; cp = System.getProperty("java.class.path"); StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); while (st.hasMoreTokens()) { String elem = st.nextToken(); if (elem.contains("tools.jar")) { toolsjar = elem; } } if (toolsjar == null) { URL rturl = String.class.getResource("/java/lang/String.class"); toolsjar = rturl.toString().replace("jar:file:", "").replace("jre/lib/rt.jar", "lib/tools.jar"); toolsjar = toolsjar.substring(0, toolsjar.indexOf('!')); System.err.println(toolsjar); } btraceExtPath = btraceExtPath + File.pathSeparator + toolsjar; java = System.getProperty("java.home").replace("/jre", ""); } /** * Display the otput from the test application */ protected boolean debugTestApp = false; /** * Run BTrace in debug mode */ protected boolean debugBTrace = false; /** * Run BTrace in unsafe mode */ protected boolean isUnsafe = false; /** * Timeout in ms to wait for the expected BTrace output */ protected long timeout = 10000L; /** * Track retransforming progress */ protected boolean trackRetransforms = false; protected void reset() { debugTestApp = false; debugBTrace = false; isUnsafe = false; timeout = 10000L; } @SuppressWarnings("DefaultCharset") public void test(String testApp, final String testScript, int checkLines, ResultValidator v) throws Exception { ProcessBuilder pb = new ProcessBuilder( java + "/bin/java", "-cp", cp, testApp ); pb.environment().remove("JAVA_TOOL_OPTIONS"); Process p = pb.start(); final PrintWriter pw = new PrintWriter(p.getOutputStream()); final StringBuilder stdout = new StringBuilder(); final StringBuilder stderr = new StringBuilder(); final AtomicInteger ret = new AtomicInteger(-1); final BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream())); final CountDownLatch testAppLatch = new CountDownLatch(1); final AtomicReference<String> pidStringRef = new AtomicReference<>(); Thread outT = new Thread(new Runnable() { @Override public void run() { try { String l; while ((l = stdoutReader.readLine()) != null) { if (l.startsWith("ready:")) { pidStringRef.set(l.split("\\:")[1]); testAppLatch.countDown(); } if (debugTestApp) { System.out.println("[traced app] " + l); } } } catch (Exception e) { e.printStackTrace(System.err); } } }, "STDOUT Reader"); outT.setDaemon(true); final BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); Thread errT = new Thread(new Runnable() { @Override public void run() { try { String l = null; while ((l = stderrReader.readLine()) != null) { testAppLatch.countDown(); if (debugTestApp) { System.err.println("[traced app] " + l); } } } catch (Exception e) { e.printStackTrace(System.err); } } }, "STDERR Reader"); errT.setDaemon(true); outT.start(); errT.start(); testAppLatch.await(); String pid = pidStringRef.get(); if (pid != null) { System.out.println("Target process ready: " + pid); Process client = attach(pid, testScript, checkLines, stdout, stderr); System.out.println("Detached."); pw.println("done"); pw.flush(); ret.set(client.waitFor()); outT.join(); errT.join(); } v.validate(stdout.toString(), stderr.toString(), ret.get()); } private Process attach(String pid, String trace, final int checkLines, final StringBuilder stdout, final StringBuilder stderr) throws Exception { URL u = ClassLoader.getSystemResource(trace); System.out.println(trace); File traceFile = new File(u.toURI()); trace = traceFile.getAbsolutePath(); final ProcessBuilder pb = new ProcessBuilder( java + "/bin/java", "-Dcom.sun.btrace.unsafe=" + isUnsafe, "-Dcom.sun.btrace.debug=" + debugBTrace, "-Dcom.sun.btrace.trackRetransforms=" + trackRetransforms, "-cp", btraceExtPath, "com.sun.btrace.client.Main", "-d", "/tmp/btrace-test", "-pd", traceFile.getParentFile().getAbsolutePath(), pid, trace ); pb.environment().remove("JAVA_TOOL_OPTIONS"); final Process p = pb.start(); final CountDownLatch l = new CountDownLatch(checkLines); new Thread(new Runnable() { @Override public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8)); String line = null; while ((line = br.readLine()) != null) { stderr.append(line).append('\n'); System.out.println("[btrace err] " + line); if (line.contains("Exception") || line.contains("Error")) { for(int i=0;i<checkLines;i++) { l.countDown(); } } } } catch (Exception e) { for(int i=0;i<checkLines;i++) { l.countDown(); } throw new Error(e); } } }, "Stderr Reader").start(); new Thread(new Runnable() { @Override public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8)); String line = null; while ((line = br.readLine()) != null) { stdout.append(line).append('\n'); System.out.println("[btrace out] " + line); if (!(debugBTrace && line.contains("DEBUG:"))) { l.countDown(); } } } catch (Exception e) { for(int i=0;i<checkLines;i++) { l.countDown(); } throw new Error(e); } } }, "Stdout Reader").start(); l.await(timeout, TimeUnit.MILLISECONDS); return p; } }