All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.dagere.peass.execution.gradle.AnboxTestExecutor Maven / Gradle / Ivy

The newest version!
package de.dagere.peass.execution.gradle;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.fasterxml.jackson.databind.node.ObjectNode;

import de.dagere.nodeDiffDetector.data.TestMethodCall;
import de.dagere.peass.execution.processutils.ProcessBuilderHelper;
import de.dagere.peass.execution.utils.CommandConcatenator;
import de.dagere.peass.execution.utils.EnvironmentVariables;
import de.dagere.peass.folders.PeassFolders;
import de.dagere.peass.testtransformation.JUnitTestTransformer;
import de.dagere.peass.utils.Constants;
import de.dagere.peass.utils.StreamGobbler;

public class AnboxTestExecutor extends GradleTestExecutor {

   public static final String ANBOX_EMULATOR_FOLDER_BASE = "/storage/emulated/0/Documents/peass/";
   public static final String ANBOX_EMULATOR_FOLDER_TEMP_RESULT = ANBOX_EMULATOR_FOLDER_BASE + "measurementsTemp/";
   public static final String ANDROID_RESOURCES_FOLDER = "app/src/main/resources/";
   public static final String ANDROID_KOPEME_CONFIGURATION = "kopeme_config.json";

   private static final Logger LOG = LogManager.getLogger(AnboxTestExecutor.class);

   private final String adbCall;
   private final AnboxDirHandler dirHandler;

   public AnboxTestExecutor(final PeassFolders folders, final JUnitTestTransformer testTransformer, final EnvironmentVariables env) {
      super(folders, testTransformer, env);
      this.adbCall = EnvironmentVariables.fetchAdbCall();
      dirHandler = new AnboxDirHandler(adbCall);
   }

   @Override
   public void prepareKoPeMeExecution(final File logFile) {
      super.prepareKoPeMeExecution(logFile);

      writeAndroidConfigJson();
      updateAndroidManifest();
      adbPush();
      compileSources();
   }

   /**
    * Writes Android configuration file inside "app/src/main/resources" to pass values for KoPeMe inside the emulator.
    */
   private void writeAndroidConfigJson() {
      ObjectNode androidConfig = Constants.OBJECTMAPPER.createObjectNode();
      androidConfig.put("KOPEME_HOME", ANBOX_EMULATOR_FOLDER_TEMP_RESULT);
      // TODO: Change the hard coded module name 'app'.
      androidConfig.put("kopeme.workingdir", ANBOX_EMULATOR_FOLDER_BASE + "app");
      File kopemeConfig = new File(folders.getProjectFolder() + "/" + ANDROID_RESOURCES_FOLDER + ANDROID_KOPEME_CONFIGURATION);
      LOG.debug("Creating file: {} with content: {}", kopemeConfig, androidConfig.toString());
      try {
         kopemeConfig.getParentFile().mkdirs();
         Constants.OBJECTMAPPER.writerWithDefaultPrettyPrinter().writeValue(kopemeConfig, androidConfig);
      } catch (IOException e) {
         LOG.error(e.getMessage());
         throw new RuntimeException(e);
      }
   }

   private void updateAndroidManifest() {
      File projectFolder = folders.getProjectFolder();

      String relativeManifestFilePath = testTransformer.getConfig().getExecutionConfig().getAndroidManifest();

      if (relativeManifestFilePath != null) {
         File manifestFile = new File(projectFolder, relativeManifestFilePath);

         try {
            ManifestEditor manifestEditor = new ManifestEditor(manifestFile);
            manifestEditor.updateForExternalStorageReadWrite();
         } catch (Exception ex) {
            ex.printStackTrace();
         }
      } else {
         LOG.error("Android manifest file path is not specified. Use --androidManifest switch to specify the path.");
      }
   }

   private void compileSources() {
      String wrapper = new File(folders.getProjectFolder(), EnvironmentVariables.fetchGradleCall()).getAbsolutePath();
      List gradleTasks = testTransformer.getConfig().getExecutionConfig().getAndroidGradleTasks();

      String[] processArgs = toMergedArray(wrapper, gradleTasks);
      LOG.debug("Command: {}", Arrays.toString(processArgs));

      ProcessBuilder builder = new ProcessBuilder(processArgs);
      builder.directory(folders.getProjectFolder());
      for (Map.Entry entry : env.getEnvironmentVariables().entrySet()) {
         LOG.trace("Environment: {} = {}", entry.getKey(), entry.getValue());
         builder.environment().put(entry.getKey(), entry.getValue());
      }

      try {
         Process process = builder.start();
         String processOutput = StreamGobbler.getFullProcess(process, true);
         LOG.debug(processOutput);
      } catch (IOException e) {
         LOG.error(e.getMessage());
         throw new RuntimeException(e);
      }
   }

   private String[] toMergedArray(String first, List remaining)
   {
      String[] mergedArray = new String[1 + (remaining != null ? remaining.size() : 0)];
      mergedArray[0] = first;

      if (remaining != null) {
         int index = 1;

         for (String element : remaining) {
            mergedArray[index++] = element;
         }
      }

      return mergedArray;
   }

   /**
    * Executes the adb push command. Copies config files necessary for proper execution of KoPeMe
    */
   private void adbPush() {
      // cleanup previous iteration
      dirHandler.removeDirInEmulator(ANBOX_EMULATOR_FOLDER_BASE);
      dirHandler.createDirInEmulator(ANBOX_EMULATOR_FOLDER_BASE);

      // copy files
      final String[] filesToBePushed = {
            "build.gradle",
            "gradle.properties",
            "app/build.gradle"
      };

      final File sourceFolder = folders.getProjectFolder();

      for (final String fileName : filesToBePushed) {
         File f = new File(fileName);

         pushSingleFile(sourceFolder, fileName, f);
      }
   }

   private void pushSingleFile(final File sourceFolder, final String fileName, File f) {
      // create directories if necessary
      if (f.getParent() != null) {
         String subDir = String.format("%s%s", ANBOX_EMULATOR_FOLDER_BASE, f.getParent());
         dirHandler.createDirInEmulator(subDir);
      }

      // push the file
      String destinationFolder = ANBOX_EMULATOR_FOLDER_BASE + (f.getParent() != null ? (f.getParent() + "/") : "");

      ProcessBuilder builder = new ProcessBuilder(adbCall, "push", fileName, destinationFolder);
      builder.directory(sourceFolder);
      LOG.debug("ADB: Pushing {}/{} to {}", sourceFolder, fileName, destinationFolder);

      try {
         Process process = builder.start();
         String processOutput = StreamGobbler.getFullProcess(process, true);
         LOG.debug(processOutput);
      } catch (IOException e) {
         LOG.error(e.getMessage());
         throw new RuntimeException(e);
      }
   }

   /**
    * Executes the adb pull command. Copies measurementsTemp folder from emulator to the temporary project folder.
    */
   private void adbPull() {
      ProcessBuilder builder = new ProcessBuilder(adbCall, "pull", ANBOX_EMULATOR_FOLDER_TEMP_RESULT, ".");
      builder.directory(folders.getPeassFolder());
      LOG.debug("ADB: Pulling {} to {}", ANBOX_EMULATOR_FOLDER_TEMP_RESULT, folders.getPeassFolder());
      try {
         Process process = builder.start();
         String processOutput = StreamGobbler.getFullProcess(process, true);
         LOG.debug(processOutput);
      } catch (IOException e) {
         LOG.error(e.getMessage());
         throw new RuntimeException(e);
      }
   }

   /**
    * Executes the Gradle process; since gradle is run inside the module folder, different parameters than for the maven execution are required
    */
   private Process buildGradleProcess(final File moduleFolder, final File logFile, TestMethodCall test) {

      String[] anboxOriginals = new String[] { adbCall, "shell", "am", "instrument", "-w", "-m", "-e", "class" };

      final String testPackageName = getTestPackageName(test);

      final String[] vars = CommandConcatenator.concatenateCommandArrays(anboxOriginals,
            new String[] { test.getExecutable(), testPackageName + "/androidx.test.runner.AndroidJUnitRunner" });
      ProcessBuilderHelper processBuilderHelper = new ProcessBuilderHelper(env, folders);
      processBuilderHelper.parseParams(test.getParams());

      LOG.debug("Executing gradle test in moduleFolder: {}", moduleFolder);
      return processBuilderHelper.buildFolderProcess(moduleFolder, logFile, vars);
   }

   public String getTestPackageName(TestMethodCall test) {
      String testPackageName = getTestPackageName();

      if (testPackageName != null) {
         return testPackageName;
      }
      if (test.getPackage().endsWith(".test")) {
         testPackageName = test.getPackage();
      } else {
         testPackageName = test.getPackage() + ".test";
      }
      return testPackageName;
   }

   public String getTestPackageName() {
      final String testPackageName = getTestTransformer().getConfig().getExecutionConfig().getAndroidTestPackageName();
      return testPackageName;
   }

   /**
    * Runs the given test and saves the results to the result folder.
    * 
    * @param specialResultFolder Folder for saving the results
    * @param testname Name of the test that should be run
    */
   @Override
   protected void runTest(final File moduleFolder, final File logFile, TestMethodCall test, final String testname, final long timeout) {
      final Process process = buildGradleProcess(moduleFolder, logFile, test);
      execute(testname, timeout, process);
      adbPull();
   }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy