/* This file is part of SlumDroid <https://github.com/slumdroid/slumdroid>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * 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 General Public License <http://www.gnu.org/licenses/gpl-3.0.txt> * for more details. * * Copyright (C) 2012-2016 Gennaro Imparato */ package it.slumdroid.tool.components.engine; import static it.slumdroid.tool.Resources.CLASS_NAME; import static it.slumdroid.tool.Resources.SCREENSHOT_ENABLED; import static it.slumdroid.tool.Resources.SLEEP_AFTER_TASK; import static it.slumdroid.tool.Resources.TAG; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Element; import android.util.Log; import it.slumdroid.droidmodels.guitree.GuiTree; import it.slumdroid.droidmodels.model.ActivityState; import it.slumdroid.droidmodels.model.Session; import it.slumdroid.droidmodels.model.Task; import it.slumdroid.droidmodels.model.Transition; import it.slumdroid.droidmodels.xml.XmlGraph; import it.slumdroid.tool.components.abstractor.Abstractor; import it.slumdroid.tool.components.automation.Automation; import it.slumdroid.tool.components.exploration.ExplorationStrategy; import it.slumdroid.tool.components.persistence.PersistenceFactory; import it.slumdroid.tool.components.persistence.ResumingPersistence; import it.slumdroid.tool.components.planner.Plan; import it.slumdroid.tool.components.planner.UltraPlanner; import it.slumdroid.tool.components.scheduler.TraceDispatcher; import it.slumdroid.tool.model.ActivityDescription; import it.slumdroid.tool.model.SaveStateListener; import it.slumdroid.tool.utilities.AllPassFilter; import it.slumdroid.tool.utilities.SessionParams; import it.slumdroid.tool.utilities.UserFactory; // TODO: Auto-generated Javadoc /** * The Class SlumDroidEngine. */ @SuppressWarnings({ "rawtypes" }) public class SlumDroidEngine extends android.test.ActivityInstrumentationTestCase2 implements SaveStateListener { /** The Constant ACTOR_NAME. */ public final static String ACTOR_NAME = "SlumDroidEngine"; /** The Constant PARAM_NAME. */ private final static String PARAM_NAME = "taskId"; /** The id. */ private int id = 0; /** The abstractor. */ private Abstractor theAbstractor = new Abstractor(); /** The automation. */ private Automation theAutomation = new Automation(); /** The persistence. */ private ResumingPersistence thePersistence; /** The persistence factory. */ protected PersistenceFactory thePersistenceFactory; /** The planner. */ private UltraPlanner thePlanner = new UltraPlanner(); /** The scheduler. */ private TraceDispatcher theScheduler = new TraceDispatcher(); /** The strategy. */ private ExplorationStrategy theStrategy = new ExplorationStrategy(); /** * Instantiates a new SlumDroid engine. * * @throws ClassNotFoundException the class not found exception * @throws ParserConfigurationException the parser configuration exception */ @SuppressWarnings("unchecked") public SlumDroidEngine() throws ClassNotFoundException, ParserConfigurationException { super(Class.forName(CLASS_NAME)); getTheGuiTree().setDateTime(new GregorianCalendar().getTime().toString()); AllPassFilter inputFilter = new AllPassFilter(); getPlanner().setInputFilter(inputFilter); getAbstractor().addFilter(inputFilter); AllPassFilter eventFilter = new AllPassFilter(); getPlanner().setEventFilter(eventFilter); getAbstractor().addFilter(eventFilter); getPlanner().setUser(UserFactory.getUser(getAbstractor())); getPlanner().setFormFiller(UserFactory.getUser(getAbstractor())); getPlanner().setAbstractor(getAbstractor()); PersistenceFactory.registerForSavingState(this); setPersistenceFactory(new PersistenceFactory (getTheGuiTree(), getScheduler(), getStrategy())); setPersistence(getPersistenceFactory().getPersistence()); } /* (non-Javadoc) * @see android.test.ActivityInstrumentationTestCase2#setUp() */ protected void setUp() throws Exception { super.setUp(); getAutomation().bind(this); getPersistence().setContext(Automation.getCurrentActivity()); Automation.getExtractor().extractState(); ActivityDescription description = Automation.getExtractor().describeActivity(); getAbstractor().setBaseActivity(description); if (!resume()) { setupFirstStart(); } } /** * Setup first start. */ protected void setupFirstStart() { ActivityState baseActivity = getAbstractor().getBaseActivity(); getStrategy().addState(baseActivity); Log.i(TAG, "Ripping starts\nInitial Start Activity State saved"); if (SCREENSHOT_ENABLED) { getAutomation().wait(500); takeScreenshot(baseActivity); } planFirstTests(baseActivity); } /** * Test and crawl. */ public void testAndCrawl() { for (Task theTask: getScheduler()) { getStrategy().setTask(theTask); getAutomation().execute(theTask); ActivityDescription theDescription = Automation.getExtractor().describeActivity(); ActivityState theState = getAbstractor().createActivity(theDescription); if (theState.isExit()) { Log.i(TAG, "Exit state"); } else { getStrategy().compareState(theState); if (SCREENSHOT_ENABLED) { takeScreenshot(theState); } } if (SLEEP_AFTER_TASK != 0) { getAutomation().wait(SLEEP_AFTER_TASK); } getAbstractor().setFinalActivity(theTask, theState); getPersistence().addTask(theTask); if (canPlanTests(theState)) { planTests(theTask, theState); } break; } } /** * Can plan tests. * * @param theState the the state * @return true, if successful */ protected boolean canPlanTests(ActivityState theState) { return !theState.isExit() && getStrategy().checkForExploration(); } /* (non-Javadoc) * @see android.test.ActivityInstrumentationTestCase2#tearDown() */ @Override protected void tearDown() throws Exception { if ((getStrategy().getTask() != null) && (getStrategy().getTask().isFailed())) { getTheGuiTree().addFailedTask(getStrategy().getTask()); } getPersistence().save(); Automation.getRobotium().finishOpenedActivities(); super.tearDown(); } /** * Resume. * * @return true, if successful */ public boolean resume() { ResumingPersistence resumer = getPersistence(); if (!resumer.canHasResume()) { return false; } importTaskList(resumer); importActivitiyList(resumer); resumer.loadParameters(); resumer.setNotFirst(); resumer.saveStep(); return true; } /** * Import activitiy list. * * @param resumer the resumer */ public void importActivitiyList(ResumingPersistence resumer) { Session sandboxSession = getNewSession(); List<String> entries = resumer.readStateFile(); List<ActivityState> stateList = new ArrayList<ActivityState>(); for (String row: entries) { sandboxSession.parse(row); Element element = ((XmlGraph)sandboxSession).getDom().getDocumentElement(); ActivityState state = getAbstractor().importState(element); stateList.add(state); } for (ActivityState state: stateList) { getStrategy().addState(state); } } /** * Import task list. * * @param resumer the resumer */ public void importTaskList(ResumingPersistence resumer) { Session sandboxSession = getNewSession(); List<String> entries = resumer.readTaskFile(); List<Task> taskList = new ArrayList<Task>(); for (String row: entries) { sandboxSession.parse(row); Element element = ((XmlGraph)sandboxSession).getDom().getDocumentElement(); Task task = getAbstractor().importTask(element); if (task.isFailed()) { getTheGuiTree().addCrashedTask(task); } else { taskList.add(task); } } getScheduler().addTasks(taskList); } /** * Plan first tests. * * @param theState the state */ protected void planFirstTests(ActivityState theState) { planTests(null, theState); } /** * Plan tests. * * @param theTask the task * @param theState the state */ protected void planTests(Task theTask, ActivityState theState) { Plan thePlan = getPlanner().getPlanForActivity(theState); planTests(theTask, thePlan); } /** * Plan tests. * * @param theTask the task * @param thePlan the plan */ protected void planTests(Task theTask, Plan thePlan) { List<Task> tasks = new ArrayList<Task>(); for (Transition transition: thePlan) { tasks.add(getNewTask(theTask, transition)); } getScheduler().addPlannedTasks(tasks); } /** * Gets the new task. * * @param theTask the task * @param transition the transition * @return the new task */ protected Task getNewTask(Task theTask, Transition transition) { Task newTask = getAbstractor().createTask(theTask, transition); newTask.setId(nextId()); return newTask; } /** * Gets the automation. * * @return the automation */ public Automation getAutomation() { return theAutomation; } /** * Gets the abstractor. * * @return the abstractor */ public Abstractor getAbstractor() { return this.theAbstractor; } /** * Gets the gui tree. * * @return the gui tree */ private GuiTree getTheGuiTree() { return getAbstractor().getTheSession(); } /** * Gets the persistence. * * @return the persistence */ public ResumingPersistence getPersistence() { return this.thePersistence; } /** * Sets the persistence. * * @param thePersistence the new persistence */ public void setPersistence(ResumingPersistence thePersistence) { this.thePersistence = thePersistence; } /** * Gets the persistence factory. * * @return the persistence factory */ public PersistenceFactory getPersistenceFactory() { return thePersistenceFactory; } /** * Sets the persistence factory. * * @param thePersistenceFactory the new persistence factory */ public void setPersistenceFactory(PersistenceFactory thePersistenceFactory) { this.thePersistenceFactory = thePersistenceFactory; } /** * Gets the planner. * * @return the planner */ public UltraPlanner getPlanner() { return this.thePlanner; } /** * Gets the scheduler. * * @return the scheduler */ public TraceDispatcher getScheduler() { return this.theScheduler; } /** * Gets the strategy. * * @return the strategy */ public ExplorationStrategy getStrategy() { return this.theStrategy; } /** * Gets the last id. * * @return the last id */ public int getLastId() { return this.id; } /** * Next id. * * @return the string */ protected String nextId() { int num = id; id++; return String.valueOf(num); } /** * Take screenshot. * * @param theState the state */ private void takeScreenshot(ActivityState theState) { String fileName = theState.getUniqueId(); if (getPersistence().saveScreenshot(fileName + ".png")) { theState.setScreenshot(fileName + ".png"); Log.i(TAG, "Saved image on disk: " + fileName + ".png"); } else { theState.setScreenshot(new String()); } } /** * Gets the new session. * * @return the new session */ public Session getNewSession() { try { return new GuiTree(); } catch (ParserConfigurationException e) { e.printStackTrace(); } return null; } /* (non-Javadoc) * @see it.slumdroid.tool.model.SaveStateListener#onSavingState() */ public SessionParams onSavingState() { SessionParams state = new SessionParams(); state.store(PARAM_NAME, getLastId()); return state; } /* (non-Javadoc) * @see it.slumdroid.tool.model.SaveStateListener#onLoadingState(it.slumdroid.tool.utilities.SessionParams) */ public void onLoadingState(SessionParams sessionParams) { this.id = sessionParams.getInt(PARAM_NAME); } /* (non-Javadoc) * @see it.slumdroid.tool.model.SaveStateListener#getListenerName() */ public String getListenerName() { return ACTOR_NAME; } }