blob: efc002b5a7e0821948a43605135ff9ab340998c5 [file] [log] [blame]
/*
* 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();
}
}