/* * Software Name : ATK * * Copyright (C) 2007 - 2012 France Télécom * * 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. * * ------------------------------------------------------------------ * File Name : LaunchJATK.java * * Created : 02/03/2009 * Author(s) : Yvain Leyral */ package com.orange.atk.launcher; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import com.android.ddmlib.AndroidDebugBridge; import com.orange.atk.atkUI.coregui.CoreGUIPlugin; import com.orange.atk.error.ErrorListener; import com.orange.atk.error.ErrorManager; import com.orange.atk.graphAnalyser.GraphMarker; import com.orange.atk.graphAnalyser.PerformanceGraph; import com.orange.atk.interpreter.ast.ASTStart; import com.orange.atk.interpreter.atkCore.JATKInterpreter; import com.orange.atk.interpreter.estimators.ValidateSyntax; import com.orange.atk.interpreter.parser.ATKScriptParser; import com.orange.atk.interpreter.parser.ParseException; import com.orange.atk.interpreter.parser.TokenMgrError; import com.orange.atk.phone.PhoneException; import com.orange.atk.phone.PhoneInterface; import com.orange.atk.phone.TcpdumpLineListener; import com.orange.atk.phone.detection.AutomaticPhoneDetection; import com.orange.atk.platform.Platform; import com.orange.atk.results.logger.documentGenerator.DocumentGenerator; import com.orange.atk.results.logger.documentGenerator.PDFGenerator; import com.orange.atk.results.logger.documentGenerator.TextGenerator; import com.orange.atk.results.logger.log.DocumentLogger; import com.orange.atk.results.logger.log.ResultLogger; import com.orange.atk.util.FileUtil; import com.orange.atk.util.NetworkAnalysisUtils; /** * Entry point of JATK interpreter. * * @author France Telecom R&D (C) France Telecom, 2008. */ public class LaunchJATK implements ErrorListener { // Default name for the report private static final String REPORT_FILENAME = "report."; // possible types for report public static final String PDF_TYPE = "pdf"; public static final String TXT_TYPE = "txt"; private static String JATKdir = Platform.getInstance().getJATKPath(); // true if the parser must generate an conf file // Variables private String includeDir = ""; private String testFile = ""; private String realTestFile = ""; // private static String JATKdir="C:\\Program Files\\JATK\\"; private static String xmlconfilepath = null; private static boolean hasParseException = false; // private static boolean isHardStopNotDisable = true; private static PhoneInterface currentPhone = null; private static DocumentGenerator documentGenerator = null; private static ResultLogger logger = null; // value of the timeout in minutes private static int timeout = -1; private Map<String, PerformanceGraph> mapPerfGraph; private Map<String, GraphMarker> mapAction = null; private static int result = 0; private Hashtable hoppertestParam; public String[] listHopper; // store the type of log (txt/pdf) private String logType = TXT_TYPE; // Directory where results would be saved private String logDir; public LaunchJATK() { super(); ErrorManager.getInstance().addErrorListener(this); this.logDir = Platform.TMP_DIR + Platform.FILE_SEPARATOR; this.includeDir = JATKdir; setCurrentPhone(); this.init(); Logger.getLogger(this.getClass()).debug("LaunchJATK()"); } public LaunchJATK(String logDir, String includeDir, String testFile, String realTestFile, String logType) { this(); this.logDir = logDir; this.includeDir = includeDir; this.testFile = testFile; this.realTestFile = realTestFile; this.logType = logType; } private String init() { // check in java path win32com.dll File win32 = new File(System.getenv("java.home") + Platform.FILE_SEPARATOR + "win32com.dll"); if (!win32.exists() && System.getenv("java.home") != null) FileUtil.copyfile(win32, new File(JATKdir + Platform.FILE_SEPARATOR + "win32com.dll")); return PhoneInterface.STATUS_PASSED; } private TcpdumpLineListener tcpdumpLineListener = new TcpdumpLineListener() { public void newTcpDumpLine(String line) { Date theDate = NetworkAnalysisUtils.extractTcpdumpLineDate(line); String url = NetworkAnalysisUtils.extractTcpdumpLineUrl(line); if (logger != null && theDate != null && url != null) { logger.addInfotoActionLogger("URL", url, theDate, theDate); } } }; private void createPhone() throws PhoneException { // add config currentPhone = AutomaticPhoneDetection.getInstance().getDevice(); try { currentPhone.setvariable(realTestFile, logDir); currentPhone.addTcpdumpLineListener(tcpdumpLineListener); currentPhone.startTestingMode(); } catch (PhoneException e) { currentPhone.stopTestingMode(); throw new PhoneException(e.getMessage()); } } private void createPDFFile() { try { // Create Document generator object if (PDF_TYPE.equals(logType)) { documentGenerator = new PDFGenerator(new FileOutputStream(new File(logDir + Platform.FILE_SEPARATOR + REPORT_FILENAME + "pdf")), logDir, "", "Orange FR.", testFile, false); } else { documentGenerator = new TextGenerator(new FileOutputStream(new File(logDir + Platform.FILE_SEPARATOR + REPORT_FILENAME + TXT_TYPE))); } } catch (FileNotFoundException e1) { e1.printStackTrace(); return; } } private void setTimeOut() { if (timeout > 0) { Runnable r = new Runnable() { public void run() { try { long duration = timeout * 60L * 1000L; Thread.sleep(duration); } catch (InterruptedException ex) { // system has generate an interrupt exception // just exit return; } // End of sleep, timeout reach Logger.getLogger(this.getClass()).debug("Timeout..."); stopInfoLog(); writeLogAndExitPhoneHandling(); throw new RuntimeException("Timeout..."); } }; new Thread(r).start(); } } private int interpretTestFile() throws FileNotFoundException { int result = 0; // start Parsing .tst file try { ATKScriptParser parser = new ATKScriptParser(new java.io.FileReader(realTestFile)); ASTStart expr = parser.start(); // TODO:include a if and an argument for dump // expr.dump(""); if (expr.jjtGetNumChildren() == 0) { logger.addInfoToDocumentLogger("Empty file...", 0, realTestFile); } else { ValidateSyntax vs = new ValidateSyntax(realTestFile, false); String output = (String) expr.jjtAccept(vs, ""); if (output.length() >= 1) { logger.addErrorToDocumentLogger(output, 0, null); result = 3; Logger.getLogger(this.getClass()).warn( "Script not valid, please check the report file"); } else { JATKInterpreter interpreter = new JATKInterpreter(currentPhone, logger, realTestFile, logDir, includeDir); // Start of interpreter Boolean res = (Boolean) expr.jjtAccept(interpreter, null); // End of interpreter if (res.booleanValue()) { logger.addInfoToDocumentLogger("Test passed", -1, ""); result = 0; } else { logger.addErrorToDocumentLogger("Test failed", 0, null); result = 1; Logger.getLogger(this.getClass()).warn( "Test failed, please check the report file"); } stopInfoLog(); } } } catch (ParseException e) { logger.addErrorToDocumentLogger(e.getMessage(), 0, null); logger.addErrorToDocumentLogger("Test failed", 0, null); result = 3; hasParseException = true; Logger.getLogger(this.getClass()).warn("Parse error, please check the report file"); } catch (TokenMgrError e) { logger.addErrorToDocumentLogger(e.getMessage(), 0, null); logger.addErrorToDocumentLogger("Test failed", 0, null); result = 3; hasParseException = true; Logger.getLogger(this.getClass()).warn("Lexical error, please check the report file"); } return result; } public String launchNewTest(String xmlconfilepath, boolean noGUI) throws FileNotFoundException, PhoneException { String result = PhoneInterface.STATUS_PASSED; System.setSecurityManager(null); // TODO handle exception FileUtil.createOrDeleteDir(logDir); currentPhone = AutomaticPhoneDetection.getInstance().getDevice(); try { currentPhone.setvariable(realTestFile, logDir); currentPhone.addTcpdumpLineListener(tcpdumpLineListener); currentPhone.startTestingMode(logDir, xmlconfilepath); } catch (PhoneException e) { currentPhone.stopTestingMode(); throw new PhoneException(e.getMessage()); } { createPDFFile(); logger = new ResultLogger(logDir, documentGenerator, xmlconfilepath); if (noGUI || !CoreGUIPlugin.mainFrame.statusBar.isStop()) { // passage de la hashmap graph dans documentlogger DocumentLogger dl = logger.getDocumentLogger(); dl.setMapPerfGraph(mapPerfGraph); setTimeOut(); if (!noGUI) logger.getDocumentLogger().addPlotlistObject(); int res = interpretTestFile(); if (res != 0) result = PhoneInterface.STATUS_FAILED; stopExecution(); writeLogAndExitPhoneHandling(); } else result = PhoneInterface.STATUS_FAILED; stopExecution(); } return result; } public String launchRandomTest(String xmlconfilepath, Map randomTestParam) throws FileNotFoundException, PhoneException { boolean result = false; System.setSecurityManager(null); FileUtil.createOrDeleteDir(logDir); createPhone(); { // Document logger createPDFFile(); logger = new ResultLogger(logDir, documentGenerator, xmlconfilepath); // passage de la hashmap graph dans documentlogger DocumentLogger dl = logger.getDocumentLogger(); dl.setMapPerfGraph(mapPerfGraph); setTimeOut(); logger.getDocumentLogger().addPlotlistObject(); logger.setPhoneInterface(currentPhone); logger.start(1000); logger.getActionsLogger().createHopperTstfile(); result = currentPhone.startRandomTest(realTestFile, logDir, logger, randomTestParam); logger.interrupt(); logger.join(); stopExecution(); writeLogAndExitPhoneHandling(); } if (result) return PhoneInterface.STATUS_PASSED; else return PhoneInterface.STATUS_FAILED; } public void cancelExecution() { if (currentPhone != null) currentPhone.stopTestingMode(); if (logger != null) { logger.setStopATK(true); if (logger.isAlive()) { logger.interrupt(); logger.join(); } } } public void stopExecution() { if (currentPhone != null) { if (currentPhone.isInTestingMode()){ currentPhone.stopTestingMode(); } } documentGenerator = null; mapPerfGraph = null; mapAction = null; } /** * Return the result of the execution * * @return the result of the execution. Used in beanshell script. O if the * execution succeeds, 1 if an interpretation error happens, 2 if a * parse error happens, ... */ public int getResult() { return result; } /** * Stop the main log system */ private static void stopInfoLog() { // Logger.getLogger(this.getClass() ).debug("Stop the logger"); if (logger != null) { if (logger.isAlive()) { logger.interrupt(); // Logger.getLogger(this.getClass() ).debug("Waiting for loop"); logger.join(); // Logger.getLogger(this.getClass() ).debug("End of loop"); } } } /** * */ public void writeLogAndExitPhoneHandling() { stopInfoLog(); if (logger != null) { // write file action.log logger.writeActionLogFile(); logger.generateGraphFile(); logger.generatepltFile(); // write Error File pdf or Txt logger.dumpInStream(hasParseException); logger = null; } try { Thread.sleep(5000); } catch (InterruptedException e) { Logger.getLogger(this.getClass()).error(e); } String testName = new File(logDir).getName(); currentPhone.pullData("mnt/sdcard/ARO/"+testName,logDir+File.separator+"ARO"); currentPhone = null; } public void setIncludeDir(String dir) { JATKdir = dir; includeDir = dir + currentPhone.getIncludeDir(); } private String getLogDir() { return logDir; } public void setLogDir(String logDir) { this.logDir = logDir; } public String getLogType() { return logType; } public PhoneInterface getCurrentPhone() { return currentPhone; } private void setCurrentPhone() { // TODO null if no phone connected ? LaunchJATK.currentPhone = AutomaticPhoneDetection.getInstance().getDevice(); } private static int getTimeout() { return timeout; } public void setMapPerfGraph(Map<String, PerformanceGraph> mapPerfGraph) { this.mapPerfGraph = mapPerfGraph; } public void setMapAction(Map<String, GraphMarker> mapAction) { this.mapAction = mapAction; } public void errorOccured() { this.cancelExecution(); CoreGUIPlugin.mainFrame.statusBar.setStop(); // Launch Autodetect after a Cancel AutomaticPhoneDetection.getInstance().resumeDetection(); CoreGUIPlugin.mainFrame.statusBar.displayErrorMessage(); } public void warningOccured() { CoreGUIPlugin.mainFrame.statusBar.displayErrorMessage(); } /******************************** METHOD TO LAUNCH ATK FROM LINE COMMAND **********************************/ public static void main(String[] args) { checkargs(args); } /** * This method check arguments and parse arguments * * @param args * arguments list */ private static void checkargs(String[] args) { // TODO : -c should be optional, in that case default phone config file // should be used // TODO : -pm should be specifiable String usage = "Usage : \n" + "test <test_options> WHERE test_options are :\n" + "\t -tf <test_file.tst> -c <monitoring_config.xml>\n" + "\t -td <test_dir> -c <monitoring_config.xml>\n" + "\t -rd <result_dir>\n" + "\t -device [optional device_serial_number]"; if (args.length == 0 || (args.length == 1 && args[0].equals("-h"))) { System.out.println(usage); result = 3; return; } DOMConfigurator.configure(Platform.getInstance().getJATKPath() + Platform.FILE_SEPARATOR + "log4j.xml"); AutomaticPhoneDetection.getInstance(false).checkDevices(); List<PhoneInterface> devices = AutomaticPhoneDetection.getInstance().getDevices(); if (devices.size() == 0) { Logger.getLogger(LaunchJATK.class).error("FAILED: no device detected."); } else { AutomaticPhoneDetection.getInstance().setSelectedDevice(devices.get(0)); LaunchJATK launcher = new LaunchJATK(); String result = launcher.parseArguments(args); if (result != null) { Logger.getLogger(LaunchJATK.class).debug(result); } } AndroidDebugBridge.disconnectBridge(); AndroidDebugBridge.terminate(); } private String parseArguments(String[] args) { if (!args[0].equals("test")) return ("FAILED: test command is missing."); String device_serial = null; String result_dir = null; Vector<String> test_files = new Vector<String>(); Vector<String> config_files = new Vector<String>(); for (int i = 1; i < args.length; i++) { if (args[i].equals("-rd")) { i++; if (i == args.length) return ("FAILED: [-rd option] missing result directory path."); else { File dir = new File(args[i]); if (!dir.exists()) return ("FAILED: [-rd option] result directory does not exist."); else result_dir = args[i]; } } else if (args[i].equals("-tf")) { i++; if (i == args.length) return ("FAILED: [-tf option] missing test file path."); else { File file = new File(args[i]); if (!file.exists()) return ("FAILED: [-tf option] test file " + args[i] + " not found."); else { test_files.add(args[i]); i++; if (i == args.length || !args[i].equals("-c")) return ("FAILED: -c <config_file_path> option missing."); else { i++; if (i == args.length) return ("FAILED: [-c option] missing config file path."); else { file = new File(args[i]); if (!file.exists()) return ("FAILED: [-c option] config file " + args[i] + " not found."); else { config_files.add(args[i]); } } } } } } else if (args[i].equals("-td")) { i++; if (i == args.length) return ("FAILED: [-td option] missing test directory path."); else { File file = new File(args[i]); if (!file.exists()) return ("FAILED: [-td option] test directory does not exist."); else { String[] tfiles = file.list(new SuffixFilter("tst")); if (tfiles.length == 0) return ("FAILED: [-td option] test directory does not contain any .tst file."); for (int j = 0; j < tfiles.length; j++) { test_files.add(args[i] + Platform.FILE_SEPARATOR + tfiles[j]); } i++; if (i == args.length || !args[i].equals("-c")) return ("FAILED: -c <config_file_path> option missing."); else { i++; if (i == args.length) return ("FAILED: [-c option] missing config file path."); else { file = new File(args[i]); if (!file.exists()) return ("FAILED: [-c option] config file " + args[i] + " not found."); else { for (int j = 0; j < tfiles.length; j++) { config_files.add(args[i]); } } } } } } } else if (args[i].equals("-device")) { i++; if (i < args.length) { device_serial = args[i]; List<PhoneInterface> devices = AutomaticPhoneDetection.getInstance() .getDevices(); for (int j = 0; j < devices.size(); j++) { if (devices.get(j).getSerialNumber().equalsIgnoreCase(device_serial)) { AutomaticPhoneDetection.getInstance().setSelectedDevice(devices.get(j)); break; } } } } } if (result_dir == null) return ("FAILED: -rd <result_directory> option must be specified."); if (test_files.size() == 0) return ("FAILED: at least one test file must be specified, using -tf and/or -td options."); for (int i = 0; i < test_files.size(); i++) { this.testFile = test_files.get(i); this.realTestFile = testFile; String testFileName = (new File(testFile)).getName(); this.logDir = result_dir + Platform.FILE_SEPARATOR + testFileName.substring(0, testFileName.lastIndexOf(".")); try { String result = launchNewTest(config_files.get(i), true); System.out.println(result + ": test " + testFile); } catch (FileNotFoundException e) { return ("FAILED: test " + testFile); } catch (PhoneException e) { return ("FAILED: test " + testFile); } } return null; } public class SuffixFilter implements FilenameFilter { private String suffix; public SuffixFilter(String suffix) { this.suffix = "." + suffix; } public boolean accept(File dir, String name) { return name.endsWith(suffix); } } }