com.photon.maven.plugins.android.standalonemojos.RobotiumMultiDeviceExecutorMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.photon.maven.plugins.android.standalonemojos.RobotiumMultiDeviceExecutorMojo.java

Source

/*
 * ###
 * Android Maven Plugin - android-maven-plugin
 * 
 * Copyright (C) 1999 - 2012 Photon Infotech Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ###
 */
/*
 * Copyright (C) 2009 Jayway AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.photon.maven.plugins.android.standalonemojos;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.ShellCommandUnresponsiveException;
import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.photon.maven.plugins.android.AbstractInstrumentationMojo;
import com.photon.maven.plugins.android.DeviceCallback;
import com.photon.maven.plugins.android.common.DeviceHelper;

/**
 * MultiDeviceExecutorMojo helps to connect to all selected android devices
 * within separate threads, install the apk file on selected devices and start
 * the application.
 * 
 * @goal perftest
 * @author viral_b
 */
public class RobotiumMultiDeviceExecutorMojo extends AbstractInstrumentationMojo {
    /**
     * @parameter expression="${deviceList}"
     */
    private String deviceList = "";
    private String[] devicesListArr = null;
    private ArrayList<Thread> threadObj = new ArrayList<Thread>();

    private AndroidTestRunListener testRunListener;
    private ArrayList<String> xmlReportNameForConnectedDevices;

    public void execute() throws MojoExecutionException, MojoFailureException {
        checkDeviceList();
        // deployDependencies();
        instrument();
        joinThreads();

        testRunListener.writeJunitReportToAllTestsFile(xmlReportNameForConnectedDevices);
    };

    /**
     * Check the deviceList parameter
     */
    private void checkDeviceList() {
        try {
            if (StringUtils.isNotBlank(deviceList)) {
                if (StringUtils.indexOf(deviceList, ",") > -1) {
                    devicesListArr = deviceList.split(",");
                } else {
                    devicesListArr = new String[1];
                    devicesListArr[0] = deviceList.trim();
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            getLog().info("checkDeviceList - Exception: " + e.getMessage());
        }
    }

    protected void instrument() throws MojoExecutionException, MojoFailureException {
        parseConfiguration();

        if (parsedInstrumentationPackage == null) {
            parsedInstrumentationPackage = extractPackageNameFromAndroidManifest(androidManifestFile);
        }

        if (parsedInstrumentationRunner == null) {
            parsedInstrumentationRunner = extractInstrumentationRunnerFromAndroidManifest(androidManifestFile);
        }

        // only run Tests in specific package
        packagesList = buildCommaSeparatedString(parsedPackages);
        packagesExists = StringUtils.isNotBlank(packagesList);

        if (parsedClasses != null) {
            classesExists = parsedClasses.size() > 0;
        } else {
            classesExists = false;
        }

        if (classesExists && packagesExists) {
            // if both packages and classes are specified --> ERROR
            throw new MojoFailureException(
                    "packages and classes are mutually exclusive. They cannot be specified at "
                            + "the same time. Please specify either packages or classes. For details, "
                            + "see http://developer.android.com/guide/developing/testing/testing_otheride.html");
        }

        doWithDevices(new DeviceCallback() {
            public void doWithDevice(final IDevice device) throws MojoExecutionException, MojoFailureException {
                RemoteAndroidTestRunner remoteAndroidTestRunner = new RemoteAndroidTestRunner(
                        parsedInstrumentationPackage, parsedInstrumentationRunner, device);

                if (packagesExists) {
                    remoteAndroidTestRunner.setTestPackageName(packagesList);
                    getLog().info("Running tests for specified test packages: " + packagesList);
                }

                if (classesExists) {
                    remoteAndroidTestRunner.setClassNames(parsedClasses.toArray(new String[parsedClasses.size()]));
                    getLog().info("Running tests for specified test classes/methods: " + parsedClasses);
                }

                remoteAndroidTestRunner.setDebug(parsedDebug);
                remoteAndroidTestRunner.setCoverage(parsedCoverage);
                remoteAndroidTestRunner.setLogOnly(parsedLogOnly);

                if (StringUtils.isNotBlank(parsedTestSize)) {
                    IRemoteAndroidTestRunner.TestSize validSize = IRemoteAndroidTestRunner.TestSize
                            .getTestSize(parsedTestSize);
                    remoteAndroidTestRunner.setTestSize(validSize);
                }

                getLog().info("Running instrumentation tests in " + parsedInstrumentationPackage + " on "
                        + device.getSerialNumber() + " (avdName=" + device.getAvdName() + ")");
                try {
                    testRunListener = new AndroidTestRunListener(project, device);
                    remoteAndroidTestRunner.run(testRunListener);
                    if (testRunListener.hasFailuresOrErrors()) {
                        throw new MojoFailureException("Tests failed on device.");
                    }
                    if (testRunListener.testRunFailed()) {
                        throw new MojoFailureException(
                                "Test run failed to complete: " + testRunListener.getTestRunFailureCause());
                    }
                    if (testRunListener.threwException()) {
                        throw new MojoFailureException(testRunListener.getExceptionMessages());
                    }
                } catch (TimeoutException e) {
                    throw new MojoExecutionException("timeout", e);
                } catch (AdbCommandRejectedException e) {
                    throw new MojoExecutionException("adb command rejected", e);
                } catch (ShellCommandUnresponsiveException e) {
                    throw new MojoExecutionException("shell command " + "unresponsive", e);
                } catch (IOException e) {
                    throw new MojoExecutionException("IO problem", e);
                }
            }
        });
    }

    protected void doWithDevices(final DeviceCallback deviceCallback)
            throws MojoExecutionException, MojoFailureException {

        final AndroidDebugBridge androidDebugBridge = initAndroidDebugBridge();

        if (androidDebugBridge.isConnected()) {
            waitForInitialDeviceList(androidDebugBridge);
            List<IDevice> devices = Arrays.asList(androidDebugBridge.getDevices());
            int numberOfDevices = devices.size();
            getLog().info("Found " + numberOfDevices + " devices connected with the Android Debug Bridge");

            if (devices.size() > 0) {
                getLog().info("android.device parameter not set, using all attached devices");
                for (final IDevice idevice : devices) {
                    for (int i = 0; i < devicesListArr.length; i++) {
                        if (devicesListArr[i].equalsIgnoreCase(idevice.getSerialNumber())) {
                            if (xmlReportNameForConnectedDevices == null) {
                                xmlReportNameForConnectedDevices = new ArrayList<String>();
                            }
                            xmlReportNameForConnectedDevices
                                    .add("TEST-" + DeviceHelper.getDescriptiveName(idevice) + ".xml");
                            startThread(deviceCallback, idevice);
                            break;
                        }
                    }

                }
            } else {
                throw new MojoExecutionException("No online devices attached.");
            }
        } else {
            throw new MojoExecutionException("Android Debug Bridge is not connected.");
        }
    }

    private void startThread(final DeviceCallback deviceCallback, final IDevice idevice) {
        try {
            Thread t = new RobitiumPerformanceTestRunner(deviceCallback, idevice);
            t.setName(idevice.getSerialNumber());
            t.start();
            threadObj.add(t);
            //         getLog().info(t.getName() + ": thread started");
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void joinThreads() {
        for (int i = 0; i < threadObj.size(); i++) {
            try {
                threadObj.get(i).join();
                //            getLog().info(threadObj.get(i).getName() + ": thread joined");
            } catch (InterruptedException e) {
                getLog().info(
                        threadObj.get(i).getName() + ": joinThreads - Exception = " + e.getLocalizedMessage());
            }
        }
    }

    private class RobitiumPerformanceTestRunner extends Thread {

        private DeviceCallback _deviceCallback;
        private IDevice _iDevice;

        public RobitiumPerformanceTestRunner(DeviceCallback deviceCallback, IDevice idevice) {
            this._deviceCallback = deviceCallback;
            this._iDevice = idevice;
        }

        public void run() {
            try {
                _deviceCallback.doWithDevice(_iDevice);
            } catch (MojoExecutionException e) {
                e.printStackTrace();
            } catch (MojoFailureException e) {
                e.printStackTrace();
            }
        }
    }
}