Skip to content

Commit

Permalink
Reduce number of created temp dirs for profiles (closes DevExpress#2735)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreyBelym committed Aug 16, 2018
1 parent 26aeffd commit a18e1d6
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 30 deletions.
10 changes: 4 additions & 6 deletions src/browser/provider/built-in/chrome/create-temp-profile.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import path from 'path';
import tmp from 'tmp';
import TempDirectory from '../../../../utils/temp-directory';
import { writeFile, ensureDir } from '../../../../utils/promisified-functions';


export default async function (proxyHostName) {
tmp.setGracefulCleanup();

const tempDir = tmp.dirSync({ unsafeCleanup: true });
const profileDirName = path.join(tempDir.name, 'Default');
const tempDir = await TempDirectory.createDirectory('chrome-profile');
const profileDirName = path.join(tempDir.path, 'Default');

await ensureDir(profileDirName);

Expand Down Expand Up @@ -39,7 +37,7 @@ export default async function (proxyHostName) {
};

await writeFile(path.join(profileDirName, 'Preferences'), JSON.stringify(preferences));
await writeFile(path.join(tempDir.name, 'First Run'), '');
await writeFile(path.join(tempDir.path, 'First Run'), '');

return tempDir;
}
3 changes: 3 additions & 0 deletions src/browser/provider/built-in/chrome/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export default {
if (OS.mac || runtimeInfo.config.headless)
await stopLocalChrome(runtimeInfo);

if (runtimeInfo.tempProfileDir)
runtimeInfo.tempProfileDir.dispose();

delete this.openedBrowsers[browserId];
},

Expand Down
2 changes: 1 addition & 1 deletion src/browser/provider/built-in/chrome/local-chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function buildChromeArgs (config, cdpPort, platformArgs, profileDir) {
return []
.concat(
cdpPort ? [`--remote-debugging-port=${cdpPort}`] : [],
!config.userProfile ? [`--user-data-dir=${profileDir.name}`] : [],
!config.userProfile ? [`--user-data-dir=${profileDir.path}`] : [],
config.headless ? ['--headless'] : [],
config.userArgs ? [config.userArgs] : [],
platformArgs ? [platformArgs] : []
Expand Down
18 changes: 1 addition & 17 deletions src/browser/provider/built-in/chrome/runtime-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,9 @@ import getConfig from './config';
import createTempProfile from './create-temp-profile';


var commonTempProfile = null;

async function getTempProfile (proxyHostName, config) {

var tempProfile = commonTempProfile;
var shouldUseCommonProfile = !config.headless && !config.emulation;

if (!shouldUseCommonProfile || !commonTempProfile)
tempProfile = await createTempProfile(proxyHostName);

if (shouldUseCommonProfile && !commonTempProfile)
commonTempProfile = tempProfile;

return tempProfile;
}

export default async function (proxyHostName, configString) {
var config = getConfig(configString);
var tempProfileDir = !config.userProfile ? await getTempProfile(proxyHostName, config) : null;
var tempProfileDir = !config.userProfile ? await createTempProfile(proxyHostName, config) : null;
var cdpPort = config.cdpPort || (!config.userProfile ? await getFreePort() : null);

return { config, cdpPort, tempProfileDir };
Expand Down
8 changes: 3 additions & 5 deletions src/browser/provider/built-in/firefox/create-temp-profile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path';
import tmp from 'tmp';
import TempDirectory from '../../../../utils/temp-directory';
import { writeFile } from '../../../../utils/promisified-functions';


Expand Down Expand Up @@ -54,11 +54,9 @@ async function generatePreferences (profileDir, { marionettePort, config }) {
}

export default async function (runtimeInfo) {
tmp.setGracefulCleanup();
const tmpDir = await TempDirectory.createDirectory('firefox-profile');

const tmpDir = tmp.dirSync({ unsafeCleanup: true });

await generatePreferences(tmpDir.name, runtimeInfo);
await generatePreferences(tmpDir.path, runtimeInfo);

return tmpDir;
}
3 changes: 3 additions & 0 deletions src/browser/provider/built-in/firefox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export default {
if (OS.mac && !config.headless)
await stopLocalFirefox(runtimeInfo);

if (runtimeInfo.tempProfileDir)
runtimeInfo.tempProfileDir.dispose();

delete this.openedBrowsers[browserId];
},

Expand Down
2 changes: 1 addition & 1 deletion src/browser/provider/built-in/firefox/local-firefox.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function buildFirefoxArgs (config, platformArgs, { marionettePort, tempProfileDi
return []
.concat(
marionettePort ? ['-marionette'] : [],
!config.userProfile ? ['-no-remote', '-new-instance', `-profile "${tempProfileDir.name}"`] : [],
!config.userProfile ? ['-no-remote', '-new-instance', `-profile "${tempProfileDir.path}"`] : [],
config.headless ? ['-headless'] : [],
config.userArgs ? [config.userArgs] : [],
platformArgs ? [platformArgs] : []
Expand Down
1 change: 1 addition & 0 deletions src/utils/promisified-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import promisify from './promisify';


export const ensureDir = promisify(mkdirp);
export const readDir = promisify(fs.readdir);
export const stat = promisify(fs.stat);
export const writeFile = promisify(fs.writeFile);
export const readFile = promisify(fs.readFile);
Expand Down
131 changes: 131 additions & 0 deletions src/utils/temp-directory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import debug from 'debug';
import fs from 'fs';
import os from 'os';
import path from 'path';
import setupExitHook from 'async-exit-hook';
import tmp from 'tmp';
import { ensureDir, readDir } from '../utils/promisified-functions';


const TESTCAFE_TMP_DIRS_ROOT = path.join(os.tmpdir(), 'testcafe-tmp');
const LOCKFILE_NAME = '.testcafe-lockfile';

const USED_TEMP_DIRS = {};

const DEBUG_LOGGER = debug('testcafe:utils:temp-directory');

class LockFile {
constructor (dirPath) {
this.path = path.join(dirPath, LOCKFILE_NAME);
}

init () {
try {
const fd = fs.openSync(this.path, 'wx');

fs.closeSync(fd);

return true;
}
catch (e) {
DEBUG_LOGGER('Failed to init lockfile ' + this.path);
DEBUG_LOGGER(e);

return false;
}
}

dispose () {
try {
fs.unlinkSync(this.path);
}
catch (e) {
DEBUG_LOGGER('Failed to dispose lockfile ' + this.path);
DEBUG_LOGGER(e);
}
}
}

export default class TempDirectory {
constructor (namePrefix) {
this.namePrefix = namePrefix;

this.path = '';
this.lockFile = null;
}

async _getTmpDirsList () {
const tmpDirNames = await readDir(TESTCAFE_TMP_DIRS_ROOT);

return tmpDirNames
.filter(tmpDir => !USED_TEMP_DIRS[tmpDir])
.filter(tmpDir => path.basename(tmpDir).startsWith(this.namePrefix));
}

async _findFreeTmpDir (tmpDirNames) {
for (const tmpDirName of tmpDirNames) {
const tmpDirPath = path.join(TESTCAFE_TMP_DIRS_ROOT, tmpDirName);

const lockFile = new LockFile(tmpDirPath);

if (lockFile.init()) {
this.path = tmpDirPath;
this.lockFile = lockFile;

return true;
}
}

return false;
}

async _createNewTmpDir () {
this.path = tmp.tmpNameSync({ dir: TESTCAFE_TMP_DIRS_ROOT, prefix: this.namePrefix + '-' });

await ensureDir(this.path);

this.lockFile = new LockFile(this.path);

this.lockFile.init();
}

static async createDirectory (prefix) {
const tmpDir = new TempDirectory(prefix);

await tmpDir.init();

return tmpDir;
}

static disposeDirectories () {
Object.values(USED_TEMP_DIRS).forEach(tmpDir => tmpDir.dispose());
}

async init () {
await ensureDir(TESTCAFE_TMP_DIRS_ROOT);

const tmpDirNames = await this._getTmpDirsList(this.namePrefix);

DEBUG_LOGGER('Found temp directories:', tmpDirNames);

const existingTmpDirFound = await this._findFreeTmpDir(tmpDirNames);

if (!existingTmpDirFound)
await this._createNewTmpDir();

DEBUG_LOGGER('Temp directory path: ', this.path);

USED_TEMP_DIRS[this.path] = this;
}

dispose () {
if (!USED_TEMP_DIRS[this.path])
return;

this.lockFile.dispose();

delete USED_TEMP_DIRS[this.path];
}
}

setupExitHook(TempDirectory.disposeDirectories);

0 comments on commit a18e1d6

Please sign in to comment.