1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package tests.support; 19 20 import junit.framework.AssertionFailedError; 21 import junit.framework.TestCase; 22 23 import java.io.File; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.InputStreamReader; 27 import java.io.Reader; 28 import java.io.StringWriter; 29 import java.util.Arrays; 30 import java.util.concurrent.Callable; 31 import java.util.concurrent.ExecutorService; 32 import java.util.concurrent.Executors; 33 import java.util.concurrent.Future; 34 import java.util.concurrent.TimeUnit; 35 36 public class Support_Exec extends TestCase { 37 38 private static final boolean againstDalvik 39 = System.getProperty("java.vendor").contains("Android"); 40 41 /** 42 * Returns a builder configured with the appropriate VM ("dalvikvm" or 43 * "java") and arguments (as specified by the system property 44 * {@code hy.test.vmargs}). 45 */ 46 public static ProcessBuilder javaProcessBuilder() 47 throws IOException, InterruptedException { 48 ProcessBuilder builder = new ProcessBuilder(); 49 50 // construct the name of executable file 51 builder.command().add(againstDalvik ? "dalvikvm" : "java"); 52 53 // parse hy.test.vmargs if was given 54 String testVMArgs = System.getProperty("hy.test.vmargs"); 55 if (testVMArgs != null) { 56 builder.command().addAll(Arrays.asList(testVMArgs.split("\\s+"))); 57 } 58 59 return builder; 60 } 61 62 /** 63 * Returns a command-line ready path formed by joining the path elements 64 * with the system path separator as a separator. 65 */ 66 public static String createPath(String... elements) { 67 StringBuilder result = new StringBuilder(); 68 for (String element : elements) { 69 result.append(File.pathSeparator); 70 result.append(element); 71 } 72 return result.toString(); 73 } 74 75 /** 76 * Starts the specified process, collects its output from standard out and 77 * standard err, and returns. If the stream emits anything to standard err, 78 * an AssertionFailedError will be thrown. 79 * 80 * <p>This method assumes the target process will complete within ten 81 * seconds. If it does not, an AssertionFailedError will be thrown. 82 */ 83 public static String execAndGetOutput(ProcessBuilder builder) throws IOException { 84 Process process = builder.start(); 85 ExecutorService executorService = Executors.newFixedThreadPool(2); 86 try { 87 Future<String> errFuture = executorService.submit( 88 streamToStringCallable(process.getErrorStream())); 89 Future<String> outFuture = executorService.submit( 90 streamToStringCallable(process.getInputStream())); 91 92 Throwable failure; 93 String out = ""; 94 try { 95 out = outFuture.get(10, TimeUnit.SECONDS); 96 String err = errFuture.get(10, TimeUnit.SECONDS); 97 failure = err.length() > 0 98 ? new AssertionFailedError("Unexpected err stream data:\n" + err) 99 : null; 100 } catch (Exception e) { 101 failure = e; 102 } 103 104 if (failure != null) { 105 AssertionFailedError error = new AssertionFailedError( 106 "Failed to execute " + builder.command() + "; output was:\n" + out); 107 error.initCause(failure); 108 throw error; 109 } else { 110 return out; 111 } 112 } finally { 113 executorService.shutdown(); 114 } 115 } 116 117 /** 118 * Starts the process described by 'builder', and asserts that it sees 119 * 'expectedOut' on stdout and 'expectedErr' on stderr. Times out after 120 * 10s. 121 */ 122 public static void execAndCheckOutput(ProcessBuilder builder, 123 String expectedOut, String expectedErr) throws Exception { 124 Process process = builder.start(); 125 ExecutorService executorService = Executors.newFixedThreadPool(2); 126 try { 127 Future<String> errFuture = 128 executorService.submit(streamToStringCallable(process.getErrorStream())); 129 Future<String> outFuture = 130 executorService.submit(streamToStringCallable(process.getInputStream())); 131 assertEquals(expectedOut, outFuture.get(10, TimeUnit.SECONDS)); 132 assertEquals(expectedErr, errFuture.get(10, TimeUnit.SECONDS)); 133 } finally { 134 executorService.shutdown(); 135 process.waitFor(); 136 } 137 } 138 139 private static Callable<String> streamToStringCallable(final InputStream in) { 140 return new Callable<String>() { 141 public String call() throws Exception { 142 StringWriter writer = new StringWriter(); 143 Reader reader = new InputStreamReader(in); 144 int c; 145 while ((c = reader.read()) != -1) { 146 writer.write(c); 147 } 148 return writer.toString(); 149 } 150 }; 151 } 152 } 153