• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.cts;
18 
19 import com.android.cts.TestHost.ActionType;
20 import com.android.cts.TestHost.MODE;
21 
22 import org.xml.sax.SAXException;
23 
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.security.NoSuchAlgorithmException;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.List;
34 
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.transform.TransformerException;
37 import javax.xml.transform.TransformerFactoryConfigurationError;
38 
39 /**
40  * Main console of CTS providing user with the interface to interact. <BR>
41  * Using CommandParser to parse command line argument and process.
42  * <ul>
43  *    <li> start a test plan
44  *    <li> remove a test plan
45  *    <li> add a test package
46  *    <li> remove a test package
47  *    <li> list current available devices
48  *    <li> list current available test plan
49  *    <li> list current available package
50  *    <li> list current test result
51  *    <li> view CTS' status, uninitialized, idle or running
52  *    <li> view command history
53  *    <li> select a history command to run
54  * </ul>
55  */
56 public class ConsoleUi {
57 
58     private static final String OS_NAME_LINUX = "Linux";
59     private static final String LS_PLAN_SEPARATOR = "=================================";
60     private static final String CMD_TYPE_LEADING_SPACE = "  ";
61     private static final String CMD_OPT_LEADING_SPACE = "    ";
62     private static final String CREATE_SESSION = "create a new session";
63     private static final String CHOOSE_SESSION = "choose a session";
64 
65     private TestHost mHost;
66     private boolean mKeepRunning;
67     private BufferedReader mCommandInput;
68     // private static ConsoleInputStream sConsoleReader;
69     private CommandHistory mCommandHistory = new CommandHistory();
70     private String mOsName = "none";
71 
72     // Define test case name pattern
73     static final String CASE_NAME_PATTERN_STR = "((\\S+\\.)+\\S+)\\.(\\S+):(\\S+)";
74     private static HashMap<String, Integer> mResultCodeMap;
75 
76     static {
77         mResultCodeMap = new HashMap<String, Integer>();
mResultCodeMap.put(CtsTestResult.STR_PASS, CtsTestResult.CODE_PASS)78         mResultCodeMap.put(CtsTestResult.STR_PASS, CtsTestResult.CODE_PASS);
mResultCodeMap.put(CtsTestResult.STR_FAIL, CtsTestResult.CODE_FAIL)79         mResultCodeMap.put(CtsTestResult.STR_FAIL, CtsTestResult.CODE_FAIL);
mResultCodeMap.put(CtsTestResult.STR_ERROR, CtsTestResult.CODE_ERROR)80         mResultCodeMap.put(CtsTestResult.STR_ERROR, CtsTestResult.CODE_ERROR);
mResultCodeMap.put(CtsTestResult.STR_NOT_EXECUTED, CtsTestResult.CODE_NOT_EXECUTED)81         mResultCodeMap.put(CtsTestResult.STR_NOT_EXECUTED, CtsTestResult.CODE_NOT_EXECUTED);
mResultCodeMap.put(CtsTestResult.STR_TIMEOUT, CtsTestResult.CODE_TIMEOUT)82         mResultCodeMap.put(CtsTestResult.STR_TIMEOUT, CtsTestResult.CODE_TIMEOUT);
83     }
84 
ConsoleUi(TestHost host)85     public ConsoleUi(TestHost host) {
86         mHost = host;
87         mCommandInput = new BufferedReader(new InputStreamReader(System.in));
88         mKeepRunning = true;
89 
90         initInputStream();
91     }
92 
93     /**
94      * Start the console user interface.
95      *
96      */
startUi()97     public void startUi() {
98         while (mKeepRunning) {
99             try {
100                 String cmdLine = readLine(CUIOutputStream.CTS_PROMPT_SIGN);
101                 CommandParser cp = CommandParser.parse(cmdLine);
102                 processCommand(cp);
103                 mCommandHistory.addCommand(cp, cmdLine);
104             } catch (CommandNotFoundException e) {
105                 // avoid displaying help message for empty
106                 // command by pressing ENTER over console directly
107             } catch (Exception e) {
108                 Log.e("Got exception while processing command.", e);
109                 showHelp();
110             }
111         }
112     }
113 
114     /**
115      * Initialize the CommandProcessor.
116      */
initInputStream()117     private void initInputStream() {
118         // mOsName = System.getProperty("os.name");
119         if (mOsName.equals(OS_NAME_LINUX)) {
120             // sConsoleReader = new ConsoleInputStream(new FileInputStream(
121             // FileDescriptor.in), mCommandHistory);
122             // sConsoleReader.setup();
123         } else {
124             mCommandInput = new BufferedReader(new InputStreamReader(System.in));
125         }
126     }
127 
128     /**
129      * Read a message line from console.
130      *
131      * @param prompt The notification message print out to console before reading.
132      * @return The string user typed in.
133      */
readLine(String prompt)134     private String readLine(String prompt) throws IOException {
135         String cmdLine = null;
136         if (mOsName.equals(OS_NAME_LINUX)) {
137             // cmdLine = sConsoleReader.readLine(prompt).trim();
138         } else {
139             CUIOutputStream.print(prompt);
140             cmdLine = mCommandInput.readLine().trim();
141         }
142         return cmdLine;
143     }
144 
145     /**
146      * Display the help message.
147      */
showHelp()148     private void showHelp() {
149         CUIOutputStream.println("Usage: command options");
150         CUIOutputStream.println("Avaiable commands and options:");
151         showHostCmdHelp();
152         showPlanCmdHelp();
153         showPackageCmdHelp();
154         showResultCmdHelp();
155         showHistoryCmdHelp();
156         showDeviceCmdHelp();
157     }
158 
159     /**
160      * Display the help message related to history commands.
161      */
showHistoryCmdHelp()162     private void showHistoryCmdHelp() {
163         final String cmdStr = CTSCommand.HISTORY + "/" + CTSCommand.H;
164 
165         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "History:");
166         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
167                 + cmdStr + ": list all commands in command history");
168         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
169                 + cmdStr + " count: list the latest count records in command history");
170         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
171                 + cmdStr + " " + CTSCommand.OPTION_E
172                 + " num: run the command designated by 'num' in command history");
173     }
174 
175     /**
176      * Display the help message related to result commands.
177      */
showResultCmdHelp()178     private void showResultCmdHelp() {
179         final String cmdStr = CTSCommand.LIST + " " + CTSCommand.OPTION_R
180                 + "/" + CTSCommand.OPTION_RESULT;
181         final String sessionStr = CTSCommand.OPTION_S + "/" + CTSCommand.OPTION_SESSION;
182         final String resultsStr = " [" + CtsTestResult.STR_PASS
183                        + "/" + CtsTestResult.STR_FAIL
184                        + "/" + CtsTestResult.STR_NOT_EXECUTED
185                        + "/" + CtsTestResult.STR_TIMEOUT
186                        + "] ";
187 
188         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Result:");
189         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
190                 + cmdStr + ": list all result of sessions");
191         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
192                 + cmdStr + " " + sessionStr
193                 + " session_id: list detail case result of a specified session");
194         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
195                 + cmdStr + resultsStr + sessionStr
196                 + " session_id: list detail cases of a specified"
197                 + " session by the specified result.");
198     }
199 
200     /**
201      * Display the help message related to package commands.
202      */
showPackageCmdHelp()203     private void showPackageCmdHelp() {
204         final String cmdStr = CTSCommand.LIST + " " + CTSCommand.OPTION_P
205                 + "/" + CTSCommand.OPTION_PACKAGE;
206         final String pkgStr = CTSCommand.OPTION_P + "/" + CTSCommand.OPTION_PACKAGE;
207 
208         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Package:");
209         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
210                 + cmdStr + ": list available packages");
211         CUIOutputStream.println(CMD_OPT_LEADING_SPACE + cmdStr + " package_name: "
212                 + "list contents of the package with specified name");
213 
214         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
215                 + CTSCommand.ADD + " " + pkgStr
216                 + " root: add packages from root to repository");
217         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
218                 + CTSCommand.REMOVE + " " + pkgStr + " package_name/all: "
219                 + "remove a package or all packages from repository");
220     }
221 
222     /**
223      * Display the help message related to plan commands.
224      */
showPlanCmdHelp()225     private void showPlanCmdHelp() {
226         final String lsPlanStr = CTSCommand.LIST + " " + CTSCommand.OPTION_PLAN;
227         final String addPlanStr = CTSCommand.ADD + " " + CTSCommand.OPTION_PLAN;
228         final String rmPlanStr = CTSCommand.REMOVE + " " + CTSCommand.OPTION_PLAN;
229         final String addDerivedPlanStr = CTSCommand.ADD + " " + CTSCommand.OPTION_DERIVED_PLAN;
230 
231         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Plan:");
232         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
233                 + lsPlanStr + ": list available plans");
234         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
235                 + lsPlanStr + " plan_name: list contents of the plan with specified name");
236         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
237                 + addPlanStr + " plan_name: add a new plan with specified name");
238         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
239                 + addDerivedPlanStr + " plan_name "
240                 + CTSCommand.OPTION_S + "/" + CTSCommand.OPTION_SESSION + " session_id "
241                 + CTSCommand.OPTION_R + "/" + CTSCommand.OPTION_RESULT + " result_type"
242                 + ": derive a plan from the given session");
243         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
244                 + rmPlanStr + " plan_name/all: remove a plan or all plans from repository");
245         showStartSessionHelp();
246     }
247 
248     /**
249      * Display the help message related to start session command.
250      */
showStartSessionHelp()251     private void showStartSessionHelp() {
252         final String cmdStr = CTSCommand.START + " " + CTSCommand.OPTION_PLAN;
253         final String testStr = CTSCommand.OPTION_T + "/" + CTSCommand.OPTION_TEST;
254         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
255         final String pkgStr = CTSCommand.OPTION_P + "/" + CTSCommand.OPTION_PACKAGE;
256 
257         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
258                 + cmdStr + " test_plan_name: run a test plan");
259         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
260                 + cmdStr + " test_plan_name " + deviceStr + " device_ID: "
261                 + "run a test plan using the specified device");
262         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
263             + cmdStr + " test_plan_name " + testStr + " test_name: run a specific test");
264         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
265                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name: "
266                 + "run a specific java package");
267         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
268                 + cmdStr + " test_plan_name " + testStr + " test_name "
269                 + deviceStr + " device_ID: run a specific test using the specified device");
270         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
271                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name "
272                 + deviceStr + " device_ID: "
273                 + "run a specific java package using the specified device");
274     }
275 
276     /**
277      * Display the help message related to host commands.
278      */
showHostCmdHelp()279     private void showHostCmdHelp() {
280         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Host:");
281         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
282                 + CTSCommand.HELP + ": show this message");
283         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
284                 + CTSCommand.EXIT + ": exit cts command line");
285     }
286 
287     /**
288      * Display the help message related to device commands.
289      */
showDeviceCmdHelp()290     private void showDeviceCmdHelp() {
291         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
292 
293         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Device:");
294         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
295                 + CTSCommand.LIST + " " + deviceStr + ": list available devices");
296     }
297 
298     /**
299      * Process the command from user's input.
300      *
301      * @param cp Command container.
302      */
processCommand(final CommandParser cp)303     public void processCommand(final CommandParser cp) throws Exception {
304         String action = cp.getAction();
305 
306         if (action.equals(CTSCommand.EXIT)) {
307             if (cp.getArgSize() != 1) {
308                 showHelp();
309                 return;
310             }
311             Log.d("exit cts host");
312             mKeepRunning = false;
313             mHost.tearDown();
314         } else if (action.equals(CTSCommand.HELP)) {
315             showHelp();
316         } else if (mCommandHistory.isHistoryCommand(action)) {
317             processHistoryCommands(cp);
318         } else if (action.equals(CTSCommand.ADD)) {
319             processAddCommand(cp);
320         } else if (action.equals(CTSCommand.START)) {
321             processStartCommand(cp);
322         } else if (action.equals(CTSCommand.REMOVE)) {
323             processRmCommand(cp);
324         } else if (action.equals(CTSCommand.LIST)) {
325             processListCommand(cp);
326         } else {
327             showHelp();
328         }
329     }
330 
331     /**
332      * Process start command.
333      *
334      * @param cp Command container.
335      */
processStartCommand(CommandParser cp)336     private void processStartCommand(CommandParser cp) throws SAXException,
337             ParserConfigurationException {
338         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
339             processStartSessionCommand(cp);
340         } else if (cp.containsKey(CTSCommand.OPTION_P)
341                 || cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
342             processStartPackageCommand(cp);
343         } else {
344             showHelp();
345         }
346     }
347 
348     /**
349      * Process start package command.
350      *
351      * <ul>
352      *     <li> Syntax:
353      *            start --package zipped-package-file
354      * </ul>
355      * @param cp Command container.
356      */
processStartPackageCommand(CommandParser cp)357     private void processStartPackageCommand(CommandParser cp) {
358         try {
359             String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
360             mHost.startZippedPackage(pathName);
361         } catch (DeviceDisconnectedException e) {
362           Log.e("Device " + e.getMessage() + " disconnected", e);
363         } catch (Exception e) {
364             Log.e("Met exception during running zipped package.", e);
365         }
366     }
367 
368     /**
369      * Validate the command parameters used to activate CTS.
370      *
371      * @param cp Command container.
372      * @return If command parameters are valid, return true; else, return false.
373      */
validateCommandParams(CommandParser cp)374     public boolean validateCommandParams(CommandParser cp) {
375         if (cp == null) {
376             return false;
377         }
378 
379         if (cp.getAction() == null) {
380             return true;
381         } else if (isValidCommandOption(cp, CTSCommand.START,
382                 CTSCommand.OPTION_PLAN)) {
383             return true;
384         } else if (isValidCommandOption(cp, CTSCommand.START,
385                 CTSCommand.OPTION_PACKAGE)) {
386             return true;
387         } else if (isValidCommandOption(cp, CTSCommand.START,
388                 CTSCommand.OPTION_P)) {
389             return true;
390         } else {
391             return false;
392         }
393     }
394 
395     /**
396      * Check if the command option is valid.
397      *
398      * @param cp CommandParser which contains the command and options.
399      * @param command Command the user typed in.
400      * @param option Option the user typed in.
401      * @return If command option valid, return true; else, return false.
402      */
isValidCommandOption(CommandParser cp, String command, String option)403     private static boolean isValidCommandOption(CommandParser cp,
404             String command, String option) {
405         return (cp.getAction().equals(command)) && (cp.containsKey(option))
406                 && (cp.getValue(option) != null)
407                 && (cp.getValue(option).length() != 0);
408     }
409 
410     /**
411      * Process start session command.
412      * <ul>
413      *     <li> Syntax 1:
414      *            start --plan plan-name
415      *              [ --device device-id ]
416      *              [ --test test-name ]
417      *     <li> Syntax 2:
418      *            start --plan plan-name
419      *              [ --device device-id ]
420      *              [ --package java-package-name ]
421      * </ul>
422      * @param cp container which contained start command options and values
423      *           Process the list commands.
424      */
processStartSessionCommand(CommandParser cp)425     private void processStartSessionCommand(CommandParser cp)
426             throws SAXException, ParserConfigurationException {
427 
428         if (mHost.getDeviceList().length == 0) {
429             Log.e("No device connected", null);
430             return;
431         }
432 
433         String testPlanPath = null;
434         String deviceId = null;
435         String testName = null;
436         String javaPkgName = null;
437         String testPlanName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
438         try {
439             if (cp.getActionValues().size() != 0 || cp.getOptionSize() < 1
440                     || cp.getOptionSize() > 3) {
441                 showStartSessionHelp();
442                 return;
443             }
444             testPlanName = mHost.getPlanName(cp
445                     .getValue(CTSCommand.OPTION_PLAN));
446             testPlanPath = HostConfig.getInstance().getPlanRepository()
447                     .getPlanPath(testPlanName);
448             if (testPlanPath == null) {
449                 CUIOutputStream.println("Plan " + testPlanName
450                         + " is not in repository, please create it!");
451                 return;
452             }
453 
454             if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
455                 deviceId = cp.getValue(CTSCommand.OPTION_DEVICE);
456                 String[] deviceIdList = deviceId.trim().split(",");
457                 if (deviceIdList.length > 1) {
458                     Log.e("Just allow choosing one device ID.", null);
459                     return;
460                 }
461             }
462 
463             ActionType actionType = ActionType.START_NEW_SESSION;
464             if (cp.containsKey(CTSCommand.OPTION_TEST)) {
465                 testName = cp.getValue(CTSCommand.OPTION_TEST);
466                 if (-1 == testName.indexOf(Test.METHOD_SEPARATOR)) {
467                     Log.e("Test full name must be in the form of:"
468                             + " java_package_name.class_name#method_name.", null);
469                     return;
470                 }
471                 actionType = ActionType.RUN_SINGLE_TEST;
472             } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
473                 javaPkgName = cp.getValue(CTSCommand.OPTION_PACKAGE);
474                 actionType = ActionType.RUN_SINGLE_JAVA_PACKAGE;
475             }
476 
477             TestSession ts = null;
478             ArrayList<TestSession> sessionList = mHost.getSessionList(testPlanName);
479             if ((sessionList != null) && (sessionList.size() > 0)) {
480                 if ((testName == null) || (testName.length() == 0)) {
481                     String mode = chooseMode(sessionList);
482                     if (CREATE_SESSION.equals(mode)) {
483                         ts = TestHost.createSession(testPlanName);
484                     }
485                 }
486                 if (ts == null) {
487                     ts = chooseTestSession(sessionList);
488                     deviceId = ts.getDeviceId();
489                     if ((actionType != ActionType.RUN_SINGLE_TEST)
490                             && (actionType != ActionType.RUN_SINGLE_JAVA_PACKAGE)) {
491                         actionType = ActionType.RESUME_SESSION;
492                     }
493                 }
494             }
495 
496             if (deviceId == null) {
497                 TestDevice td = mHost.getFirstAvailableDevice();
498                 if (td == null) {
499                     // no devices attached
500                     CUIOutputStream.println("No idle devices found.");
501                     return;
502                 }
503                 deviceId = td.getSerialNumber();
504             }
505 
506             if (!checkDeviceExists(mHost.getDeviceList(), deviceId)) {
507                 CUIOutputStream.println("Can't find specified device id.  Is it attached?");
508                 return;
509             }
510 
511             if (ts == null) {
512                 ts = TestHost.createSession(testPlanName);
513             }
514             mHost.startSession(ts, deviceId, testName, javaPkgName, actionType);
515         } catch (IOException e) {
516             Log.e("Can't create test session", e);
517         } catch (DeviceNotAvailableException e) {
518             CUIOutputStream.println("Test plan(" + testPlanName + ") "
519                     + e.getMessage());
520             showStartSessionHelp();
521         } catch (TestNotFoundException e) {
522             CUIOutputStream.println(e.getMessage());
523         } catch (TestPlanNotFoundException e) {
524             CUIOutputStream.println("Can't find test plan " + testPlanName);
525         } catch (IllegalTestNameException e) {
526             CUIOutputStream.println("Illegal case name: " + testName);
527         } catch (DeviceDisconnectedException e) {
528             Log.e("Device " + e.getMessage() + " disconnected ", null);
529         } catch (NoSuchAlgorithmException e) {
530             Log.e("Fail to initialise SHA-1 algorithm", e);
531         } catch (InvalidApkPathException e) {
532             Log.e(e.getMessage(), null);
533         } catch (InvalidNameSpaceException e) {
534             Log.e(e.getMessage(), null);
535         }
536     }
537 
538     /**
539      * Choose test session among the available test session list.
540      *
541      * @param sessionList The available test session list.
542      * @return The test session chosen.
543      */
chooseTestSession(ArrayList<TestSession> sessionList)544     private TestSession chooseTestSession(ArrayList<TestSession> sessionList) throws IOException {
545         if ((sessionList == null) || (sessionList.size() == 0)) {
546             return null;
547         }
548 
549         if (sessionList.size() == 1) {
550             return sessionList.get(0);
551         }
552 
553         int index = 0;
554         String notification = "Please choose a session from the existed session(s):\n";
555         for (TestSession session : sessionList) {
556             notification += "  " + session.getId() + "  [" + index + "] \n";
557             index ++;
558         }
559 
560         return sessionList.get(getUserInputId(notification, 0, index));
561     }
562 
563     /**
564      * Choose  between creating a new session and choosing a session among available ones.
565      *
566      * @param sessionList The available test session list.
567      * @return If choose to create a new session, return CREATE_SESSION;
568      *         else return CHOOSE_SESSION.
569      */
chooseMode(ArrayList<TestSession> sessionList)570     private String chooseMode(ArrayList<TestSession> sessionList) throws IOException {
571         if (TestHost.sMode == MODE.RUN || (sessionList == null) || (sessionList.size() == 0)) {
572             // do not prompt if the test run was started from command line mode, or when
573             // there are no existing sessions
574             return CREATE_SESSION;
575         }
576 
577         String planName = sessionList.get(0).getSessionLog().getTestPlanName();
578         String notification = "There are " + sessionList.size()
579             + " existing session(s) for plan " + planName + ".\n"
580             + "Create a new session or choose an existing one?\n"
581             + "  Create a new session [0]\n"
582             + "  Choose a session     [1]\n";
583 
584         int indexSelected = getUserInputId(notification, 0, 2);
585         if (indexSelected == 0) {
586             return CREATE_SESSION;
587         } else {
588             return CHOOSE_SESSION;
589         }
590     }
591 
592     /**
593      * Validate the specified device ID against the available device array.
594      *
595      * @param availableDevices The available device array.
596      * @param specifiedId The specified device ID list.
597      * @return true if the id is valid
598      */
checkDeviceExists(TestDevice[] availableDevices, String specifiedId)599     public boolean checkDeviceExists(TestDevice[] availableDevices, String specifiedId) {
600         for (TestDevice dev : availableDevices) {
601             if (specifiedId.equals(dev.getSerialNumber())) {
602                 return true;
603             }
604         }
605         return false;
606     }
607 
608     /**
609      * Get device ID from the device ID string against the available devices.
610      *
611      * @param availableDevices The available devices.
612      * @param idStr The device ID string.
613      * @return The device ID.
614      */
getDeviceId(TestDevice[] availableDevices, String idStr)615     public int getDeviceId(TestDevice[] availableDevices, String idStr) {
616         for (int i = 0; i < availableDevices.length; i++) {
617             TestDevice dev = availableDevices[i];
618             if (idStr.equals(dev.getSerialNumber())) {
619                 return i;
620             }
621         }
622         return -1;
623     }
624 
625     /**
626      * Get the ID input by the against the specified range.
627      *
628      * @param notification The notification message to notify the user.
629      * @param startIndex The start index.
630      * @param endIndex The end index.
631      * @return The selected index of the ID the user chosen.
632      */
getUserInputId(String notification, int startIndex, int endIndex)633     private int getUserInputId(String notification, int startIndex, int endIndex)
634                 throws IOException {
635         int indexSelected = 0;
636         boolean success = false;
637         while (!success) {
638             String answer = readLine(notification);
639             try {
640                 indexSelected = Integer.parseInt(answer);
641                 if ((indexSelected >= 0) && (indexSelected < endIndex)) {
642                     success = true;
643                 } else {
644                     CUIOutputStream.println("" + indexSelected
645                             + " is out of range [0," + (endIndex -1 ) + "].");
646                 }
647             } catch (NumberFormatException e) {
648                 CUIOutputStream.println("Invalid nuber is typed in.");
649             }
650         }
651         return indexSelected;
652     }
653 
654     /**
655      * Check if the specified device ID is valid.
656      *
657      * @param numOfAvailableDevices The number of available devices.
658      * @param specifiedId The specified device ID.
659      * @return If the specified ID contained in available ID list,
660      *         return true; else, return false.
661      */
isValidDeviceId(int numOfAvailableDevices, int specifiedId)662     public boolean isValidDeviceId(int numOfAvailableDevices, int specifiedId) {
663         if (specifiedId < 0 || specifiedId >= numOfAvailableDevices) {
664             return false;
665         }
666         return true;
667     }
668 
669     /**
670      * Process list commands.
671      * <ul>
672      *     <li> Syntax 1:
673      *            ls --device
674      *     <li> Syntax 2:
675      *            ls --plan [ plan-name ]
676      *     <li> Syntax 3:
677      *            ls --package [ package-name ]
678      *     <li> Syntax 4:
679      *            ls --result
680      *              [ pass/fail/notExecuted/timeout ]
681      *              [ --session session_id ]
682      * </ul>
683      *
684      * @param cp Command container.
685      */
processListCommand(CommandParser cp)686     private void processListCommand(CommandParser cp) throws SAXException,
687             IOException, ParserConfigurationException {
688         if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
689             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
690                 showDeviceCmdHelp();
691                 return;
692             }
693             if (cp.getValue(CTSCommand.OPTION_DEVICE).equals("")) {
694                 listDevices();
695             } else {
696                 showDeviceCmdHelp();
697             }
698         } else if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
699             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
700                 showPlanCmdHelp();
701                 return;
702             }
703             String planValue = cp.getValue(CTSCommand.OPTION_PLAN);
704             if (planValue.equals("")) {
705                 listPlans();
706             } else {
707                 listSinglePlan(mHost.getPlanName(planValue));
708             }
709         } else if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
710             if (cp.getActionValues().size() != 0
711                     || (cp.getOptionSize() < 1 || cp.getOptionSize() > 2)) {
712                 showResultCmdHelp();
713                 return;
714             }
715             String resultValue = cp.getValue(CTSCommand.OPTION_RESULT);
716             String sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
717             Integer resultCode = null;
718 
719             if (sessionId != null) {
720                 if (resultValue.length() != 0
721                         && !mResultCodeMap.containsKey(resultValue)) {
722                     showResultCmdHelp();
723                 } else {
724                     resultCode = mResultCodeMap.get(resultValue);
725                     listSessionResult(sessionId, resultCode);
726                 }
727             } else if (resultValue.length() == 0) {
728                 listResults();
729             } else {
730                 showHelp();
731             }
732         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
733             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
734                 showPackageCmdHelp();
735                 return;
736             }
737             listPackages(cp);
738         } else {
739             showHelp();
740         }
741     }
742 
743     /**
744      * Process the removing commands.
745      * <ul>
746      *     <li> Syntax 1:
747      *            rm --plan [ plan-name ] [ all ]
748      *     <li> Syntax 2:
749      *            rm --package [ package-name ] [ all ]
750      * </ul>
751      *
752      * @param cp Command container.
753      */
processRmCommand(CommandParser cp)754     private void processRmCommand(CommandParser cp) throws IOException {
755         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
756             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
757                 showPlanCmdHelp();
758                 return;
759             }
760 
761             String planName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
762             if (HostConfig.ALL.equals(planName)) {
763                 String prompt = "Remove all of the plans?([y/N])";
764                 String answer = readLine(prompt).trim();
765                 if (!isConfirmation(answer, false)) {
766                     return;
767                 }
768             }
769 
770             mHost.removePlans(planName);
771         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
772             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
773                 showPackageCmdHelp();
774                 return;
775             }
776 
777             String packageName = cp.getValue(CTSCommand.OPTION_PACKAGE);
778             if (HostConfig.ALL.equals(packageName)) {
779                 String prompt = "Remove all of the packages?([y/N])";
780                 String answer = readLine(prompt).trim();
781                 if (!isConfirmation(answer, false)) {
782                     return;
783                 }
784             }
785 
786             mHost.removePackages(packageName);
787         } else {
788             showHelp();
789         }
790     }
791 
792     /**
793      * Check if the answer is confirmation.
794      *
795      * @param answer The answer user typed in.
796      * @param defaultResult If true, default to yes; else, default to no.
797      * @return If confirmation, return true; else, return false.
798      */
isConfirmation(String answer, boolean defaultResult)799     public static boolean isConfirmation(String answer, boolean defaultResult) {
800         if ("".equals(answer)) {
801             return defaultResult;
802         }
803 
804         return ("y".equals(answer.toLowerCase()) || "yes".equals(answer.toLowerCase()));
805     }
806 
807     /**
808      * Process the add commands.
809      * <ul>
810      *     <li> Syntax 1:
811      *            add --plan plan-name
812      *     <li> Syntax 2:
813      *            add --package package-name
814      * </ul>
815      *
816      * @param cp Command container.
817      */
processAddCommand(CommandParser cp)818     private void processAddCommand(CommandParser cp) {
819         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
820             if (isValidAddPlanArguments(cp)) {
821                 createPlan(cp, CTSCommand.OPTION_PLAN);
822             } else {
823                 showPlanCmdHelp();
824             }
825         } else if (cp.containsKey(CTSCommand.OPTION_DERIVED_PLAN)) {
826             if (isValidDerivedPlanArguments(cp)) {
827                 createPlan(cp, CTSCommand.OPTION_DERIVED_PLAN);
828             } else {
829                 showPlanCmdHelp();
830             }
831         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
832             try {
833                 addPackage(cp);
834             } catch (IOException e) {
835                 Log.e("Can't add package", e);
836             } catch (IndexOutOfBoundsException e) {
837                 Log.e("Can't add package", e);
838             } catch (NoSuchAlgorithmException e) {
839                 Log.e("Can't add package", e);
840             }
841         } else {
842             showHelp();
843         }
844     }
845 
846     /**
847      * Check if it's valid arguments for adding plan.
848      *
849      * @param cp The command processor.
850      * @return if valid, return true; else, return false.
851      */
isValidAddPlanArguments(CommandParser cp)852     private boolean isValidAddPlanArguments(CommandParser cp) {
853         return (cp.getArgSize() == 3) && (cp.getActionValues().size() == 0)
854                 && (cp.getOptionSize() == 1);
855     }
856 
857     /**
858      * Check if it's valid arguments for deriving plan.
859      *
860      * @param cp The command processor.
861      * @return if valid, return true; else, return false.
862      */
isValidDerivedPlanArguments(CommandParser cp)863     private boolean isValidDerivedPlanArguments(CommandParser cp) {
864         //argument size: it's at least 3, as "add --plan plan_name"
865         //action values: no option contains more than one value
866         //option size: it's at least 1, as "add --plan plan_name"
867         return (cp.getArgSize() >= 3) && (cp.getActionValues().size() == 0)
868                 && (cp.getOptionSize() >= 1);
869     }
870 
871     /**
872      * Process the history commands.
873      * <ul>
874      *     <li> Syntax:
875      *            history [ -e ] [ number]
876      * </ul>
877      *
878      * @param cp Command container.
879      */
processHistoryCommands(final CommandParser cp)880     private void processHistoryCommands(final CommandParser cp)
881             throws Exception {
882         try {
883             if ((cp.getOptionSize() == 0) && (cp.getActionValues().size() == 0)) {
884                 mCommandHistory.show(mCommandHistory.size());
885             } else if (cp.containsKey(CTSCommand.OPTION_E)
886                     && (cp.getActionValues().size() == 0)) {
887                 int cmdNum = 0;
888                 cmdNum = Integer.parseInt(cp.getValue(CTSCommand.OPTION_E));
889                 if (cmdNum >= 0 && cmdNum < mCommandHistory.size()) {
890                     String cmdLine = mCommandHistory.get(cmdNum);
891                     CommandParser cpH = CommandParser.parse(cmdLine);
892                     CUIOutputStream.printPrompt();
893                     CUIOutputStream.println(cmdLine);// print(CTS_PROMPT_SIGN
894                                                         // + cmdLine);
895                     processCommand(cpH);
896                     mCommandHistory.addCommand(cpH, cmdLine);
897                 } else {
898                     if (mCommandHistory.size() > 0) {
899                         Log.e("Command index " + cmdNum
900                                 + " is out of command history range [0,"
901                                 + (mCommandHistory.size() - 1) + "].", null);
902                     } else {
903                         Log.e("No command exists in command history.", null);
904                     }
905                 }
906             } else if ((cp.getOptionSize() == 0)
907                     && (cp.getActionValues().size() == 1)) {
908                 int cmdCount = Integer.parseInt(cp.getActionValues().iterator()
909                         .next());
910                 if (cmdCount < 0 || cmdCount > mCommandHistory.size()) {
911                     cmdCount = mCommandHistory.size();
912                 }
913                 mCommandHistory.show(cmdCount);
914             } else {
915                 showHistoryCmdHelp();
916             }
917 
918         } catch (NumberFormatException e) {
919             showHistoryCmdHelp();
920         }
921     }
922 
923     /**
924      * List a single plan by the plan name given.
925      *
926      * @param name The plan name.
927      */
listSinglePlan(String name)928     private void listSinglePlan(String name) throws SAXException, IOException,
929             ParserConfigurationException {
930         String planName = null;
931         for (String str : mHost.getPlanRepository().getAllPlanNames()) {
932             if (str.startsWith(name)) {
933                 planName = str;
934                 break;
935             }
936         }
937 
938         if (planName == null) {
939             Log.e("No plan named " + name + " in repository!", null);
940             return;
941         }
942 
943         String planPath = mHost.getPlanRepository().getPlanPath(planName);
944         ArrayList<String> removedPkgList = new ArrayList<String>();
945         Collection<String> pkgNames = TestPlan.getEntries(planPath, removedPkgList);
946 
947         if (removedPkgList.size() != 0) {
948             CUIOutputStream.println("The following package(s) contained in plan "
949                     + planName + " have been removed:");
950             for (String pkgName : removedPkgList) {
951                 CUIOutputStream.println("    " + pkgName);
952             }
953         }
954 
955         if (pkgNames.size() > 0) {
956             CUIOutputStream.println("Packages of plan " + planName
957                     + " (" + pkgNames.size() + " in total):");
958             CUIOutputStream.println(LS_PLAN_SEPARATOR);
959             for (String pkgName : pkgNames) {
960                 CUIOutputStream.println(pkgName);
961             }
962         }
963     }
964 
965     /**
966      * Create test plan via the test session and result type given.
967      *
968      * @param name The test plan name.
969      * @param ts The test session.
970      * @param resultType The result type.
971      */
createPlanFromSession(final String name, TestSession ts, final String resultType)972     private void createPlanFromSession(final String name, TestSession ts, final String resultType)
973             throws FileNotFoundException, ParserConfigurationException,
974             TransformerFactoryConfigurationError, TransformerException {
975 
976         HashMap<String, ArrayList<String>> selectedResult =
977             new HashMap<String, ArrayList<String>>();
978         ArrayList<String> packageNames = new ArrayList<String>();
979 
980         for (TestPackage pkg : ts.getSessionLog().getTestPackages()) {
981             String pkgName = pkg.getAppPackageName();
982             ArrayList<String> excludedList = pkg.getExcludedList(resultType);
983             if (excludedList != null) {
984                 packageNames.add(pkgName);
985                 selectedResult.put(pkgName, excludedList);
986             }
987         }
988 
989         if ((selectedResult != null) && (selectedResult.size() > 0)) {
990             TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
991         } else {
992             if (resultType == null) {
993                 Log.i("All tests of session " + ts.getId()
994                         + " have passed execution. The plan is not created!");
995             } else {
996                 Log.i("No " + resultType +  " tests of session " + ts.getId()
997                         + ". The plan is not created!");
998             }
999         }
1000     }
1001 
1002     /**
1003      * Add a derived plan from a given session.
1004      *
1005      * @param cp Command container.
1006      * @param name The plan name.
1007      * @param packageNames The package name list.
1008      */
addDerivedPlan(final CommandParser cp, final String name, ArrayList<String> packageNames)1009     private void addDerivedPlan(final CommandParser cp, final String name,
1010             ArrayList<String> packageNames) {
1011 
1012         try {
1013             String sessionId = null;
1014             String resultType = null;
1015             int id = TestSession.getLastSessionId();
1016 
1017             if (cp.containsKey(CTSCommand.OPTION_SESSION)) {
1018                 sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
1019                 id = Integer.parseInt(sessionId);
1020             }
1021             TestSession ts = mHost.getSession(id);
1022             if (ts == null) {
1023                 Log.e("The session ID of " + id + " doesn't exist.", null);
1024                 return;
1025             }
1026 
1027             if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
1028                 resultType = cp.getValue(CTSCommand.OPTION_RESULT);
1029                 if (!CtsTestResult.isValidResultType(resultType)) {
1030                     Log.e("The following result type is invalid: " + resultType, null);
1031                     return;
1032                 }
1033             }
1034             createPlanFromSession(name, ts, resultType);
1035         } catch (Exception e) {
1036             Log.e("Got exception while trying to add a plan!", e);
1037             return;
1038         }
1039     }
1040 
1041     /**
1042      * Add a plan by the plan name given.
1043      *
1044      * @param cp Command container.
1045      * @param name The plan name.
1046      * @param packageNames The package name list.
1047      */
addPlan(final CommandParser cp, final String name, ArrayList<String> packageNames)1048     private void addPlan(final CommandParser cp, final String name,
1049             ArrayList<String> packageNames) {
1050 
1051         try {
1052             PlanBuilder planBuilder = new PlanBuilder(packageNames);
1053 
1054             if (mOsName.equals(OS_NAME_LINUX)) {
1055                 // planBuilder.setInputStream(sConsoleReader);
1056             } else {
1057                 planBuilder.setInputStream(mCommandInput);
1058             }
1059 
1060             HashMap<String, ArrayList<String>> selectedResult = planBuilder.doSelect();
1061             if (selectedResult != null) {
1062                 TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
1063             } else {
1064                 Log.i("Selected nothing for the plan of " + name + ". The plan is not created!");
1065             }
1066         } catch (Exception e) {
1067             Log.e("Got exception while trying to add a plan!", e);
1068             return;
1069         }
1070     }
1071 
1072     /**
1073      * Create a plan.
1074      *
1075      * @param cp Command container.
1076      * @param type the action type.
1077      */
createPlan(final CommandParser cp, final String type)1078     private void createPlan(final CommandParser cp, final String type) {
1079         String name = null;
1080         if (CTSCommand.OPTION_PLAN.equals(type)) {
1081             name = cp.getValue(CTSCommand.OPTION_PLAN);
1082         } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
1083             name = cp.getValue(CTSCommand.OPTION_DERIVED_PLAN);
1084         } else {
1085             return;
1086         }
1087 
1088         if (HostUtils.isFileExist(HostConfig.getInstance().getPlanRepository()
1089                 .getPlanPath(name)) == true) {
1090             Log.e("Plan " + name + " already exist, please use another name!", null);
1091             return;
1092         }
1093 
1094         try {
1095             if ((name != null) && (!name.matches("\\w+"))) {
1096                 CUIOutputStream.println("Only letter of the alphabet, number and '_'"
1097                         + " are available for test plan name");
1098                 return;
1099             }
1100 
1101             ArrayList<String> packageNames =
1102                 HostConfig.getInstance().getCaseRepository().getPackageNames();
1103             Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
1104             if (testPackages.size() == 0) {
1105                 CUIOutputStream.println("No package found in repository, please add package first!");
1106                 return;
1107             }
1108             if (CTSCommand.OPTION_PLAN.equals(type)) {
1109                 addPlan(cp, name, packageNames);
1110             } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
1111                 addDerivedPlan(cp, name, packageNames);
1112             }
1113         } catch (Exception e) {
1114             Log.e("Got exception while trying to add a plan!", e);
1115             return;
1116         }
1117     }
1118 
1119     /**
1120      * List all of the plans in the plan repository.
1121      */
listPlans()1122     private void listPlans() {
1123         ArrayList<String> plans = mHost.getPlanRepository().getAllPlanNames();
1124 
1125         if (plans.size() == 0) {
1126             CUIOutputStream.println("No plan created!");
1127         } else {
1128             CUIOutputStream.println("List of plans (" + plans.size() + " in total):");
1129             for (String name : plans) {
1130                 CUIOutputStream.println(name);
1131             }
1132         }
1133     }
1134 
1135     /**
1136      * List detailed case result of specified session. The result can be
1137      * filtered, if resultType isn't null, by the specified resultType.
1138      *
1139      * @param idStr the session id.
1140      * @param resultType the type of result, [pass, fail, notExecuted, timeout, null].
1141      */
listSessionResult(final String idStr, final Integer resultType)1142     private void listSessionResult(final String idStr, final Integer resultType) {
1143         if (!idStr.matches("\\d+")) {
1144             showResultCmdHelp();
1145             return;
1146         }
1147 
1148         int sessionId = Integer.parseInt(idStr);
1149 
1150         TestSession ts = mHost.getSession(sessionId);
1151         if (null == ts) {
1152             Log.e("Can't find specified session", null);
1153             return;
1154         }
1155 
1156         TestSessionLog log = ts.getSessionLog();
1157         CUIOutputStream.println("Result of session " + ts.getId());
1158         CUIOutputStream.println("Result\t\tCase name");
1159         CUIOutputStream
1160                 .println("==============================================================");
1161         for (Test test : log.getAllResults()) {
1162             CtsTestResult result = test.getResult();
1163             if ((resultType != null) && (result.getResultCode() != resultType.intValue())) {
1164                 continue;
1165             }
1166             CUIOutputStream.println(result.getResultString() + "\t\t"
1167                     + test.getFullName());
1168         }
1169     }
1170 
1171     /**
1172      * List all of the test results.
1173      */
listResults()1174     private void listResults() {
1175         Collection<TestSession> sessions = mHost.getSessions();
1176         if (sessions.isEmpty()) {
1177             CUIOutputStream.println("There isn't any test result!");
1178         } else {
1179             CUIOutputStream.println("List of all results: ");
1180             CUIOutputStream.println(
1181                     "Session\t\tTest result\t\t\t\tStart time\t\tEnd time\t\tTest plan name");
1182             CUIOutputStream.println("\t\tPass\tFail\tTimeout\tNotExecuted");
1183 
1184             for (TestSession session : sessions) {
1185                 TestSessionLog log = session.getSessionLog();
1186                 int passNum = log.getTestList(
1187                         CtsTestResult.CODE_PASS).size();
1188                 int failNum = log.getTestList(
1189                         CtsTestResult.CODE_FAIL).size();
1190                 int notExecutedNum = log.getTestList(
1191                         CtsTestResult.CODE_NOT_EXECUTED).size();
1192                 int timeOutNum = log.getTestList(
1193                         CtsTestResult.CODE_TIMEOUT).size();
1194 
1195                 String resStr = Long.toString(passNum) + "\t" + failNum;
1196                 resStr += "\t" + timeOutNum;
1197                 resStr += "\t" + notExecutedNum;
1198 
1199                 String startTimeStr =
1200                     HostUtils.getFormattedTimeString(log.getStartTime().getTime(), " ", ".", ":");
1201                 String endTimeStr =
1202                     HostUtils.getFormattedTimeString(log.getEndTime().getTime(), " ", ".", ":");
1203                 CUIOutputStream.println(Long.toString(session.getId()) + "\t\t"
1204                         + resStr + "\t\t" + startTimeStr
1205                         + "\t" + endTimeStr + "\t" + log.getTestPlanName());
1206             }
1207         }
1208     }
1209 
1210     /**
1211      * Add a package by the path and package name.
1212      *
1213      * @param cp Command container.
1214      */
addPackage(final CommandParser cp)1215     private void addPackage(final CommandParser cp) throws IOException,
1216             IndexOutOfBoundsException, NoSuchAlgorithmException {
1217         if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
1218             showPackageCmdHelp();
1219             return;
1220         }
1221         String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
1222         mHost.addPackage(pathName);
1223     }
1224 
1225     /**
1226      * List current package in the case repository.
1227      *
1228      * @param cp Command container
1229      */
listPackages(final CommandParser cp)1230     private void listPackages(final CommandParser cp) {
1231         // walk through the case root path
1232         // and list available packages
1233         String expectPackage = cp.getValue(CTSCommand.OPTION_PACKAGE);
1234         String caseRoot = mHost.getCaseRepository().getRoot();
1235         if (caseRoot == null) {
1236             Log.e("Case repository is null", null);
1237             return;
1238         }
1239 
1240         File root = new File(caseRoot);
1241         if (!root.isDirectory()) {
1242             Log.e("Case repository must be a directory!", null);
1243             return;
1244         }
1245 
1246         Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
1247 
1248         if (testPackages.size() == 0) {
1249             CUIOutputStream
1250                     .println("No package available under case repository!");
1251         } else {
1252             if (expectPackage.equals("")) {
1253                 CUIOutputStream.println("Available packages ("
1254                         + testPackages.size() + " in total):");
1255                 for (TestPackage pkg : testPackages) {
1256                     CUIOutputStream.println(pkg.getAppPackageName());
1257                 }
1258             } else {
1259                 List<ArrayList<String>> list = mHost.getCaseRepository()
1260                         .listAvailablePackage(expectPackage);
1261                 ArrayList<String> packageList = list.get(0);
1262                 ArrayList<String> suiteList = list.get(1);
1263                 ArrayList<String> caseList = list.get(2);
1264                 ArrayList<String> testList = list.get(3);
1265                 if ((packageList.size() == 0) && (suiteList.size() == 0)
1266                         && (caseList.size() == 0) && (testList.size() == 0)) {
1267                     CUIOutputStream
1268                             .println("Not available test package, suite, cases or tests: "
1269                                     + expectPackage);
1270                 } else {
1271                     if (packageList.size() != 0) {
1272                         CUIOutputStream.println(
1273                                 "Test packages (" + packageList.size() + " in total):");
1274                         for (String packageName : packageList) {
1275                             CUIOutputStream.println(packageName);
1276                         }
1277                     }
1278                     if (suiteList.size() != 0) {
1279                         CUIOutputStream.println(
1280                                 "Test suites (" + suiteList.size() + " in total):");
1281                         for (String suiteName : suiteList) {
1282                             CUIOutputStream.println(suiteName);
1283                         }
1284                     }
1285                     if (caseList.size() != 0) {
1286                         CUIOutputStream.println("Test cases (" + caseList.size() + " in total):");
1287                         for (String caseName : caseList) {
1288                             CUIOutputStream.println(caseName);
1289                         }
1290                     }
1291                     if (testList.size() != 0) {
1292                         CUIOutputStream.println("Tests (" + testList.size() + " in total):");
1293                         for (String testName : testList) {
1294                             CUIOutputStream.println(testName);
1295                         }
1296                     }
1297                 }
1298             }
1299         }
1300     }
1301 
1302     /**
1303      * List all of the devices connected.
1304      */
listDevices()1305     private void listDevices() {
1306         String[] deviceNames = mHost.listDevices();
1307         if (deviceNames.length == 0) {
1308             CUIOutputStream.println("No device connected.");
1309             return;
1310         }
1311 
1312         CUIOutputStream.println("Id\t\tDevice Name\t\tStatus");
1313 
1314         for (int i = 0; i < deviceNames.length; i++) {
1315             CUIOutputStream.println(i + "\t\t" + deviceNames[i]);
1316         }
1317     }
1318 }
1319