Skip to content

Commit

Permalink
The client implementation for Chromedriver storage (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
mykola-mokhnach authored Jul 1, 2019
2 parents 005f0b5 + 563789f commit 36ea901
Show file tree
Hide file tree
Showing 6 changed files with 806 additions and 42 deletions.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { default as chromedriver } from './lib/chromedriver';
import ChromedriverStorageClient from './lib/storage-client';

export { ChromedriverStorageClient };
export default chromedriver;
141 changes: 101 additions & 40 deletions lib/chromedriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import semver from 'semver';
import _ from 'lodash';
import path from 'path';
import compareVersions from 'compare-versions';
import ChromedriverStorageClient from './storage-client';


const log = logger.getLogger('Chromedriver');
Expand Down Expand Up @@ -110,6 +111,7 @@ class Chromedriver extends events.EventEmitter {
verbose,
logPath,
disableBuildCheck,
isAutodownloadEnabled = false,
} = args;

this.proxyHost = host;
Expand All @@ -128,6 +130,9 @@ class Chromedriver extends events.EventEmitter {
this.verbose = verbose;
this.logPath = logPath;
this.disableBuildCheck = !!disableBuildCheck;
this.storageClient = isAutodownloadEnabled
? new ChromedriverStorageClient({ chromedriverDir: this.executableDir })
: null;
}

async getMapping () {
Expand Down Expand Up @@ -256,53 +261,109 @@ class Chromedriver extends events.EventEmitter {
}

const mapping = await this.getMapping();
const cds = await this.getChromedrivers(mapping);
let didStorageSync = false;
const syncChromedrivers = async (chromeVersion) => {
didStorageSync = true;
const retrievedMapping = await this.storageClient.retrieveMapping();
log.debug('Got chromedrivers mapping from the storage: ' +
JSON.stringify(retrievedMapping, null, 2));
const driverKeys = await this.storageClient.syncDrivers({
minBrowserVersion: chromeVersion.major,
});
if (_.isEmpty(driverKeys)) {
return false;
}
const synchronizedDriversMapping = driverKeys.reduce((acc, x) => {
const {version, minBrowserVersion} = retrievedMapping[x];
acc[version] = minBrowserVersion;
return acc;
}, {});
Object.assign(mapping, synchronizedDriversMapping);
let shouldUpdateGlobalMapping = true;
if (await fs.exists(this.mappingPath)) {
try {
await fs.writeFile(this.mappingPath, JSON.stringify(mapping, null, 2), 'utf8');
shouldUpdateGlobalMapping = false;
} catch (e) {
log.warn(`Cannot store the updated chromedrivers mapping into '${this.mappingPath}'. ` +
`This may reduce the performance of further executions. Original error: ${e.message}`);
}
}
if (shouldUpdateGlobalMapping) {
Object.assign(CHROMEDRIVER_CHROME_MAPPING, mapping);
}
return true;
};

if (this.disableBuildCheck) {
const cd = cds[0];
log.warn(`Chrome build check disabled. Using most recent Chromedriver version (${cd.version}, at '${cd.executable}')`);
log.warn(`If this is wrong, set 'chromedriverDisableBuildCheck' capability to 'false'`);
return cd.executable;
}
do {
const cds = await this.getChromedrivers(mapping);

const chromeVersion = await this.getChromeVersion();
if (this.disableBuildCheck) {
const {version, executable} = cds[0];
log.warn(`Chrome build check disabled. Using most recent Chromedriver version (${version}, at '${executable}')`);
log.warn(`If this is wrong, set 'chromedriverDisableBuildCheck' capability to 'false'`);
return executable;
}

if (!chromeVersion) {
// unable to get the chrome version
let cd = cds[0];
log.warn(`Unable to discover Chrome version. Using Chromedriver ${cd.version} at '${cd.executable}'`);
return cd.executable;
}
const chromeVersion = await this.getChromeVersion();
if (!chromeVersion) {
// unable to get the chrome version
const {version, executable} = cds[0];
log.warn(`Unable to discover Chrome version. Using Chromedriver ${version} at '${executable}'`);
return executable;
}

log.debug(`Found Chrome bundle '${this.bundleId}' version '${chromeVersion}'`);

if (semver.gt(chromeVersion, _.values(mapping)[0]) &&
!_.isUndefined(cds[0]) && _.isUndefined(cds[0].minChromeVersion)) {
// this is a chrome above the latest version we know about,
// and we have a chromedriver that is beyond what we know,
// so use the most recent chromedriver that we found
let cd = cds[0];
log.warn(`No known Chromedriver available to automate Chrome version '${chromeVersion}'.\n` +
`Using Chromedriver version '${cd.version}', which has not been tested with Appium.`);
return cd.executable;
}
log.debug(`Found Chrome bundle '${this.bundleId}' version '${chromeVersion}'`);

const workingCds = cds.filter((cd) => {
return !_.isUndefined(cd.minChromeVersion) && semver.gte(chromeVersion, cd.minChromeVersion);
});
const autodownloadMsg = this.storageClient && didStorageSync
? ''
: '. You could also try to enable automated chromedrivers download server feature';
if (semver.gt(chromeVersion, _.values(mapping)[0]) && cds[0] && !cds[0].minChromeVersion) {
if (this.storageClient && !didStorageSync) {
try {
if (await syncChromedrivers(chromeVersion)) {
continue;
}
} catch (e) {
log.warn(e.stack);
}
}
// this is a chrome above the latest version we know about,
// and we have a chromedriver that is beyond what we know,
// so use the most recent chromedriver that we found
const {version, executable} = cds[0];
log.warn(`No known Chromedriver available to automate Chrome version '${chromeVersion}'.\n` +
`Using Chromedriver version '${version}', which has not been tested with Appium` +
autodownloadMsg);
return executable;
}

if (_.isEmpty(workingCds)) {
log.errorAndThrow(`No Chromedriver found that can automate Chrome '${chromeVersion}'. ` +
`See ${CHROMEDRIVER_TUTORIAL} for more details.`);
}
const workingCds = cds.filter((cd) => {
const versionObj = semver.coerce(cd.minChromeVersion);
return versionObj && chromeVersion.major === versionObj.major;
});
if (_.isEmpty(workingCds)) {
if (this.storageClient && !didStorageSync) {
try {
if (await syncChromedrivers(chromeVersion)) {
continue;
}
} catch (e) {
log.warn(e.stack);
}
}
log.errorAndThrow(`No Chromedriver found that can automate Chrome '${chromeVersion}'. ` +
`See ${CHROMEDRIVER_TUTORIAL} for more details` + autodownloadMsg);
}

const binPath = workingCds[0].executable;
log.debug(`Found ${workingCds.length} Chromedriver executable${workingCds.length === 1 ? '' : 's'} ` +
`capable of automating Chrome '${chromeVersion}'.\n` +
`Choosing the most recent, '${binPath}'.`);
log.debug('If a specific version is required, specify it with the `chromedriverExecutable`' +
'desired capability.');
return binPath;
const binPath = workingCds[0].executable;
log.debug(`Found ${workingCds.length} Chromedriver executable${workingCds.length === 1 ? '' : 's'} ` +
`capable of automating Chrome '${chromeVersion}'.\nChoosing the most recent, '${binPath}'.`);
log.debug('If a specific version is required, specify it with the `chromedriverExecutable`' +
'desired capability.');
return binPath;
// eslint-disable-next-line no-constant-condition
} while (true);
}

async initChromedriverPath () {
Expand Down
Loading

0 comments on commit 36ea901

Please sign in to comment.