/* MonkeyTalk - a cross-platform functional testing tool Copyright (C) 2013 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.java; import java.io.File; import java.lang.reflect.Proxy; import com.gorillalogic.monkeytalk.BuildStamp; import com.gorillalogic.monkeytalk.agents.AgentManager; import com.gorillalogic.monkeytalk.agents.AndroidEmulatorAgent; import com.gorillalogic.monkeytalk.agents.IAgent; import com.gorillalogic.monkeytalk.java.api.Application; import com.gorillalogic.monkeytalk.java.error.MonkeyTalkError; import com.gorillalogic.monkeytalk.java.proxy.ComponentProxyHandler; import com.gorillalogic.monkeytalk.processor.PlaybackListener; import com.gorillalogic.monkeytalk.processor.Scope; import com.gorillalogic.monkeytalk.processor.ScriptProcessor; import com.gorillalogic.monkeytalk.utils.AndroidUtils; /** * The MonkeyTalk driver. */ public class MonkeyTalkDriver { private ScriptProcessor processor; private Scope scope; private ComponentProxyHandler componentProxy; private int startup = 0; private boolean verbose = true; private Logger logger = new Logger(); /** * Construct a new MonkeyTalk driver with the given working directory and agent name (iOS, * Android, AndroidEmulator). * * @param dir * the working directory * @param agentName * the agent name (iOS, Android, AndroidEmulator) */ public MonkeyTalkDriver(File dir, String agentName) { this(dir, AgentManager.getAgent(agentName)); } /** * Construct a new MonkeyTalk driver with the given working directory, agent name (iOS, Android, * AndroidEmulator), and target host. * * @param dir * the working directory * @param agentName * the agent name (iOS, Android, AndroidEmulator) * @param host * the target host */ public MonkeyTalkDriver(File dir, String agentName, String host) { this(dir, AgentManager.getAgent(agentName, host)); } /** * Construct a new MonkeyTalk driver with the given working directory, agent name (iOS, Android, * AndroidEmulator), target host, and target port. * * @param dir * the working directory * @param agentName * the agent name (iOS, Android, AndroidEmulator) * @param host * the target host * @param port * the target port */ public MonkeyTalkDriver(File dir, String agentName, String host, int port) { this(dir, AgentManager.getAgent(agentName, host, port)); } /** * Construct a new MonkeyTalk driver with working directory and agent. * * @param dir * the working directory * @param agent * the MonkeyTalk agent */ private MonkeyTalkDriver(File dir, IAgent agent) { this(new ScriptProcessor(dir, agent)); } /** * Construct a new MonkeyTalk driver with the given processor. * * @param processor * the MonkeyTalk script processor */ private MonkeyTalkDriver(ScriptProcessor processor) { this.processor = processor; scope = new Scope(); componentProxy = new ComponentProxyHandler(processor, scope); componentProxy.setVerbose(verbose); componentProxy.setLogger(logger); if (processor != null && processor.getAgent() != null && processor.getAgent().getName() != null && processor.getAgent().getName().equalsIgnoreCase("AndroidEmulator")) { setAdb(AndroidUtils.getAdb()); } if (verbose) { logger.println(BuildStamp.STAMP); } } /** * Set the global timeout. * * @param timeout * the timeout (in ms) */ public void setTimeout(int timeout) { if (processor != null) { processor.setGlobalTimeout(timeout); } } /** * Set the global thinktime. * * @param thinktime * the thinktime (in ms) */ public void setThinktime(int thinktime) { if (processor != null) { processor.setGlobalThinktime(thinktime); } } /** * Set the global before & after screenshots. * * @param screenshots * true to take before & after screenshots */ public void setScreenshots(boolean screenshots) { if (processor != null) { processor.setTakeAfterScreenshot(screenshots); processor.setTakeAfterMetrics(screenshots); } } /** * Set the global screenshot on error. * * @param screenshotOnError * true to take a screenshot on error */ public void setScreenshotOnError(boolean screenshotOnError) { if (processor != null) { processor.setGlobalScreenshotOnError(screenshotOnError); } } /** * Set the startup time. * * @param startup * the startup time (in s) */ public void setStartup(int startup) { this.startup = startup; } /** * Set the adb path (for AndroidEmulator only). * * @param adb * the adb path */ public void setAdb(File adb) { setAgentProperty(AndroidEmulatorAgent.ADB_PROP, adb != null ? adb.getAbsolutePath() : null); } /** * Set the adb serial (for AndroidEmulator only). * * @param serial * the adb serial */ public void setAdbSerial(String serial) { setAgentProperty(AndroidEmulatorAgent.ADB_SERIAL_PROP, serial); } /** * Set the adb local port (for AndroidEmulator only). * * @param port * the local port */ public void setAdbLocalPort(int port) { setAgentProperty(AndroidEmulatorAgent.ADB_LOCAL_PORT_PROP, port > 0 ? Integer.toString(port) : null); } /** * Set the adb remote port (for AndroidEmulator only). * * @param port * the remote port */ public void setAdbRemotePort(int port) { setAgentProperty(AndroidEmulatorAgent.ADB_REMOTE_PORT_PROP, port > 0 ? Integer.toString(port) : null); } /** * Helper to set agent properties. * * @param key * the agent property * @param val * the agent property value */ private void setAgentProperty(String key, String val) { processor.getAgent().setProperty(key, val); } /** * Turn on verbose output. * * @param verbose * true for verbose output */ public void setVerbose(boolean verbose) { this.verbose = verbose; componentProxy.setVerbose(verbose); } /** * Set a custom script playback listener. The listener will receive callbacks when each command * is played and completed, and also when each stand-alone script is played and completed. * * @param scriptListener * the custom listener */ public void setScriptListener(PlaybackListener scriptListener) { processor.setPlaybackListener(scriptListener); } public void setLogger(Logger logger) { if (logger != null) { this.logger = logger; if (componentProxy != null) { componentProxy.setLogger(logger); } } } /** * Get the MonkeyTalk application. This is the base class for all MonkeyTalk interactions with * the application under test. * * @return the MonkeyTalk application */ public Application app() { if (processor != null && processor.getAgent() != null) { start(); } return (Application) Proxy.newProxyInstance(Application.class.getClassLoader(), new Class[] { Application.class }, componentProxy); } /** * Start the agent. The agent is automatically started when you first get the application (via * {@link MonkeyTalkDriver#app()}). <b>ONLY</b> call {@code start()} if you must restart the * agent after a manual stop (via {@link MonkeyTalkDriver#stop()}). */ public void start() { if (startup > 0) { boolean success = processor.getAgent().waitUntilReady(startup * 1000); if (!success) { throw new MonkeyTalkError( "Unable to startup MonkeyTalk connection - timeout after " + startup + "s"); } } processor.getAgent().start(); } /** * Stop the agent. Typically, it is not necessary to call this. */ public void stop() { if (processor != null && processor.getAgent() != null) { processor.abort(); processor.getAgent().stop(); processor.getAgent().close(); } } }