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
17package com.android.hosttest;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import junit.framework.Test;
23import junit.framework.TestResult;
24import junit.textui.TestRunner;
25
26import com.android.ddmlib.AndroidDebugBridge;
27import com.android.ddmlib.IDevice;
28import com.android.ddmlib.Log;
29import 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 */
41public 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
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
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        DeviceConnector connector = new DeviceConnector();
75        mDevice = connector.connectToDevice(mDeviceSerial);
76        return super.start(parentArgs.toArray(new String[parentArgs.size()]));
77    }
78
79    private String extractArg(String[] args, int index) {
80        if (args.length <= index) {
81            printUsage();
82            throw new IllegalArgumentException("Error: not enough arguments");
83        }
84        return args[index];
85    }
86
87
88    /**
89     * Main entry point.
90     *
91     * Establishes connection to provided adb device and runs tests
92     *
93     * @param args expects:
94     *     test class to run
95     *     optionally, device serial number. If unspecified, will connect to first device found
96     *     optionally, file system path to test data files
97     */
98    public static void main(String[] args) {
99        DeviceTestRunner aTestRunner = new DeviceTestRunner();
100        try {
101            TestResult r = aTestRunner.start(args);
102            if (!r.wasSuccessful())
103                System.exit(FAILURE_EXIT);
104            System.exit(SUCCESS_EXIT);
105        } catch(Exception e) {
106            System.err.println(e.getMessage());
107            System.exit(EXCEPTION_EXIT);
108        }
109    }
110
111    private static void printUsage() {
112        System.out.println("Usage: DeviceTestRunner <test_class> [-s device_serial] " +
113                "[-p test_data_path]");
114    }
115
116    /**
117     * Override parent to set DeviceTest data
118     */
119    @Override
120    public TestResult doRun(Test test, boolean wait) {
121        if (test instanceof DeviceTest) {
122            DeviceTest deviceTest = (DeviceTest)test;
123            deviceTest.setDevice(mDevice);
124            deviceTest.setTestAppPath(mTestDataPath);
125        } else {
126            Log.w(LOG_TAG, String.format("%s test class is not a DeviceTest.",
127                    test.getClass().getName()));
128        }
129        return super.doRun(test, wait);
130    }
131
132    /**
133     * Override parent to create DeviceTestSuite wrapper, instead of TestSuite
134     */
135    @SuppressWarnings("unchecked")
136    @Override
137    protected TestResult runSingleMethod(String testCase, String method, boolean wait)
138    throws Exception {
139        Class testClass = loadSuiteClass(testCase);
140        Test test = DeviceTestSuite.createTest(testClass, method);
141        return doRun(test, wait);
142    }
143}
144