1f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage tests.support; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 201f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport junit.framework.AssertionFailedError; 211f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport junit.framework.TestCase; 221f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 261f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.io.InputStreamReader; 271f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.io.Reader; 281f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.io.StringWriter; 291f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.Arrays; 301f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.concurrent.Callable; 311f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.concurrent.ExecutorService; 321f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.concurrent.Executors; 331f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.concurrent.Future; 341f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilsonimport java.util.concurrent.TimeUnit; 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Support_Exec extends TestCase { 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 381f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson private static final boolean againstDalvik 391f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson = System.getProperty("java.vendor").contains("Android"); 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 421f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * Returns a builder configured with the appropriate VM ("dalvikvm" or 431f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * "java") and arguments (as specified by the system property 441f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * {@code hy.test.vmargs}). 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 461f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson public static ProcessBuilder javaProcessBuilder() 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throws IOException, InterruptedException { 481f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson ProcessBuilder builder = new ProcessBuilder(); 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 501f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson // construct the name of executable file 511f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson builder.command().add(againstDalvik ? "dalvikvm" : "java"); 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 531f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson // parse hy.test.vmargs if was given 541f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson String testVMArgs = System.getProperty("hy.test.vmargs"); 551f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson if (testVMArgs != null) { 561f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson builder.command().addAll(Arrays.asList(testVMArgs.split("\\s+"))); 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 591f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson return builder; 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 621f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson /** 631f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * Returns a command-line ready path formed by joining the path elements 641f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * with the system path separator as a separator. 651f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson */ 661f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson public static String createPath(String... elements) { 671f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson StringBuilder result = new StringBuilder(); 681f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson for (String element : elements) { 691f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson result.append(File.pathSeparator); 701f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson result.append(element); 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 721f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson return result.toString(); 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 751f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson /** 769c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson * Starts the specified process, collects its output from standard out and 779c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson * standard err, and returns. If the stream emits anything to standard err, 789c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson * an AssertionFailedError will be thrown. 791f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * 80513ac78ca8aaeb61fa06928ca10aeff34a7b4683Brian Carlstrom * <p>This method assumes the target process will complete within thirty 811f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson * seconds. If it does not, an AssertionFailedError will be thrown. 821f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson */ 831805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes public static String execAndGetOutput(ProcessBuilder builder) throws IOException { 849c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson Process process = builder.start(); 859c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson ExecutorService executorService = Executors.newFixedThreadPool(2); 861f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson try { 879c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson Future<String> errFuture = executorService.submit( 889c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson streamToStringCallable(process.getErrorStream())); 899c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson Future<String> outFuture = executorService.submit( 909c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson streamToStringCallable(process.getInputStream())); 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 921f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson Throwable failure; 939c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson String out = ""; 941f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson try { 95513ac78ca8aaeb61fa06928ca10aeff34a7b4683Brian Carlstrom out = outFuture.get(30, TimeUnit.SECONDS); 96513ac78ca8aaeb61fa06928ca10aeff34a7b4683Brian Carlstrom String err = errFuture.get(30, TimeUnit.SECONDS); 979c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson failure = err.length() > 0 989c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson ? new AssertionFailedError("Unexpected err stream data:\n" + err) 999c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson : null; 1001f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson } catch (Exception e) { 1011f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson failure = e; 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1041f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson if (failure != null) { 1051f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson AssertionFailedError error = new AssertionFailedError( 1061f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson "Failed to execute " + builder.command() + "; output was:\n" + out); 1071f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson error.initCause(failure); 1081f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson throw error; 1091f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson } else { 1101f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson return out; 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1121f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson } finally { 1131f4eba15dc9e4086ce7e2a4fc7cac83fe6bbc03dJesse Wilson executorService.shutdown(); 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1171805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes /** 1181805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes * Starts the process described by 'builder', and asserts that it sees 1191805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes * 'expectedOut' on stdout and 'expectedErr' on stderr. Times out after 1201805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes * 10s. 1211805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes */ 1221805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes public static void execAndCheckOutput(ProcessBuilder builder, 1231805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes String expectedOut, String expectedErr) throws Exception { 1241805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes Process process = builder.start(); 1251805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes ExecutorService executorService = Executors.newFixedThreadPool(2); 1261805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes try { 1271805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes Future<String> errFuture = 1281805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes executorService.submit(streamToStringCallable(process.getErrorStream())); 1291805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes Future<String> outFuture = 1301805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes executorService.submit(streamToStringCallable(process.getInputStream())); 1311805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes assertEquals(expectedOut, outFuture.get(10, TimeUnit.SECONDS)); 1321805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes assertEquals(expectedErr, errFuture.get(10, TimeUnit.SECONDS)); 1331805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes } finally { 1341805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes executorService.shutdown(); 1351805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes process.waitFor(); 1361805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes } 1371805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes } 1381805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes 1399c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson private static Callable<String> streamToStringCallable(final InputStream in) { 1409c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson return new Callable<String>() { 1419c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson public String call() throws Exception { 1429c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson StringWriter writer = new StringWriter(); 1439c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson Reader reader = new InputStreamReader(in); 1449c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson int c; 1459c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson while ((c = reader.read()) != -1) { 1469c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson writer.write(c); 1479c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson } 1489c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson return writer.toString(); 1499c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson } 1509c048fb7738ee3ac3677ba2170e360de8d70dcabJesse Wilson }; 151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 153