async endSimulatorDaemon () {
    // Looks for launchd daemons corresponding to the sim udid and tries to stop them cleanly
    // This prevents xcrun simctl erase hangs.
    log.debug(`Killing any simulator daemons for ${this.udid}`);

    let launchctlCmd = `launchctl list | grep ${this.udid} | cut -f 3 | xargs -n 1 launchctl`;
    try {
      let stopCmd = `${launchctlCmd} stop`;
      await exec('bash', ['-c', stopCmd]);
    } catch (err) {
      log.warn(`Could not stop simulator daemons: ${err.message}`);
      log.debug('Carrying on anyway!');
    }
    try {
      let removeCmd = `${launchctlCmd} remove`;
      await exec('bash', ['-c', removeCmd]);
    } catch (err) {
      log.warn(`Could not remove simulator daemons: ${err.message}`);
      log.debug('Carrying on anyway!');
    }
    try {
      // Waits 10 sec for the simulator launchd services to stop.
      await waitForCondition(async () => {
        let {stdout} = await exec('bash', ['-c',
          `ps -e  | grep ${this.udid} | grep launchd_sim | grep -v bash | grep -v grep | awk {'print$1'}`]);
        return stdout.trim().length === 0;
      }, {waitMs: 10000, intervalMs: 500});
    } catch (err) {
      log.warn(`Could not end simulator daemon for ${this.udid}: ${err.message}`);
      log.debug('Carrying on anyway!');
    }
  }
Пример #2
0
apkSigningMethods.signWithCustomCert = async function signWithCustomCert (apk) {
  log.debug(`Signing '${apk}' with custom cert`);
  if (!(await fs.exists(this.keystorePath))) {
    throw new Error(`Keystore: ${this.keystorePath} doesn't exist.`);
  }
  if (!(await fs.exists(apk))) {
    throw new Error(`'${apk}' doesn't exist.`);
  }

  try {
    const args = ['sign',
      '--ks', this.keystorePath,
      '--ks-key-alias', this.keyAlias,
      '--ks-pass', `pass:${this.keystorePassword}`,
      '--key-pass', `pass:${this.keyPassword}`,
      apk];
    await this.executeApksigner(args);
  } catch (err) {
    log.warn(`Cannot use apksigner tool for signing. Defaulting to jarsigner. ` +
      `Original error: ${err.message}`);
    try {
      log.debug('Unsigning apk.');
      await exec(getJavaForOs(), ['-jar', path.resolve(this.helperJarPath, 'unsign.jar'), apk]);
      log.debug('Signing apk.');
      const jarsigner = path.resolve(getJavaHome(), 'bin', `jarsigner${system.isWindows() ? '.exe' : ''}`);
      await exec(jarsigner, ['-sigalg', 'MD5withRSA', '-digestalg', 'SHA1',
        '-keystore', this.keystorePath, '-storepass', this.keystorePassword,
        '-keypass', this.keyPassword, apk, this.keyAlias]);
    } catch (e) {
      throw new Error(`Could not sign with custom certificate. Original error ${e.message}`);
    }
  }
};
Пример #3
0
async function endAllSimulatorDaemons () {
  log.debug('Ending all simulator daemons');
  for (let servicePattern of ['com.apple.iphonesimulator', 'com.apple.CoreSimulator']) {
    log.debug(`Killing any other ${servicePattern} daemons`);
    let launchCtlCommand = `launchctl list | grep ${servicePattern} | cut -f 3 | xargs -n 1 launchctl`;
    try {
      let stopCmd = `${launchCtlCommand} stop`;
      await exec('bash', ['-c', stopCmd]);
    } catch (err) {
      log.warn(`Could not stop ${servicePattern} daemons, carrying on anyway!`);
    }
    try {
      let removeCmd = `${launchCtlCommand} remove`;
      await exec('bash', ['-c', removeCmd]);
    } catch (err) {
      log.warn(`Could not remove ${servicePattern} daemons, carrying on anyway!`);
    }
  }
  // waiting until the simulator service has died.
  try {
    await waitForCondition(async () => {
      let {stdout} = await exec('bash', ['-c',
        `ps -e  | grep launchd_sim | grep -v bash | grep -v grep | awk {'print$1'}`]);
      return stdout.trim().length === 0;
    }, {waitMs: 5000, intervalMs: 500});
  } catch (err) {
    log.warn(`Could not end all simulator daemons, carrying on!`);
  }
  log.debug('Finishing ending all simulator daemons');
}
Пример #4
0
apkSigningMethods.signWithCustomCert = async function (apk) {
  log.debug(`Signing '${apk}' with custom cert`);
  const java = getJavaForOs();
  let javaHome = getJavaHome();
  let jarsigner = path.resolve(javaHome, 'bin', 'jarsigner');
  if (system.isWindows()) {
    jarsigner = jarsigner + '.exe';
  }
  if (!(await fs.exists(this.keystorePath))) {
    throw new Error(`Keystore: ${this.keystorePath} doesn't exist.`);
  }
  if (!(await fs.exists(apk))) {
    throw new Error(`${apk} file doesn't exist.`);
  }
  try {
    log.debug("Unsigning apk.");
    await exec(java, ['-jar', path.resolve(this.helperJarPath, 'unsign.jar'), apk]);
    log.debug("Signing apk.");
    await exec(jarsigner, ['-sigalg', 'MD5withRSA', '-digestalg', 'SHA1',
                           '-keystore', this.keystorePath, '-storepass', this.keystorePassword,
                           '-keypass', this.keyPassword, apk, this.keyAlias]);
  } catch (e) {
    log.errorAndThrow(`Could not sign with custom ceritficate. Original error ${e.message}`);
  }
};
Пример #5
0
apkSigningMethods.zipAlignApk = async function zipAlignApk (apk) {
  await this.initZipAlign();
  try {
    await exec(this.binaries.zipalign, ['-c', '4', apk]);
    log.debug(`${apk}' is already zip-aligned. Doing nothing`);
    return false;
  } catch (e) {
    log.debug(`'${apk}' is not zip-aligned. Aligning`);
  }
  try {
    await fs.access(apk, _fs.W_OK);
  } catch (e) {
    throw new Error(`The file at '${apk}' is not writeable. ` +
      `Please grant write permissions to this file or to its parent folder '${path.dirname(apk)}' ` +
      `for the Appium process, so it can zip-align the file`);
  }
  const alignedApk = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
  await mkdirp(path.dirname(alignedApk));
  try {
    await exec(this.binaries.zipalign, ['-f', '4', apk, alignedApk]);
    await fs.mv(alignedApk, apk, { mkdirp: true });
    return true;
  } catch (e) {
    if (await fs.exists(alignedApk)) {
      await fs.unlink(alignedApk);
    }
    throw new Error(`zipAlignApk failed. Original error: ${e.message}. Stdout: '${e.stdout}'; Stderr: '${e.stderr}'`);
  }
};
Пример #6
0
apkUtilsMethods.extractStringsFromApk = async function (apk, language, out) {
  log.debug(`Extracting strings for language: ${language || "default"}`);
  let stringsJson = 'strings.json';
  let localPath;
  if (!language) {
    language = await this.getDeviceLanguage();
  }
  let apkTools = this.jars['appium_apk_tools.jar'];
  let args = ['-jar', apkTools, 'stringsFromApk', apk, out, language];
  let fileData, apkStrings;
  try {
    await exec('java', args);
  } catch (e) {
    log.debug(`No strings.xml for language '${language}', getting default ` +
              `strings.xml`);
    args.pop();
    await exec('java', args);
  }

  try {
    log.debug("Reading strings from converted strings.json");
    localPath = path.join(out, stringsJson);
    fileData = await fs.readFile(localPath, 'utf8');
    apkStrings = JSON.parse(fileData);
  } catch (e) {
    if (fileData) {
      log.debug(`Content started with: ${fileData.slice(0, 300)}`);
    }
    let msg = `Could not parse strings from strings.json. Original ` +
              `error: ${e.message}`;
    log.errorAndThrow(msg);
  }
  return {apkStrings, localPath};
};
Пример #7
0
systemCallMethods.checkAvdExist = async function checkAvdExist (avdName) {
  let cmd, result;
  try {
    cmd = await this.getSdkBinaryPath('emulator');
    result = await exec(cmd, ['-list-avds']);
  } catch (e) {
    let unknownOptionError = new RegExp('unknown option: -list-avds', 'i').test(e.stderr);
    if (!unknownOptionError) {
      throw new Error(`Error executing checkAvdExist. Original error: '${e.message}'; ` +
                      `Stderr: '${(e.stderr || '').trim()}'; Code: '${e.code}'`);

    }
    const sdkVersion = await getSdkToolsVersion();
    let binaryName = 'android';
    if (sdkVersion) {
      if (sdkVersion.major >= 25) {
        binaryName = 'avdmanager';
      }
    } else {
      log.warn(`Defaulting binary name to '${binaryName}', because SDK version cannot be parsed`);
    }
    // If -list-avds option is not available, use android command as an alternative
    cmd = await this.getSdkBinaryPath(binaryName);
    result = await exec(cmd, ['list', 'avd', '-c']);
  }
  if (result.stdout.indexOf(avdName) === -1) {
    let existings = `(${result.stdout.trim().replace(/[\n]/g, '), (')})`;
    throw new Error(`Avd '${avdName}' is not available. please select your avd name from one of these: '${existings}'`);
  }
};
Пример #8
0
async function getScreenshotWithIdevicelib (udid, isLandscape) {
  const pathToScreenshotTiff = await tempDir.path({prefix: `screenshot-${udid}`, suffix: '.tiff'});
  await fs.rimraf(pathToScreenshotTiff);
  const pathToResultPng = await tempDir.path({prefix: `screenshot-${udid}`, suffix: '.png'});
  await fs.rimraf(pathToResultPng);
  try {
    try {
      await exec('idevicescreenshot', ['-u', udid, pathToScreenshotTiff]);
    } catch (e) {
      throw new Error(`Cannot take a screenshot from the device '${udid}' using ` +
        `idevicescreenshot. Original error: ${e.message}`);
    }
    let sipsArgs = ['-s', 'format', 'png', pathToScreenshotTiff, '--out', pathToResultPng];
    if (isLandscape) {
      sipsArgs = ['-r', '-90', ...sipsArgs];
    }
    try {
      // The sips tool is only present on Mac OS
      await exec('sips', sipsArgs);
    } catch (e) {
      throw new Error(`Cannot convert a screenshot from TIFF to PNG using sips tool. ` +
        `Original error: ${e.message}`);
    }
    if (!await fs.exists(pathToResultPng)) {
      throw new Error(`Cannot convert a screenshot from TIFF to PNG. The conversion ` +
        `result does not exist at '${pathToResultPng}'`);
    }
    return (await fs.readFile(pathToResultPng)).toString('base64');
  } finally {
    await fs.rimraf(pathToScreenshotTiff);
    await fs.rimraf(pathToResultPng);
  }
}
 /**
  * Kill the UI client if it is running.
  *
  * @param {boolean} force - Set it to true to send SIGKILL signal to Simulator process.
  *                          SIGTERM will be sent by default.
  * @return {boolean} True if the UI client was successfully killed or false
  *                   if it is not running.
  */
 async killUIClient (force = false) {
   const osascriptArgs = ['-e', `tell application "System Events" to unix id of processes whose bundle identifier is "${this.uiClientBundleId}"`];
   const {stdout} = await exec('osascript', osascriptArgs);
   if (!stdout.trim().length) {
     return false;
   }
   const killArgs = force ? ['-9', stdout.trim()] : [stdout.trim()];
   await exec('kill', killArgs);
   return true;
 }
Пример #10
0
  async retrieveDerivedDataPath () {
    if (this._derivedDataPath) {
      return this._derivedDataPath;
    }

    // try a number of ways to find the derived data folder for this run
    const pid = await getPidUsingPattern(`xcodebuild.*${this.device.udid}`);
    if (!pid) {
      log.debug(`Cannot find xcodebuild's process id, so unable to retrieve DerivedData folder path`);
      return;
    }
    let stdout = '';
    try {
      const execInfo = await exec('lsof', ['-p', pid]);
      stdout = execInfo.stdout;
    } catch (err) {
      log.debug(`Cannot get the list of files opened by xcodebuild process (pid: ${pid}) because of '${err.stderr}'`);
      return;
    }
    // try to find a derived data folder open by xcodebuild
    let match = DERIVED_DATA_FOLDER_REGEXP.exec(stdout);
    if (!match) {
      // no match found, so try to find the log file and search inside for the derived data instead
      log.debug(`Cannot find a match for DerivedData folder path from lsof. Trying to access logs`);
      match = DERIVED_DATA_LOG_REGEXP.exec(stdout);
      if (!match) {
        // still no go. We are done
        log.debug(`Cannot find a match for xcodebuild log file. No derived data folder will be found`);
        return;
      }
      // now parse the log file for the derived data folder
      const logFile = match[1];
      try {
        // grep on the log file, since it might be too big to fit it completely into the memory
        const grepData = await exec('grep', [DERIVED_DATA_GREP_EXPRESSION, logFile]);
        match = DERIVED_DATA_FOLDER_REGEXP.exec(grepData.stdout);
        if (!match) {
          // nothing found. We are done
          log.debug(`Cannot find the derived data location from the xcodebuild log file '${logFile}'`);
          return;
        }
      } catch (e) {
        log.warn(`Cannot grep on the the xcodebuild log file '${logFile}'. Original error: ${e.message}`);
        return;
      }
    }

    // at this point we have gotten a match by one of the two ways above, so save it
    this._derivedDataPath = match[1];

    return this._derivedDataPath;
  }
Пример #11
0
apkSigningMethods.signWithDefaultCert = async function signWithDefaultCert (apk) {
  log.debug(`Signing '${apk}' with default cert`);
  if (!(await fs.exists(apk))) {
    throw new Error(`${apk} file doesn't exist.`);
  }

  try {
    const args = ['sign',
      '--key', DEFAULT_PRIVATE_KEY,
      '--cert', DEFAULT_CERTIFICATE,
      apk];
    await this.executeApksigner(args);
  } catch (err) {
    log.warn(`Cannot use apksigner tool for signing. Defaulting to sign.jar. ` +
      `Original error: ${err.message}` + (err.stderr ? `; StdErr: ${err.stderr}` : ''));
    const java = getJavaForOs();
    const signPath = path.resolve(this.helperJarPath, 'sign.jar');
    log.debug('Resigning apk.');
    try {
      await exec(java, ['-jar', signPath, apk, '--override']);
    } catch (e) {
      throw new Error(`Could not sign with default certificate. Original error ${e.message}`);
    }
  }
};
Пример #12
0
async function setupSelendroid () {
  if (await fs.exists(SE_JAR_PATH) &&
      await fs.md5(SE_JAR_PATH) === SE_DOWNLOAD_MD5) {
    log.info("Standalone jar exists and has correct hash, skipping download");
  } else {
    await downloadSelendroid();
  }
  log.info(`Determining AndroidManifest location`);
  let manifestPath = await getFilePathFromJar(/AndroidManifest.*\.xml$/,
                                              SE_JAR_PATH);
  log.info(`Determining server apk location`);
  let serverPath = await getFilePathFromJar(/selendroid-server.*\.apk$/,
                                            SE_JAR_PATH);
  log.info(`Extracting manifest and apk to ${SE_DOWNLOAD_DIR}`);
  await exec('jar', ['xf', SE_JAR_PATH, manifestPath, serverPath], {
    cwd: SE_DOWNLOAD_DIR
  });
  log.info(`Copying manifest and apk to ${SE_DIR}`);
  let extractedManifestPath = path.resolve(SE_DOWNLOAD_DIR, manifestPath);
  let extractedServerPath = path.resolve(SE_DOWNLOAD_DIR, serverPath);
  await fs.copyFile(extractedManifestPath, SE_MANIFEST_PATH);
  await fs.copyFile(extractedServerPath, SE_APK_PATH);
  log.info("Cleaning up temp files");
  await fs.rimraf(extractedManifestPath);
  await fs.rimraf(extractedServerPath);
  log.info(`Fixing AndroidManifest icon bug`);
  await fixManifestIcons(SE_MANIFEST_PATH);
  if (!(await serverExists())) {
    throw new Error("Something went wrong in setting up selendroid");
  }
}
  async retrieveDerivedDataPath () {
    if (this.derivedDataPath) {
      return this.derivedDataPath;
    }

    let stdout;
    try {
      ({stdout} = await exec('xcodebuild', ['-project', this.agentPath, '-showBuildSettings']));
    } catch (err) {
      log.warn(`Cannot retrieve WDA build settings. Original error: ${err.message}`);
      return;
    }

    const pattern = /^\s*BUILD_DIR\s+=\s+(\/.*)/m;
    const match = pattern.exec(stdout);
    if (!match) {
      log.warn(`Cannot parse WDA build dir from ${_.truncate(stdout, {length: 300})}`);
      return;
    }
    log.debug(`Parsed BUILD_DIR configuration value: '${match[1]}'`);
    // Derived data root is two levels higher over the build dir
    this.derivedDataPath = path.dirname(path.dirname(path.normalize(match[1])));
    log.debug(`Got derived data root: '${this.derivedDataPath}'`);
    return this.derivedDataPath;
  }
Пример #14
0
async function detectUdid (caps) {
  if (caps.udid !== null && caps.udid === "auto") {
    logger.debug("Auto-detecting iOS udid...");
    let  cmd, args = [];
    try {
      cmd = await fs.which('idevice_id');
      args.push('-l');
    } catch (err) {
      cmd = require.resolve('udidetect');
    }
    let udid;
    try {
      let {stdout} = await exec(cmd, args, {timeout: 3000});
      udid = stdout.split("\n")[0];
    } catch (err) {
      logger.error("Error detecting udid");
      throw err;
    }
    if (udid && udid.length > 2) {
      caps.udid = udid;
      logger.debug(`Detected udid as '${caps.udid}'`);
    } else {
      throw new Error("Could not detect udid.");
    }
  } else {
    logger.debug("Not auto-detecting udid.");
  }
}
Пример #15
0
async function getConnectedDevices () {

  const cmd = '/usr/sbin/system_profiler';
  const args = ['-xml', 'SPUSBDataType'];
  let {stdout} = await exec(cmd, args, {timeout: XCODE_SELECT_TIMEOUT});
  let plistContent = parsePlistData(stdout);

  let devicesFound = [];
  let entriesToSearch = [plistContent[0]];
  while (entriesToSearch.length > 0) {
    let currentEntry = entriesToSearch.pop();
    if (currentEntry instanceof Array) {
      entriesToSearch = entriesToSearch.concat(currentEntry);
    } else if ((currentEntry._name &&
                currentEntry._name.substring(0, 4) === "iPad") ||
               (currentEntry._name &&
                currentEntry._name.substring(0, 6) === "iPhone")) {
      let deviceInfo = {
        name: currentEntry._name,
        udid: currentEntry.serial_num,
        productId: currentEntry.product_id,
        deviceVersion: currentEntry.bcd_device
      };
      devicesFound.push(deviceInfo);
    } else if (currentEntry._items) {
      entriesToSearch = entriesToSearch.concat(currentEntry._items);
    }
  }
  return devicesFound;
}
Пример #16
0
systemCallMethods.isMitmCertificateInstalled = async function isMitmCertificateInstalled (cert) {
  const openSsl = await getOpenSslForOs();

  if (!_.isBuffer(cert)) {
    cert = Buffer.from(cert, 'base64');
  }

  const tmpRoot = await tempDir.openDir();
  let certHash;
  try {
    const tmpCert = path.resolve(tmpRoot, 'source.cer');
    await fs.writeFile(tmpCert, cert);
    const {stdout} = await exec(openSsl, ['x509', '-noout', '-hash', '-in', tmpCert]);
    certHash = stdout.trim();
  } catch (err) {
    throw new Error(`Cannot retrieve the certificate hash. ` +
                    `Is the certificate properly encoded into base64-string? ` +
                    `Original error: ${err.message}`);
  } finally {
    await fs.rimraf(tmpRoot);
  }
  const dstPath = path.posix.resolve(CERTS_ROOT, `${certHash}.0`);
  log.debug(`Checking if the certificate is already installed at '${dstPath}'`);
  return await this.fileExists(dstPath);
};
Пример #17
0
systemCallMethods.getConnectedDevices = async function getConnectedDevices () {
  log.debug('Getting connected devices...');
  try {
    let {stdout} = await exec(this.executable.path, this.executable.defaultArgs.concat(['devices']));
    // expecting adb devices to return output as
    // List of devices attached
    // emulator-5554	device
    let startingIndex = stdout.indexOf('List of devices');
    if (startingIndex === -1) {
      throw new Error(`Unexpected output while trying to get devices. output was: ${stdout}`);
    }
    // slicing ouput we care about.
    stdout = stdout.slice(startingIndex);
    let devices = [];
    for (let line of stdout.split('\n')) {
      if (line.trim() !== '' &&
          line.indexOf('List of devices') === -1 &&
          line.indexOf('adb server') === -1 &&
          line.indexOf('* daemon') === -1 &&
          line.indexOf('offline') === -1) {
        let lineInfo = line.split('\t');
        // state is either "device" or "offline", afaict
        devices.push({udid: lineInfo[0], state: lineInfo[1]});
      }
    }
    log.debug(`${devices.length} device(s) connected`);
    return devices;
  } catch (e) {
    throw new Error(`Error while getting connected devices. Original error: ${e.message}`);
  }
};
Пример #18
0
systemCallMethods.getConnectedDevices = async function () {
  log.debug("Getting connected devices...");
  try {
    let {stdout} = await exec(this.executable.path, ['devices']);
    // expecting adb devices to return output as
    // List of devices attached
    // emulator-5554	device
    let startingIndex = stdout.indexOf("List of devices");
    if (startingIndex === -1) {
      throw new Error(`Unexpected output while trying to get devices. output was: ${stdout}`);
    } else {
      // slicing ouput we care about.
      stdout = stdout.slice(startingIndex);
      let devices = [];
      for (let line of stdout.split("\n")) {
        if (line.trim() !== "" &&
            line.indexOf("List of devices") === -1 &&
            line.indexOf("* daemon") === -1 &&
            line.indexOf("offline") === -1) {
          let lineInfo = line.split("\t");
          // state is either "device" or "offline", afaict
          devices.push({udid: lineInfo[0], state: lineInfo[1]});
        }
      }
      log.debug(`${devices.length} device(s) connected`);
      return devices;
    }
  } catch (e) {
    log.errorAndThrow(`Error while getting connected devices. Original error: ${e.message}`);
  }
};
  async run () {
    const OPEN_TIMEOUT = 3000;
    const STARTUP_TIMEOUT = 60 * 1000;
    const EXTRA_STARTUP_TIME = 2000;

    // start simulator
    let simulatorApp = path.resolve(await getXcodePath(), 'Applications', this.simulatorApp);
    let args = [simulatorApp, '--args', '-CurrentDeviceUDID', this.udid];
    log.info(`Starting simulator with command: open ${args.join(' ')}`);
    let startTime = Date.now();
    await exec('open', args, {timeout: OPEN_TIMEOUT});

    // wait for the simulator to boot
    // waiting for the simulator status to be 'booted' isn't good enough
    // it claims to be booted way before finishing loading
    // let's tail the simulator system log until we see a magic line (this.bootedIndicator)
    let bootedIndicator = await this.getBootedIndicatorString();
    await this.tailLogsUntil(bootedIndicator, STARTUP_TIMEOUT);

    // so sorry, but we should wait another two seconds, just to make sure we've really started
    // we can't look for another magic log line, because they seem to be app-dependent (not system dependent)
    log.debug(`Waiting and extra ${EXTRA_STARTUP_TIME}ms for the simulator to really finish booting`);
    await B.delay(EXTRA_STARTUP_TIME);
    log.debug('Done waiting extra time for simulator');
    log.info(`Simulator booted in ${Date.now() - startTime}ms`);
  }
Пример #20
0
async function unzipFile (zipPath) {
  logger.debug(`Unzipping ${zipPath}`);
  let valid = await testZipArchive(zipPath);
  if (!valid) {
    throw new Error(`Zip archive ${zipPath} did not test valid`);
  }

  if (system.isWindows()) {
    let zip = new AdmZip(zipPath);
    zip.extractAllTo(path.dirname(zipPath), true);
    logger.debug('Unzip successful');
    return;
  }

  let execEnv = _.clone(process.env);
  delete execEnv.UNZIP;
  let execOpts = {cwd: path.dirname(zipPath), env: execEnv};
  try {
    let {stdout} = await exec('unzip', ['-o', zipPath], execOpts);
    return stdout;
  } catch (err) {
    logger.error(`Unzip threw error ${err}`);
    logger.error(`Stderr: ${err.stderr}`);
    logger.error(`Stdout: ${err.stdout}`);
    throw new Error('Archive could not be unzipped, check appium logs.');
  }
}
Пример #21
0
async function testZipArchive (zipPath) {
  logger.debug(`Testing zip archive: ${zipPath}`);
  if (system.isWindows()) {
    if (await fs.exists(zipPath)) {
      logger.debug('Zip archive tested clean');
      return true;
    } else {
      logger.debug('Zip archive not found');
      return false;
    }
  }

  let execEnv = _.clone(process.env);
  delete execEnv.UNZIP;
  let execOpts = {cwd: path.dirname(zipPath), env: execEnv};
  let output;
  try {
    output = await exec('unzip', ['-tq', zipPath], execOpts);
    if (/No errors detected/.exec(output.stdout)) {
      return true;
    }
    logger.error(`Zip file ${zipPath} was not valid`);
    logger.error(`Stderr: ${output.stderr}`);
    logger.error(`Stdout: ${output.stdout}`);
    logger.error('Zip archive did not test successfully, check appium server ' +
                 'logs for output');
    return false;
  } catch (err) {
    logger.error(`Test zip archive threw error ${err}`);
    logger.error(`Stderr: ${err.stderr}`);
    logger.error(`Stdout: ${err.stdout}`);
    throw new Error('Error testing zip archive, are you sure this is a zip file?');
  }
}
Пример #22
0
 let execFunc = async () => {
   try {
     if (!(cmd instanceof Array)) {
       cmd = [cmd];
     }
     let args = this.executable.defaultArgs.concat(cmd);
     log.debug(`Running ${this.executable.path} with args: ` +
               `${JSON.stringify(args)}`);
     let {stdout} = await exec(this.executable.path, args, opts);
     // sometimes ADB prints out stupid stdout warnings that we don't want
     // to include in any of the response data, so let's strip it out
     let linkerWarningRe = /^WARNING: linker.+$/m;
     stdout = stdout.replace(linkerWarningRe, '').trim();
     return stdout;
   } catch (e) {
     let protocolFaultError = new RegExp("protocol fault \\(no status\\)", "i").test(e);
     let deviceNotFoundError = new RegExp("error: device not found", "i").test(e);
     if (protocolFaultError || deviceNotFoundError) {
       log.info(`error sending command, reconnecting device and retrying: ${cmd}`);
       await sleep(1000);
       await this.getDevicesWithRetry();
     }
     throw new Error(`Error executing adbExec. Original error: ${e.message}` +
                       JSON.stringify(e));
   }
 };
Пример #23
0
 async diagnose () {
   const successMess = 'The Authorization DB is set up properly.';
   const errMess = 'The Authorization DB is NOT set up properly.';
   let stdout;
   try {
     stdout = (await exec('security', ['authorizationdb', 'read', 'system.privilege.taskport'])).stdout;
   } catch (err) {
     if (await system.macOsxVersion() === '10.8') {
       let data;
       try {
         data = await fs.readFile('/etc/authorization', 'utf8');
       } catch (err) {
         log.debug(err);
         return nok(errMess);
       }
       let rg =/<key>system.privilege.taskport<\/key>\s*\n\s*<dict>\n\s*<key>allow-root<\/key>\n\s*(<true\/>)/;
       return data && data.match(rg) ? ok(successMess) : nok(errMess);
     } else {
       log.debug(err);
       return nok(errMess);
     }
   }
   return stdout && (stdout.match(/is-developer/) || stdout.match(/allow/)) ?
      ok(successMess) : nok(errMess);
 }
Пример #24
0
async function buildDocs (pathToDocs) {
  const mkdocsTemplate = Handlebars.compile(await fs.readFile(path.resolve(__dirname, '..', 'mkdocs.yml'),  'utf8'));
  const themeDir = path.resolve(__dirname, '..', 'cinder');
  const sitemap = require(path.resolve(pathToDocs, 'toc.js'));

  // Build the MkDocs for each language
  for (let language of LANGUAGES) {
    // generate pages yaml from the sitemap
    let toc = buildDocYML(sitemap[language]);
    toc = toc.trim();

    await fs.writeFile(path.resolve(pathToDocs, 'mkdocs.yml'), mkdocsTemplate({language, themeDir, toc}));
    const pathToBuildDocsTo = path.resolve(__dirname, '..', 'docs', language);
    try {
      await exec('mkdocs', ['build', '--site-dir', pathToBuildDocsTo], {
        cwd: pathToDocs,
      });
    } catch (e) {
      console.log('Could not build', e.message);
      console.log('Reason:', e.stderr);
      throw e;
    }
    await alterHTML(pathToBuildDocsTo);
  }
}
Пример #25
0
  await zip.readEntries(apk, async ({entry, extractEntryTo}) => {
    entry = entry.fileName;
    if (!rsa.test(entry)) {
      return;
    }
    log.debug(`Entry: ${entry}`);
    let entryPath = path.join(this.tmpDir, pkg, 'cert');
    log.debug(`entryPath: ${entryPath}`);
    let entryFile = path.join(entryPath, entry);
    log.debug(`entryFile: ${entryFile}`);
    // ensure /tmp/pkg/cert/ doesn't exist or extract will fail.
    await fs.rimraf(entryPath);
    // META-INF/CERT.RSA
    await extractEntryTo(entryPath);
    log.debug('extracted!');
    // check for match
    log.debug('Printing apk md5.');
    let {stdout} = await exec(keytool, ['-v', '-printcert', '-file', entryFile]);
    entryHash = md5re.exec(stdout);
    entryHash = entryHash ? entryHash[1] : null;
    log.debug(`entryHash MD5: ${entryHash}`);
    log.debug(`keystore MD5: ${keystoreHash}`);
    let matchesKeystore = entryHash && entryHash === keystoreHash;
    log.debug(`Matches keystore? ${matchesKeystore}`);

    // If we have a keystore match, stop iterating
    if (matchesKeystore) {
      foundKeystoreMatch = true;
      return false;
    }
  });
Пример #26
0
  async startCaptureSimulator () {
    if (_.isUndefined(this.sim.udid)) {
      throw new Error(`Log capture requires a sim udid`);
    }

    let tool, args;
    if (this.xcodeVersion.major < 9) {
      const systemLogPath = path.resolve(this.sim.getLogDir(), 'system.log');
      if (!await fs.exists(systemLogPath)) {
        throw new Error(`No logs could be found at ${systemLogPath}`);
      }
      log.debug(`System log path: ${systemLogPath}`);
      tool = 'tail';
      args = ['-f', '-n', '1', systemLogPath];
    } else {
      if (!await this.sim.isRunning()) {
        throw new Error(`iOS Simulator with udid ${this.sim.udid} is not running`);
      }
      tool = 'xcrun';
      args = ['simctl', 'spawn', this.sim.udid, 'log', 'stream', '--style', 'compact'];
    }
    log.debug(`Starting log capture for iOS Simulator with udid '${this.sim.udid}', ` +
              `using '${tool} ${args.join(' ')}'`);
    try {
      // cleanup existing listeners if the previous session has not been terminated properly
      await exec('pkill', ['-xf', [tool, ...args].join(' ')]);
    } catch (ign) {}
    try {
      this.proc = new SubProcess(tool, args);
      await this.finishStartingLogCapture();
    } catch (e) {
      throw new Error(`Simulator log capture failed. Original error: ${e.message}`);
    }
  }
Пример #27
0
async function getFilePathFromJar (fileRegex, jarPath) {
  let {stdout} = await exec('jar', ['tf', jarPath]);
  for (let line of stdout.split('\n')) {
    if (fileRegex.test(line.trim())) {
      return line.trim();
    }
  }
  throw new Error(`Could not find ${fileRegex} in ${jarPath}`);
}
Пример #28
0
async function getGitRev () {
  let cwd = path.resolve(__dirname, "..", "..");
  let rev = null;
  try {
    let {stdout} = await exec("git", ["rev-parse", "HEAD"], {cwd});
    rev = stdout.trim();
  } catch (ign) {}
  return rev;
}
Пример #29
0
async function arch () {
  if (isLinux() || isMac()) {
    let {stdout} = await exec('uname', ['-m']);
    return stdout.trim() === 'i686' ? '32' : '64';
  } else if (isWindows()) {
    let is64 = this.isOSWin64();
    return is64 ? '64' : '32';
  }
}
async function cleanApp (appRoot, sdk) {
  logger.debug(`Cleaning SafariLauncher for ${sdk}`);
  try {
    await exec('xcodebuild', ['-sdk', sdk, 'clean'], {cwd: appRoot});
  } catch (err) {
    logger.error(err);
    throw err;
  }
}