/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.monkeytalk.agents;
import java.io.File;
import java.util.Arrays;
import com.gorillalogic.monkeytalk.utils.FileUtils;
import com.gorillalogic.monkeytalk.utils.exec.*;
public class AndroidEmulatorAgent extends AndroidAgent {
public static final String ADB_PROP = "adb";
public static final String ADB_SERIAL_PROP = "adbSerial";
public static final String ADB_LOCAL_PORT_PROP = "adbLocalPort";
public static final String ADB_REMOTE_PORT_PROP = "adbRemotePort";
private AdbHelper adbHelper;
public AndroidEmulatorAgent() {
super();
adbHelper = new AdbHelper();
}
@Override
public String getName() {
return "AndroidEmulator";
}
@Override
public void start() {
super.start();
adbHelper.startAdb(getAdb());
}
public File getAdb() {
String a = getProperty(ADB_PROP);
return (a == null ? null : new File(a));
}
public String getAdbSerial() {
String s = getProperty(ADB_SERIAL_PROP);
return (s == null ? "" : s.trim());
}
public int getAdbLocalPort() {
String s = getProperty(ADB_LOCAL_PORT_PROP);
try {
int port = Integer.parseInt(s);
return (port > 0 ? port : getPort());
} catch (NumberFormatException ex) {
return super.getPort();
}
}
@Override
public int getPort() {
return getAdbLocalPort();
}
public int getAdbRemotePort() {
String s = getProperty(ADB_REMOTE_PORT_PROP);
try {
int port = Integer.parseInt(s);
return (port > 0 ? port : getPort());
} catch (NumberFormatException ex) {
return super.getPort();
}
}
@Override
public void stop() {
if (adbHelper.isAdbRunning()) {
adbHelper.stopAdb(getAdb());
}
}
@Override
public String validate() {
if (getHost() == null || getPort() == -1) {
return getName() + " - playback host or port not set";
} else if (getAdb() == null) {
return getName()
+ " - you must specify adb to run on the Android Emulator or on a tethered Android device.";
} else if (!getAdb().exists()) {
return getName() + " - you must specify a vaild path to adb. File not found: "
+ getAdb().getAbsolutePath();
} else if (!getAdb().isFile()) {
return getName() + " - you must specify a vaild path to adb. Not a file: "
+ getAdb().getAbsolutePath();
}
return null;
}
private class AdbHelper {
private boolean adbRunning = false;
public AdbHelper() {
}
public boolean isAdbRunning() {
return adbRunning;
}
private void startAdb(File adb) {
try {
if (getAdbSerial().contains(":")) {
connectAdb(adb);
}
// adb forward tcp:<local> tcp:<remote>
String[] cmdAndArgs;
if (getAdbSerial().length() > 0) {
cmdAndArgs = new String[] { adb.getAbsolutePath(), "-s", getAdbSerial(),
"forward", "tcp:" + getAdbLocalPort(), "tcp:" + getAdbRemotePort() };
} else {
cmdAndArgs = new String[] { adb.getAbsolutePath(), "forward",
"tcp:" + getAdbLocalPort(), "tcp:" + getAdbRemotePort() };
}
ExecResult adbResult = Exec.run(cmdAndArgs);
if (adbResult.getExitValue() != 0) {
// retrieve the output
String output = adbResult.getStdout();
String err = adbResult.getStderr();
// combine stdout and stderr so we don't miss anything
String out = output
+ ((output.length() > 0 && err.length() > 0) ?"\n":"") + err;
throw new RuntimeException(out);
} else {
adbRunning = true;
}
} catch (Exception ex) {
throw new RuntimeException("Error starting adb:\n" + ex.getMessage());
}
}
private void stopAdb(File adb) {
try {
String[] cmdAndArgs = new String[] { adb.getAbsolutePath(), "kill-server" };
ExecResult adbResult = Exec.run(cmdAndArgs);
if (adbResult.getExitValue() != 0) {
// retrieve the output
String output = adbResult.getStdout();
String err = adbResult.getStderr();
// combine stdout and stderr so we don't miss anything
String out = output
+ (output.length() > 0 && output.length() > 0 ? "\n" + err : "");
throw new RuntimeException(out);
} else {
adbRunning = false;
}
} catch (Exception ex) {
throw new RuntimeException("Error stopping adb:\n" + ex.getMessage());
}
}
private void connectAdb(File adb) {
if (getAdbSerial().length() == 0) {
return;
}
try {
String[] cmdAndArgs = new String[] { adb.getAbsolutePath(), "connect",
getAdbSerial() };
ExecResult adbResult = Exec.run(cmdAndArgs);
if (adbResult.getExitValue() != 0) {
// retrieve the output
String err = adbResult.getStderr();
throw new RuntimeException("Error running adb: " + Arrays.toString(cmdAndArgs)
+ "\n" + err + " err=" + adbResult.getExitValue());
} else {
@SuppressWarnings("unused")
String output = adbResult.getStdout();
// System.out.println("connectAdb(): output=" + out);
}
} catch (Exception ex) {
throw new RuntimeException("Error connecting:\n" + ex.getMessage());
}
}
}
}