• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.hosttest;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 
22 import junit.framework.Test;
23 import junit.framework.TestResult;
24 import junit.textui.TestRunner;
25 
26 import com.android.ddmlib.AndroidDebugBridge;
27 import com.android.ddmlib.IDevice;
28 import com.android.ddmlib.Log;
29 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
30 
31 /**
32  * Command line interface for running DeviceTest tests.
33  *
34  * Extends junit.textui.TestRunner to handle optional -s (device serial) and -p (test data)
35  * arguments, and then pass their values to the instantiated DeviceTests.
36  *
37  * Provided test class must be a DeviceTest.
38  *
39  * @see junit.textui.TestRunner for more information on command line syntax.
40  */
41 public class DeviceTestRunner extends TestRunner {
42 
43     private static final String LOG_TAG = "DeviceTestRunner";
44     private String mDeviceSerial = null;
45     private IDevice mDevice = null;
46     private String mTestDataPath = null;
47 
DeviceTestRunner()48     private DeviceTestRunner() {
49     }
50 
51     /**
52      * Starts the test run.
53      * Extracts out DeviceTestCase specific command line arguments, then passes control to parent
54      * TestRunner.
55      * @param args command line arguments
56      * @return {@link TestResult}
57      */
58     @Override
start(String[] args)59     public TestResult start(String[] args) throws Exception {
60         // holds unprocessed arguments to pass to parent
61         List<String> parentArgs = new ArrayList<String>();
62         for (int i=0; i < args.length; i++) {
63             if (args[i].equals("-s")) {
64                 i++;
65                 mDeviceSerial = extractArg(args, i);
66             } else if (args[i].equals("-p")) {
67                 i++;
68                 mTestDataPath = extractArg(args, i);
69             } else {
70                 // unrecognized arg, must be for parent
71                 parentArgs.add(args[i]);
72             }
73         }
74         mDevice = connectToDevice(mDeviceSerial);
75         return super.start(parentArgs.toArray(new String[parentArgs.size()]));
76     }
77 
extractArg(String[] args, int index)78     private String extractArg(String[] args, int index) {
79         if (args.length <= index) {
80             printUsage();
81             throw new IllegalArgumentException("Error: not enough arguments");
82         }
83         return args[index];
84     }
85 
86     /**
87      * Initializes DDMS library, and connects to specified Android device
88      * @param deviceSerial
89      * @return {@link IDevice}
90      * @throws IllegalArgumentException if specified device cannot be found
91      */
connectToDevice(String deviceSerial)92     private IDevice connectToDevice(String deviceSerial) {
93         // initialize DDMS with no clientSupport aka debugger support
94         AndroidDebugBridge.init(false /* clientSupport */);
95         AndroidDebugBridge adbBridge = AndroidDebugBridge.createBridge();
96         for (IDevice device : adbBridge.getDevices()) {
97             if (deviceSerial == null) {
98                 return device;
99             } else if (deviceSerial.equals(device.getSerialNumber())) {
100                 return device;
101             }
102         }
103         System.out.println("Waiting for device...");
104         NewDeviceListener listener = new NewDeviceListener(deviceSerial);
105         AndroidDebugBridge.addDeviceChangeListener(listener);
106         IDevice device = listener.waitForDevice(5000);
107         AndroidDebugBridge.removeDeviceChangeListener(listener);
108         if (device == null) {
109             throw new IllegalArgumentException("Could not connect to device");
110         }
111         return device;
112     }
113 
114     /**
115      * Listener for new Android devices
116      */
117     private static class NewDeviceListener implements IDeviceChangeListener {
118         private IDevice mDevice;
119         private String mSerial;
120 
NewDeviceListener(String serial)121         public NewDeviceListener(String serial) {
122             mSerial = serial;
123         }
124 
deviceChanged(IDevice device, int changeMask)125         public void deviceChanged(IDevice device, int changeMask) {
126         }
127 
deviceConnected(IDevice device)128         public void deviceConnected(IDevice device) {
129             if (mSerial == null) {
130                 setDevice(device);
131             } else if (mSerial.equals(device.getSerialNumber())) {
132                 setDevice(device);
133             }
134         }
135 
setDevice(IDevice device)136         private synchronized void setDevice(IDevice device) {
137             mDevice = device;
138             notify();
139         }
140 
deviceDisconnected(IDevice device)141         public void deviceDisconnected(IDevice device) {
142         }
143 
waitForDevice(long waitTime)144         public IDevice waitForDevice(long waitTime) {
145             synchronized(this) {
146                 if (mDevice == null) {
147                     try {
148                         wait(waitTime);
149                     } catch (InterruptedException e) {
150                         System.out.println("Waiting for device interrupted");
151                     }
152                 }
153             }
154             return mDevice;
155         }
156     }
157 
158     /**
159      * Main entry point.
160      *
161      * Establishes connection to provided adb device and runs tests
162      *
163      * @param args expects:
164      *     test class to run
165      *     optionally, device serial number. If unspecified, will connect to first device found
166      *     optionally, file system path to test data files
167      */
main(String[] args)168     public static void main(String[] args) {
169         DeviceTestRunner aTestRunner = new DeviceTestRunner();
170         try {
171             TestResult r = aTestRunner.start(args);
172             if (!r.wasSuccessful())
173                 System.exit(FAILURE_EXIT);
174             System.exit(SUCCESS_EXIT);
175         } catch(Exception e) {
176             System.err.println(e.getMessage());
177             System.exit(EXCEPTION_EXIT);
178         }
179     }
180 
printUsage()181     private static void printUsage() {
182         System.out.println("Usage: DeviceTestRunner <test_class> [-s device_serial] " +
183                 "[-p test_data_path]");
184     }
185 
186     /**
187      * Override parent to set DeviceTest data
188      */
189     @Override
doRun(Test test, boolean wait)190     public TestResult doRun(Test test, boolean wait) {
191         if (test instanceof DeviceTest) {
192             DeviceTest deviceTest = (DeviceTest)test;
193             deviceTest.setDevice(mDevice);
194             deviceTest.setTestAppPath(mTestDataPath);
195         } else {
196             Log.w(LOG_TAG, String.format("%s test class is not a DeviceTest.",
197                     test.getClass().getName()));
198         }
199         return super.doRun(test, wait);
200     }
201 
202     /**
203      * Override parent to create DeviceTestSuite wrapper, instead of TestSuite
204      */
205     @Override
runSingleMethod(String testCase, String method, boolean wait)206     protected TestResult runSingleMethod(String testCase, String method, boolean wait)
207     throws Exception {
208         Class testClass = loadSuiteClass(testCase);
209         Test test = DeviceTestSuite.createTest(testClass, method);
210         return doRun(test, wait);
211     }
212 }
213