/* * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.ovsdb.utils.ovsdb.it.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Run subprocesses and log or return their output. */ public class ProcUtils { private static final Logger LOG = LoggerFactory.getLogger(ProcUtils.class); /** * Run a process and assert the exit code is 0. * @param waitFor How long to wait for the command to execute * @param words The words of the command to run * @throws IOException if something goes wrong on the IO end * @throws InterruptedException If this thread is interrupted */ public static void runProcess(long waitFor, String... words) throws IOException, InterruptedException { runProcess(waitFor, null, words); } /** * Run a process, collect the stdout, and assert the exit code is 0. * @param waitFor How long to wait for the command to execute * @param capturedStdout Whatever the process wrote to standard out * @param words The words of the command to run * @throws IOException if something goes wrong on the IO end * @throws InterruptedException If this thread is interrupted */ public static void runProcess(long waitFor, StringBuilder capturedStdout, String... words) throws IOException, InterruptedException { int exitValue = tryProcess(null, waitFor, capturedStdout, words); Assert.assertEquals("ProcUtils.runProcess exit code is not 0", 0, exitValue); } public static int runProcess(int reserved, long waitFor, StringBuilder capturedStdout, String... words) throws IOException, InterruptedException { int exitValue = tryProcess(null, waitFor, capturedStdout, words); LOG.info("ProcUtils.runProcess exit code: ", exitValue); return exitValue; } /** * Run a process. * @param waitFor How long to wait for the command to execute * @param words The words of the command to run * @return The process's exit code * @throws IOException if something goes wrong on the IO end * @throws InterruptedException If this thread is interrupted */ public static int tryProcess(String logText, long waitFor, String... words) throws IOException, InterruptedException { return tryProcess(logText, waitFor, null, words); } /** * Run a process, collect the stdout. * @param waitFor How long to wait (milliseconds) for the command to execute * @param capturedStdout Whatever the process wrote to standard out * @param words The words of the command to run * @return The process's exit code or -1 if the the command does not complete within waitFor milliseconds * @throws IOException if something goes wrong on the IO end * @throws InterruptedException If this thread is interrupted */ public static int tryProcess(String logText, long waitFor, StringBuilder capturedStdout, String... words) throws IOException, InterruptedException { LOG.info("ProcUtils.runProcess {} running \"{}\", waitFor {}", logText != null ? logText : "", words, waitFor); Process proc = new ProcessBuilder(words).start(); int exitValue = -1; // Use a try block to guarantee stdout and stderr are closed try (BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream())); BufferedReader stderr = new BufferedReader(new InputStreamReader(proc.getErrorStream()))) { exitValue = waitForExitValue(waitFor, proc); while (stderr.ready()) { LOG.warn("ProcUtils.runProcess {} [stderr]: {}", logText != null ? logText : "", stderr.readLine()); } StringBuilder stdoutStringBuilder = (capturedStdout != null) ? capturedStdout : new StringBuilder(); int read; char[] buf = new char[1024]; while (-1 != (read = stdout.read(buf))) { stdoutStringBuilder.append(buf, 0, read); } LOG.info("ProcUtils.runProcess {} [stdout]:\n{}", logText != null ? logText : "", stdoutStringBuilder.toString()); } return exitValue; } /** * Wait for a process to end. * @param waitFor how long to wait in milliseconds * @param proc Process object * @return the process's exit value or -1 if the process did not complete within waitFor milliseconds * @throws InterruptedException if this thread is interrupted */ private static int waitForExitValue(long waitFor, Process proc) throws InterruptedException { //Java 7 has no way to check whether a process is still running without blocking //until the process exits. What this hack does is checks the exitValue() which //throws an IllegalStateException if the process is still running still it does //not have a exit value. We catch that exception and implement our own timeout. //Once we no longer need to support Java 7, this has more elegant solutions. int exitValue = -1; long startTime = System.currentTimeMillis(); while (true) { try { exitValue = proc.exitValue(); break; } catch (IllegalThreadStateException e) { if ((System.currentTimeMillis() - startTime) < waitFor) { Thread.sleep(200); } else { LOG.warn("ProcUtils.waitForExitValue: timed out while waiting for command to complete", e); break; } } } return exitValue; } }