1 /* 2 * Copyright (C) 2011 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 package com.android.cts.tradefed.command; 17 18 import com.android.cts.tradefed.build.CtsBuildHelper; 19 import com.android.cts.tradefed.build.CtsBuildProvider; 20 import com.android.cts.tradefed.result.ITestResultRepo; 21 import com.android.cts.tradefed.result.ITestSummary; 22 import com.android.cts.tradefed.result.PlanCreator; 23 import com.android.cts.tradefed.result.TestResultRepo; 24 import com.android.cts.tradefed.testtype.ITestPackageRepo; 25 import com.android.cts.tradefed.testtype.TestPackageRepo; 26 import com.android.tradefed.command.Console; 27 import com.android.tradefed.config.ArgsOptionParser; 28 import com.android.tradefed.config.ConfigurationException; 29 import com.android.tradefed.util.FileUtil; 30 import com.android.tradefed.util.RegexTrie; 31 import com.android.tradefed.util.TableFormatter; 32 33 import java.io.File; 34 import java.io.FileNotFoundException; 35 import java.io.FilenameFilter; 36 import java.io.PrintWriter; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.List; 40 import java.util.Map; 41 42 /** 43 * Specialization of trade federation console that adds CTS commands to list plans and packages. 44 */ 45 public class CtsConsole extends Console { 46 47 protected static final String ADD_PATTERN = "a(?:dd)?"; 48 49 private CtsBuildHelper mCtsBuild = null; 50 51 CtsConsole() { 52 super(); 53 } 54 55 @Override 56 public void run() { 57 printLine(String.format("Android CTS %s", CtsBuildProvider.CTS_BUILD_VERSION)); 58 super.run(); 59 } 60 61 /** 62 * Adds the 'list packages' and 'list plans' commands 63 */ 64 @Override 65 protected void setCustomCommands(RegexTrie<Runnable> trie, List<String> genericHelp, 66 Map<String, String> commandHelp) { 67 trie.put(new Runnable() { 68 @Override 69 public void run() { 70 CtsBuildHelper ctsBuild = getCtsBuild(); 71 if (ctsBuild != null) { 72 listPlans(ctsBuild); 73 } 74 } 75 }, LIST_PATTERN, "p(?:lans)?"); 76 trie.put(new Runnable() { 77 @Override 78 public void run() { 79 CtsBuildHelper ctsBuild = getCtsBuild(); 80 if (ctsBuild != null) { 81 listPackages(ctsBuild); 82 } 83 } 84 }, LIST_PATTERN, "packages"); 85 trie.put(new Runnable() { 86 @Override 87 public void run() { 88 CtsBuildHelper ctsBuild = getCtsBuild(); 89 if (ctsBuild != null) { 90 listResults(ctsBuild); 91 } 92 } 93 }, LIST_PATTERN, "r(?:esults)?"); 94 95 // find existing help for 'LIST_PATTERN' commands, and append these commands help 96 String listHelp = commandHelp.get(LIST_PATTERN); 97 if (listHelp == null) { 98 // no help? Unexpected, but soldier on 99 listHelp = new String(); 100 } 101 String combinedHelp = listHelp + 102 "\tp[lans]\t\tList all CTS test plans" + LINE_SEPARATOR + 103 "\tpackages\tList all CTS packages" + LINE_SEPARATOR + 104 "\tr[esults]\tList all CTS results" + LINE_SEPARATOR; 105 commandHelp.put(LIST_PATTERN, combinedHelp); 106 107 ArgRunnable<CaptureList> addDerivedCommand = new ArgRunnable<CaptureList>() { 108 @Override 109 public void run(CaptureList args) { 110 // Skip 2 tokens to get past addPattern and "derivedplan" 111 String[] flatArgs = new String[args.size() - 2]; 112 for (int i = 2; i < args.size(); i++) { 113 flatArgs[i - 2] = args.get(i).get(0); 114 } 115 CtsBuildHelper ctsBuild = getCtsBuild(); 116 if (ctsBuild != null) { 117 addDerivedPlan(ctsBuild, flatArgs); 118 } 119 } 120 }; 121 trie.put(addDerivedCommand, ADD_PATTERN, "d(?:erivedplan?)", null); 122 commandHelp.put(ADD_PATTERN, String.format( 123 "%s help:" + LINE_SEPARATOR + 124 "\tderivedplan Add a derived plan" + LINE_SEPARATOR, 125 ADD_PATTERN)); 126 } 127 128 @Override 129 protected String getConsolePrompt() { 130 return "cts-tf > "; 131 } 132 133 @Override 134 protected String getGenericHelpString(List<String> genericHelp) { 135 StringBuilder helpBuilder = new StringBuilder(); 136 helpBuilder.append("CTS-tradefed host version "); 137 helpBuilder.append(CtsBuildProvider.CTS_BUILD_VERSION); 138 helpBuilder.append("\n\n"); 139 helpBuilder.append("CTS-tradefed is the test harness for running the Android "); 140 helpBuilder.append("Compatibility Suite, built on top of the tradefed framework.\n\n"); 141 helpBuilder.append("Available commands and options\n"); 142 helpBuilder.append("Host:\n"); 143 helpBuilder.append(" help: show this message\n"); 144 helpBuilder.append(" help all: show the complete tradefed help\n"); 145 helpBuilder.append(" exit: gracefully exit the cts console, waiting till all "); 146 helpBuilder.append("invocations are complete\n"); 147 helpBuilder.append("Run:\n"); 148 helpBuilder.append(" run cts --plan test_plan_name: run a test plan\n"); 149 helpBuilder.append(" run cts --package/-p : run a CTS test package\n"); 150 helpBuilder.append(" run cts --class/-c [--method/-m] : run a specific test class and/or"); 151 helpBuilder.append("method\n"); 152 helpBuilder.append(" run cts --continue-session session_ID: run all not executed "); 153 helpBuilder.append("tests from a previous CTS session\n"); 154 helpBuilder.append(" run cts [options] --serial/s device_ID: run CTS on specified "); 155 helpBuilder.append("device\n"); 156 helpBuilder.append(" run cts [options] --shards number_of_shards: shard a CTS run into "); 157 helpBuilder.append("given number of independent chunks, to run on multiple devices in"); 158 helpBuilder.append("parallel\n"); 159 helpBuilder.append(" run cts --help/--help-all: get more help on running CTS\n"); 160 helpBuilder.append("List:\n"); 161 helpBuilder.append(" l/list d/devices: list connected devices and their state\n"); 162 helpBuilder.append(" l/list packages: list CTS test packages\n"); 163 helpBuilder.append(" l/list p/plans: list CTS test plans\n"); 164 helpBuilder.append(" l/list i/invocations: list invocations aka CTS test runs currently"); 165 helpBuilder.append("in progress\n"); 166 helpBuilder.append(" l/list c/commands: list commands: aka CTS test run commands "); 167 helpBuilder.append("currently in the queue waiting to be allocated devices\n"); 168 helpBuilder.append(" l/list r/results: list CTS results currently present in the "); 169 helpBuilder.append("repository\n"); 170 helpBuilder.append("Add:\n"); 171 helpBuilder.append(" add derivedplan --plan plane_name --session/-s session_id -r "); 172 helpBuilder.append("[pass/fail/notExecuted/timeout]: derive a plan from the given "); 173 helpBuilder.append("session\n"); 174 helpBuilder.append("Dump:\n"); 175 helpBuilder.append(" d/dump l/logs: dump the tradefed logs for all running invocations\n"); 176 return helpBuilder.toString(); 177 } 178 179 private void listPlans(CtsBuildHelper ctsBuild) { 180 FilenameFilter xmlFilter = new FilenameFilter() { 181 @Override 182 public boolean accept(File dir, String name) { 183 return name.endsWith(".xml"); 184 } 185 }; 186 for (File planFile : ctsBuild.getTestPlansDir().listFiles(xmlFilter)) { 187 printLine(FileUtil.getBaseName(planFile.getName())); 188 } 189 } 190 191 private void listPackages(CtsBuildHelper ctsBuild) { 192 ITestPackageRepo testCaseRepo = new TestPackageRepo(ctsBuild.getTestCasesDir(), false); 193 for (String packageUri : testCaseRepo.getPackageNames()) { 194 printLine(packageUri); 195 } 196 } 197 198 private void listResults(CtsBuildHelper ctsBuild) { 199 TableFormatter tableFormatter = new TableFormatter(); 200 List<List<String>> table = new ArrayList<List<String>>(); 201 table.add(Arrays.asList("Session","Pass", "Fail","Not Executed","Start time","Plan name", 202 "Device serial(s)")); 203 ITestResultRepo testResultRepo = new TestResultRepo(ctsBuild.getResultsDir()); 204 for (ITestSummary result : testResultRepo.getSummaries()) { 205 table.add(Arrays.asList(Integer.toString(result.getId()), 206 Integer.toString(result.getNumPassed()), 207 Integer.toString(result.getNumFailed()), 208 Integer.toString(result.getNumIncomplete()), 209 result.getTimestamp(), 210 result.getTestPlan(), 211 result.getDeviceSerials())); 212 } 213 tableFormatter.displayTable(table, new PrintWriter(System.out, true)); 214 } 215 216 private void addDerivedPlan(CtsBuildHelper ctsBuild, String[] flatArgs) { 217 PlanCreator creator = new PlanCreator(); 218 try { 219 ArgsOptionParser optionParser = new ArgsOptionParser(creator); 220 optionParser.parse(Arrays.asList(flatArgs)); 221 creator.createAndSerializeDerivedPlan(ctsBuild); 222 } catch (ConfigurationException e) { 223 printLine("Error: " + e.getMessage()); 224 printLine(ArgsOptionParser.getOptionHelp(false, creator)); 225 } 226 } 227 228 private CtsBuildHelper getCtsBuild() { 229 if (mCtsBuild == null) { 230 String ctsInstallPath = System.getProperty("CTS_ROOT"); 231 if (ctsInstallPath != null) { 232 mCtsBuild = new CtsBuildHelper(new File(ctsInstallPath)); 233 try { 234 mCtsBuild.validateStructure(); 235 } catch (FileNotFoundException e) { 236 printLine(String.format("Invalid cts install: %s", e.getMessage())); 237 mCtsBuild = null; 238 } 239 } else { 240 printLine("Could not find CTS install location: CTS_ROOT env variable not set"); 241 } 242 } 243 return mCtsBuild; 244 } 245 246 public static void main(String[] args) throws InterruptedException { 247 Console console = new CtsConsole(); 248 Console.startConsole(console, args); 249 } 250 } 251