| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * 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.android.monkeyrunner; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.text.SimpleDateFormat; |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipOutputStream; |
| |
| import org.jheer.XMLWriter; |
| |
| /** |
| * MonkeyRecorder is a host side class that records the output of scripts that are run. |
| * It creates a unique directory, puts in an xml file that records each cmd and result. |
| * It stores every screenshot in this directory. |
| * When finished, it zips this all up. |
| * |
| * Calling Sequence: |
| * mr = new MonkeyRecorder(scriptName); |
| * mr.startCommand(); |
| * [mr.addAttribute(name, value);] |
| * ... |
| * [mr.addInput(cmd);] |
| * [mr.addResults(result, filename);] // filename = "" if no screenshot |
| * mr.endCommand(); |
| * mr.addComment(comment); |
| * mr.startCommand(); |
| * ... |
| * mr.endCommand(); |
| * ... |
| * mr.close(); |
| * |
| * With MonkeyRunner this should output an xml file, <script_name>-yyyyMMdd-HH:mm:ss.xml, into the |
| * directory out/<script_name>-yyyyMMdd-HH:mm:ss with the contents: |
| * |
| * <?xml version="1.0" encoding='UTF-8'?> |
| * <script_run> |
| * script_name="filename" |
| * monkeyRunnerVersion="0.2" |
| * <!-- Device specific variables --> |
| * <device_var var_name="name" var_value="value" /> |
| * <device_var name="build.display" value="opal-userdebug 1.6 DRC79 14207 test-keys"/> |
| * ... |
| * <!-- Script commands --> |
| * <command> |
| * dateTime="20090921-17:08:43" |
| * <input cmd="Pressing: menu"/> |
| * <response result="OK" dateTime="20090921-17:08:43"/> |
| * </command> |
| * ... |
| * <command> |
| * dateTime="20090921-17:09:44" |
| * <input cmd="grabscreen"/> |
| * <response result="OK" dateTime="20090921-17:09:45" screenshot="home_screen-20090921-17:09:45.png"/> |
| * </command> |
| * ... |
| * </script_run> |
| * |
| * And then zip it up with all the screenshots in the file: <script_name>-yyyyMMdd-HH:mm:ss.zip. |
| */ |
| |
| public class MonkeyRecorder { |
| |
| // xml file to store output results in |
| private static String mXmlFilename; |
| private static FileWriter mXmlFile; |
| private static XMLWriter mXmlWriter; |
| |
| // unique subdirectory to put results in (screenshots and xml file) |
| private static String mDirname; |
| private static List<String> mScreenShotNames = new ArrayList<String>(); |
| |
| // where we store all the results for all the script runs |
| private static final String ROOT_DIR = "out"; |
| |
| // for getting the date and time in now() |
| private static final SimpleDateFormat SIMPLE_DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd-HH:mm:ss"); |
| |
| /** |
| * Create a new MonkeyRecorder that records commands and zips up screenshots for submittal |
| * |
| * @param scriptName filepath of the monkey script we are running |
| */ |
| public MonkeyRecorder(String scriptName) throws IOException { |
| // Create directory structure to store xml file, images and zips |
| File scriptFile = new File(scriptName); |
| scriptName = scriptFile.getName(); // Get rid of path |
| mDirname = ROOT_DIR + "/" + stripType(scriptName) + "-" + now(); |
| new File(mDirname).mkdirs(); |
| |
| // Initialize xml file |
| mXmlFilename = stampFilename(stripType(scriptName) + ".xml"); |
| initXmlFile(scriptName); |
| } |
| |
| // Get the current date and time in a simple string format (used for timestamping filenames) |
| private static String now() { |
| return SIMPLE_DATE_TIME_FORMAT.format(Calendar.getInstance().getTime()); |
| } |
| |
| /** |
| * Initialize the xml file writer |
| * |
| * @param scriptName filename (not path) of the monkey script, stored as attribute in the xml file |
| */ |
| private static void initXmlFile(String scriptName) throws IOException { |
| mXmlFile = new FileWriter(mDirname + "/" + mXmlFilename); |
| mXmlWriter = new XMLWriter(mXmlFile); |
| mXmlWriter.begin(); |
| mXmlWriter.comment("Monkey Script Results"); |
| mXmlWriter.start("script_run"); |
| mXmlWriter.addAttribute("script_name", scriptName); |
| } |
| |
| /** |
| * Add a comment to the xml file. |
| * |
| * @param comment comment to add to the xml file |
| */ |
| public static void addComment(String comment) throws IOException { |
| mXmlWriter.comment(comment); |
| } |
| |
| /** |
| * Begin writing a command xml element |
| */ |
| public static void startCommand() throws IOException { |
| mXmlWriter.start("command"); |
| mXmlWriter.addAttribute("dateTime", now()); |
| } |
| |
| /** |
| * Write a command name attribute in a command xml element. |
| * It's add as a sinlge script command could be multiple monkey commands. |
| * |
| * @param cmd command sent to the monkey |
| */ |
| public static void addInput(String cmd) throws IOException { |
| String name = "cmd"; |
| String value = cmd; |
| mXmlWriter.tag("input", name, value); |
| } |
| |
| /** |
| * Write a response xml element in a command. |
| * Attributes include the monkey result, datetime, and possibly screenshot filename |
| * |
| * @param result response of the monkey to the command |
| * @param filename filename of the screen shot (or other file to be included) |
| */ |
| public static void addResult(String result, String filename) throws IOException { |
| int num_args = 2; |
| String[] names = new String[3]; |
| String[] values = new String[3]; |
| names[0] = "result"; |
| values[0] = result; |
| names[1] = "dateTime"; |
| values[1] = now(); |
| if (filename.length() != 0) { |
| names[2] = "screenshot"; |
| values[2] = stampFilename(filename); |
| addScreenShot(filename); |
| num_args = 3; |
| } |
| mXmlWriter.tag("response", names, values, num_args); |
| } |
| |
| /** |
| * Add an attribut to an xml element. name="escaped_value" |
| * |
| * @param name name of the attribute |
| * @param value value of the attribute |
| */ |
| public static void addAttribute(String name, String value) throws IOException { |
| mXmlWriter.addAttribute(name, value); |
| } |
| |
| /** |
| * Add an xml device variable element. name="escaped_value" |
| * |
| * @param name name of the variable |
| * @param value value of the variable |
| */ |
| public static void addDeviceVar(String name, String value) throws IOException { |
| String[] names = {"name", "value"}; |
| String[] values = {name, value}; |
| mXmlWriter.tag("device_var", names, values, names.length); |
| } |
| |
| /** |
| * Move the screenshot to storage and remember you did it so it can be zipped up later. |
| * |
| * @param filename file name of the screenshot to be stored (Not path name) |
| */ |
| private static void addScreenShot(String filename) { |
| File file = new File(filename); |
| String screenShotName = stampFilename(filename); |
| file.renameTo(new File(mDirname, screenShotName)); |
| mScreenShotNames.add(screenShotName); |
| } |
| |
| /** |
| * Finish writing a command xml element |
| */ |
| public static void endCommand() throws IOException { |
| mXmlWriter.end(); |
| } |
| |
| /** |
| * Add datetime in front of filetype (the stuff after and including the last infamous '.') |
| * |
| * @param filename path of file to be stamped |
| */ |
| private static String stampFilename(String filename) { |
| // |
| int typeIndex = filename.lastIndexOf('.'); |
| if (typeIndex == -1) { |
| return filename + "-" + now(); |
| } |
| return filename.substring(0, typeIndex) + "-" + now() + filename.substring(typeIndex); |
| } |
| |
| /** |
| * Strip out the file type (the stuff after and including the last infamous '.') |
| * |
| * @param filename path of file to be stripped of type information |
| */ |
| private static String stripType(String filename) { |
| // |
| int typeIndex = filename.lastIndexOf('.'); |
| if (typeIndex == -1) |
| return filename; |
| return filename.substring(0, typeIndex); |
| } |
| |
| /** |
| * Add a signature element |
| * |
| * @param filename path of file to be signatured |
| */ |
| private static void addMD5Signature(String filename) throws IOException { |
| String signature = ""; |
| // find signature... MD5 sig = new MD5(filename); signature = sig.toString(); |
| String[] names = new String[] { "type", "filename", "signature" }; |
| String[] values = new String[] { "md5", filename, signature }; |
| mXmlWriter.tag("Signature", names, values, values.length); |
| } |
| |
| |
| /** |
| * Close the monkeyRecorder by closing the xml file and zipping it up with the screenshots. |
| * |
| * @param filename path of file to be stripped of type information |
| */ |
| public static void close() throws IOException { |
| // zip up xml file and screenshots into ROOT_DIR. |
| byte[] buf = new byte[1024]; |
| String zipFileName = mXmlFilename + ".zip"; |
| endCommand(); |
| mXmlFile.close(); |
| FileOutputStream zipFile = new FileOutputStream(ROOT_DIR + "/" + zipFileName); |
| ZipOutputStream out = new ZipOutputStream(zipFile); |
| |
| // add the xml file |
| addFileToZip(out, mDirname + "/" + mXmlFilename, buf); |
| |
| // Add the screenshots |
| for (String filename : mScreenShotNames) { |
| addFileToZip(out, mDirname + "/" + filename, buf); |
| } |
| out.close(); |
| } |
| |
| /** |
| * Helper function to zip up a file into an open zip archive. |
| * |
| * @param zip the stream of the zip archive |
| * @param filepath the filepath of the file to be added to the zip archive |
| * @param buf storage place to stage reads of file before zipping |
| */ |
| private static void addFileToZip(ZipOutputStream zip, String filepath, byte[] buf) throws IOException { |
| FileInputStream in = new FileInputStream(filepath); |
| zip.putNextEntry(new ZipEntry(filepath)); |
| int len; |
| while ((len = in.read(buf)) > 0) { |
| zip.write(buf, 0, len); |
| } |
| zip.closeEntry(); |
| in.close(); |
| } |
| } |