Strict null check experiment service

This commit is contained in:
Matt Bierner 2018-12-17 11:57:40 -08:00
parent a02175c534
commit a1da99e600
2 changed files with 44 additions and 37 deletions

View file

@ -587,6 +587,7 @@
"./vs/workbench/parts/execution/electron-browser/terminal.ts",
"./vs/workbench/parts/execution/electron-browser/terminalService.ts",
"./vs/workbench/parts/execution/test/electron-browser/terminalService.test.ts",
"./vs/workbench/parts/experiments/node/experimentService.ts",
"./vs/workbench/parts/extensions/common/extensionQuery.ts",
"./vs/workbench/parts/extensions/common/extensions.ts",
"./vs/workbench/parts/extensions/common/extensionsFileTemplate.ts",

View file

@ -177,7 +177,7 @@ export class ExperimentService extends Disposable implements IExperimentService
return Promise.resolve(null);
}
return asJson(context).then(result => {
return Array.isArray<IRawExperiment>(result['experiments']) ? result['experiments'] : [];
return result && Array.isArray(result['experiments']) ? result['experiments'] : [];
});
}, () => Promise.resolve(null));
}
@ -296,15 +296,18 @@ export class ExperimentService extends Disposable implements IExperimentService
}
private checkExperimentDependencies(experiment: IRawExperiment): boolean {
if (experiment.condition.experimentsPreviouslyRun) {
const experimentsPreviouslyRun = experiment.condition ? experiment.condition.experimentsPreviouslyRun : undefined;
if (experimentsPreviouslyRun) {
const runExperimentIdsFromStorage: string[] = safeParse(this.storageService.get('currentOrPreviouslyRunExperiments', StorageScope.GLOBAL), []);
let includeCheck = true;
let excludeCheck = true;
if (Array.isArray(experiment.condition.experimentsPreviouslyRun.includes)) {
includeCheck = runExperimentIdsFromStorage.some(x => experiment.condition.experimentsPreviouslyRun.includes.indexOf(x) > -1);
const includes = experimentsPreviouslyRun.includes;
if (Array.isArray(includes)) {
includeCheck = runExperimentIdsFromStorage.some(x => includes.indexOf(x) > -1);
}
if (includeCheck && Array.isArray(experiment.condition.experimentsPreviouslyRun.excludes)) {
excludeCheck = !runExperimentIdsFromStorage.some(x => experiment.condition.experimentsPreviouslyRun.excludes.indexOf(x) > -1);
const excludes = experimentsPreviouslyRun.excludes;
if (includeCheck && Array.isArray(excludes)) {
excludeCheck = !runExperimentIdsFromStorage.some(x => excludes.indexOf(x) > -1);
}
if (!includeCheck || !excludeCheck) {
return false;
@ -322,7 +325,8 @@ export class ExperimentService extends Disposable implements IExperimentService
return Promise.resolve(ExperimentState.NoRun);
}
if (!experiment.condition) {
const condition = experiment.condition;
if (!condition) {
return Promise.resolve(ExperimentState.Run);
}
@ -330,19 +334,19 @@ export class ExperimentService extends Disposable implements IExperimentService
return Promise.resolve(ExperimentState.NoRun);
}
if (this.environmentService.appQuality === 'stable' && experiment.condition.insidersOnly === true) {
if (this.environmentService.appQuality === 'stable' && condition.insidersOnly === true) {
return Promise.resolve(ExperimentState.NoRun);
}
const isNewUser = !this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL);
if ((experiment.condition.newUser === true && !isNewUser)
|| (experiment.condition.newUser === false && isNewUser)) {
if ((condition.newUser === true && !isNewUser)
|| (condition.newUser === false && isNewUser)) {
return Promise.resolve(ExperimentState.NoRun);
}
if (typeof experiment.condition.displayLanguage === 'string') {
let localeToCheck = experiment.condition.displayLanguage.toLowerCase();
let displayLanguage = language.toLowerCase();
if (typeof condition.displayLanguage === 'string') {
let localeToCheck = condition.displayLanguage.toLowerCase();
let displayLanguage = language!.toLowerCase();
if (localeToCheck !== displayLanguage) {
const a = displayLanguage.indexOf('-');
@ -359,22 +363,23 @@ export class ExperimentService extends Disposable implements IExperimentService
}
}
if (!experiment.condition.userProbability) {
experiment.condition.userProbability = 1;
if (!condition.userProbability) {
condition.userProbability = 1;
}
let extensionsCheckPromise = Promise.resolve(true);
if (experiment.condition.installedExtensions) {
const installedExtensions = condition.installedExtensions;
if (installedExtensions) {
extensionsCheckPromise = this.extensionManagementService.getInstalled(LocalExtensionType.User).then(locals => {
let includesCheck = true;
let excludesCheck = true;
const localExtensions = locals.map(local => `${local.manifest.publisher.toLowerCase()}.${local.manifest.name.toLowerCase()}`);
if (Array.isArray(experiment.condition.installedExtensions.includes) && experiment.condition.installedExtensions.includes.length) {
const extensionIncludes = experiment.condition.installedExtensions.includes.map(e => e.toLowerCase());
if (Array.isArray(installedExtensions.includes) && installedExtensions.includes.length) {
const extensionIncludes = installedExtensions.includes.map(e => e.toLowerCase());
includesCheck = localExtensions.some(e => extensionIncludes.indexOf(e) > -1);
}
if (Array.isArray(experiment.condition.installedExtensions.excludes) && experiment.condition.installedExtensions.excludes.length) {
const extensionExcludes = experiment.condition.installedExtensions.excludes.map(e => e.toLowerCase());
if (Array.isArray(installedExtensions.excludes) && installedExtensions.excludes.length) {
const extensionExcludes = installedExtensions.excludes.map(e => e.toLowerCase());
excludesCheck = !localExtensions.some(e => extensionExcludes.indexOf(e) > -1);
}
return includesCheck && excludesCheck;
@ -385,13 +390,14 @@ export class ExperimentService extends Disposable implements IExperimentService
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
return extensionsCheckPromise.then(success => {
if (!success || !experiment.condition.fileEdits || typeof experiment.condition.fileEdits.minEditCount !== 'number') {
const runExperiment = success && Math.random() < experiment.condition.userProbability;
const fileEdits = condition.fileEdits;
if (!success || !fileEdits || typeof fileEdits.minEditCount !== 'number') {
const runExperiment = success && typeof condition.userProbability === 'number' && Math.random() < condition.userProbability;
return runExperiment ? ExperimentState.Run : ExperimentState.NoRun;
}
experimentState.editCount = experimentState.editCount || 0;
if (experimentState.editCount >= experiment.condition.fileEdits.minEditCount) {
if (experimentState.editCount >= fileEdits.minEditCount) {
return ExperimentState.Run;
}
@ -406,20 +412,21 @@ export class ExperimentService extends Disposable implements IExperimentService
if (event.kind !== StateChange.SAVED
|| latestExperimentState.state !== ExperimentState.Evaluating
|| date === latestExperimentState.lastEditedDate
|| latestExperimentState.editCount >= experiment.condition.fileEdits.minEditCount) {
|| (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount)
) {
return;
}
let filePathCheck = true;
let workspaceCheck = true;
if (typeof experiment.condition.fileEdits.filePathPattern === 'string') {
filePathCheck = match(experiment.condition.fileEdits.filePathPattern, event.resource.fsPath);
if (typeof fileEdits.filePathPattern === 'string') {
filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath);
}
if (Array.isArray(experiment.condition.fileEdits.workspaceIncludes) && experiment.condition.fileEdits.workspaceIncludes.length) {
workspaceCheck = !!WorkspaceStats.TAGS && experiment.condition.fileEdits.workspaceIncludes.some(x => !!WorkspaceStats.TAGS[x]);
if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) {
workspaceCheck = !!WorkspaceStats.TAGS && fileEdits.workspaceIncludes.some(x => !!WorkspaceStats.TAGS[x]);
}
if (workspaceCheck && Array.isArray(experiment.condition.fileEdits.workspaceExcludes) && experiment.condition.fileEdits.workspaceExcludes.length) {
workspaceCheck = !!WorkspaceStats.TAGS && !experiment.condition.fileEdits.workspaceExcludes.some(x => !!WorkspaceStats.TAGS[x]);
if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) {
workspaceCheck = !!WorkspaceStats.TAGS && !fileEdits.workspaceExcludes.some(x => !!WorkspaceStats.TAGS[x]);
}
if (filePathCheck && workspaceCheck) {
latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1;
@ -427,10 +434,10 @@ export class ExperimentService extends Disposable implements IExperimentService
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
}
});
if (latestExperimentState.editCount >= experiment.condition.fileEdits.minEditCount) {
processedExperiment.state = latestExperimentState.state = (Math.random() < experiment.condition.userProbability && this.checkExperimentDependencies(experiment)) ? ExperimentState.Run : ExperimentState.NoRun;
if (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount) {
processedExperiment.state = latestExperimentState.state = (typeof condition.userProbability === 'number' && Math.random() < condition.userProbability && this.checkExperimentDependencies(experiment)) ? ExperimentState.Run : ExperimentState.NoRun;
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
if (latestExperimentState.state === ExperimentState.Run && ExperimentActionType[experiment.action.type] === ExperimentActionType.Prompt) {
if (latestExperimentState.state === ExperimentState.Run && experiment.action && ExperimentActionType[experiment.action.type] === ExperimentActionType.Prompt) {
this.fireRunExperiment(processedExperiment);
}
}
@ -446,11 +453,10 @@ export class ExperimentService extends Disposable implements IExperimentService
}
function safeParse(text: string, defaultObject: any) {
function safeParse(text: string | undefined, defaultObject: any) {
try {
return JSON.parse(text) || defaultObject;
}
catch (e) {
return text ? JSON.parse(text) || defaultObject : defaultObject;
} catch (e) {
return defaultObject;
}
}