RunTestCommand.java revision d053117ad50d47a7f2b25be4303d945e4e9edd1e
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.commands.uiautomator; 18 19import android.os.Bundle; 20 21import com.android.commands.uiautomator.Launcher.Command; 22import com.android.uiautomator.testrunner.UiAutomatorTestRunner; 23 24import java.util.ArrayList; 25import java.util.List; 26 27/** 28 * Implementation of the runtest sub command 29 * 30 */ 31public class RunTestCommand extends Command { 32 33 private static final String OUTPUT_SIMPLE = "simple"; 34 private static final String OUTPUT_FORMAT_KEY = "outputFormat"; 35 private static final String CLASS_PARAM = "class"; 36 private static final String DEBUG_PARAM = "debug"; 37 private static final String RUNNER_PARAM = "runner"; 38 private static final String CLASS_SEPARATOR = ","; 39 private static final int ARG_OK = 0; 40 private static final int ARG_FAIL_INCOMPLETE_E = -1; 41 private static final int ARG_FAIL_INCOMPLETE_C = -2; 42 private static final int ARG_FAIL_NO_CLASS = -3; 43 private static final int ARG_FAIL_RUNNER = -4; 44 private static final int ARG_FAIL_UNSUPPORTED = -99; 45 46 private Bundle mParams = new Bundle(); 47 private List<String> mTestClasses = new ArrayList<String>(); 48 private boolean mDebug; 49 private String mRunner; 50 51 public RunTestCommand() { 52 super("runtest"); 53 } 54 55 @Override 56 public void run(String[] args) { 57 int ret = parseArgs(args); 58 switch (ret) { 59 case ARG_FAIL_INCOMPLETE_C: 60 System.err.println("Incomplete '-c' parameter."); 61 System.exit(ARG_FAIL_INCOMPLETE_C); 62 break; 63 case ARG_FAIL_INCOMPLETE_E: 64 System.err.println("Incomplete '-e' parameter."); 65 System.exit(ARG_FAIL_INCOMPLETE_E); 66 break; 67 case ARG_FAIL_UNSUPPORTED: 68 System.err.println("Unsupported standalone parameter."); 69 System.exit(ARG_FAIL_UNSUPPORTED); 70 break; 71 default: 72 break; 73 } 74 if (mTestClasses.isEmpty()) { 75 System.err.println("Please specify at least one test class to run."); 76 System.exit(ARG_FAIL_NO_CLASS); 77 } 78 getRunner().run(mTestClasses, mParams, mDebug); 79 } 80 81 private int parseArgs(String[] args) { 82 // we are parsing for these parameters: 83 // -e <key> <value> 84 // key-value pairs 85 // special ones are: 86 // key is "class", parameter is passed onto JUnit as class name to run 87 // key is "debug", parameter will determine whether to wait for debugger 88 // to attach 89 // -c <class name> 90 // -s turns on the simple output format 91 // equivalent to -e class <class name>, i.e. passed onto JUnit 92 for (int i = 0; i < args.length; i++) { 93 if (args[i].equals("-e")) { 94 if (i + 2 < args.length) { 95 String key = args[++i]; 96 String value = args[++i]; 97 if (CLASS_PARAM.equals(key)) { 98 addTestClasses(value); 99 } else if (DEBUG_PARAM.equals(key)) { 100 mDebug = "true".equals(value) || "1".equals(value); 101 } else if (RUNNER_PARAM.equals(key)) { 102 mRunner = value; 103 } else { 104 mParams.putString(key, value); 105 } 106 } else { 107 return ARG_FAIL_INCOMPLETE_E; 108 } 109 } else if (args[i].equals("-c")) { 110 if (i + 1 < args.length) { 111 addTestClasses(args[++i]); 112 } else { 113 return ARG_FAIL_INCOMPLETE_C; 114 } 115 } else if (args[i].equals("-s")) { 116 mParams.putString(OUTPUT_FORMAT_KEY, OUTPUT_SIMPLE); 117 } else { 118 return ARG_FAIL_UNSUPPORTED; 119 } 120 } 121 return ARG_OK; 122 } 123 124 protected UiAutomatorTestRunner getRunner() { 125 if (mRunner == null) { 126 return new UiAutomatorTestRunner(); 127 } 128 // use reflection to get the runner 129 Object o = null; 130 try { 131 Class<?> clazz = Class.forName(mRunner); 132 o = clazz.newInstance(); 133 } catch (ClassNotFoundException cnfe) { 134 System.err.println("Cannot find runner: " + mRunner); 135 System.exit(ARG_FAIL_RUNNER); 136 } catch (InstantiationException ie) { 137 System.err.println("Cannot instantiate runner: " + mRunner); 138 System.exit(ARG_FAIL_RUNNER); 139 } catch (IllegalAccessException iae) { 140 System.err.println("Constructor of runner " + mRunner + " is not accessibile"); 141 System.exit(ARG_FAIL_RUNNER); 142 } 143 try { 144 UiAutomatorTestRunner runner = (UiAutomatorTestRunner)o; 145 return runner; 146 } catch (ClassCastException cce) { 147 System.err.println("Specified runner is not subclass of " 148 + UiAutomatorTestRunner.class.getSimpleName()); 149 System.exit(ARG_FAIL_RUNNER); 150 } 151 // won't reach here 152 return null; 153 } 154 155 /** 156 * Add test classes from a potentially comma separated list 157 * @param classes 158 */ 159 private void addTestClasses(String classes) { 160 String[] classArray = classes.split(CLASS_SEPARATOR); 161 for (String clazz : classArray) { 162 mTestClasses.add(clazz); 163 } 164 } 165 166 @Override 167 public String detailedOptions() { 168 return " runtest <class spec> [options]\n" 169 + " <class spec>: <JARS> < -c <CLASSES> | -e class <CLASSES> >\n" 170 + " <JARS>: a list of jar files containing test classes and dependencies. If\n" 171 + " the path is relative, it's assumed to be under /data/local/tmp. Use\n" 172 + " absolute path if the file is elsewhere. Multiple files can be\n" 173 + " specified, separated by space.\n" 174 + " <CLASSES>: a list of test class names to run, separated by comma. To\n" 175 + " a single method, use TestClass#testMethod format. The -e or -c option\n" 176 + " may be repeated.\n" 177 + " options:\n" 178 + " --nohup: trap SIG_HUP, so test won't terminate even if parent process\n" 179 + " is terminated, e.g. USB is disconnected.\n" 180 + " -e debug [true|false]: wait for debugger to connect before starting.\n" 181 + " -e runner [CLASS]: use specified test runner class instead. If\n" 182 + " unspecified, framework default runner will be used.\n" 183 + " -e <NAME> <VALUE>: other name-value pairs to be passed to test classes.\n" 184 + " May be repeated.\n" 185 + " -e outputFormat simple | -s: enabled less verbose JUnit style output.\n"; 186 } 187 188 @Override 189 public String shortHelp() { 190 return "executes UI automation tests"; 191 } 192 193}