Skip to content

Commit 482ed16

Browse files
committed
[extension-manager] fixed tests
Signed-off-by: Anton Kosiakov <anton.kosyakov@typefox.io>
1 parent 4cc6029 commit 482ed16

14 files changed

+4491
-113
lines changed

generator-theia/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"dependencies": {
2727
"@types/fs-extra": "^4.0.2",
28-
"@types/request": "^2.0.0",
28+
"@types/request": "^2.0.3",
2929
"@types/semver": "^5.3.32",
3030
"@types/yargs": "^8.0.2",
3131
"@types/yeoman-generator": "^1.0.2",

package.json

+5-7
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
"yo": "^2.0.0"
99
},
1010
"scripts": {
11-
"prepare": "yarn run prepare:generator && yarn run prepare:packages",
12-
"prepare:generator": "yarn run bootstrap:generator && yarn run build:generator && yarn run link:generator",
13-
"bootstrap:generator": "lerna bootstrap --scope generator-theia -- --no-optional",
14-
"build:generator": "lerna run prepare --scope generator-theia --stream",
15-
"link:generator": "lerna exec --scope generator-theia --stream -- yarn link && yarn link generator-theia",
11+
"prepare": "yarn run generator:bootstrap && yarn run generator:build && yarn run prepare:packages",
12+
"generator:bootstrap": "node scripts/lerna bootstrap --scope generator-theia --hoist -- --no-optional && node scripts/link-generator",
13+
"generator:build": "node scripts/lerna run prepare --scope generator-theia --stream",
1614
"prepare:packages": "yarn run bootstrap && yarn run clean && yarn run clean:rebuild && yarn run build",
17-
"bootstrap": "node scripts/generate && node scripts/lerna bootstrap --scope \"@theia/*\" --hoist -- --no-optional",
18-
"refresh": "yarn run build:generator && node scripts/lerna clean --scope \"@theia/*\" --yes && yarn run bootstrap",
15+
"bootstrap": "node scripts/generate && node scripts/lerna bootstrap --hoist -- --no-optional",
16+
"refresh": "yarn run generator:build && node scripts/lerna clean --scope \"@theia/*\" --yes && yarn run bootstrap",
1917
"clean": "node scripts/lerna run clean --scope \"@theia/*\" --parallel",
2018
"build": "node scripts/lerna run build --scope \"@theia/*\" --stream",
2119
"docs": "node scripts/lerna run docs --scope \"@theia/*\" --stream",

packages/core/extension.package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"@types/bunyan": "^1.8.0",
1111
"@types/express": "^4.0.36",
1212
"@types/ws": "^3.0.2",
13-
"@types/yargs": "^8.0.1",
13+
"@types/yargs": "^8.0.2",
1414
"body-parser": "^1.17.2",
1515
"bunyan": "^1.8.10",
1616
"electron": "^1.6.11",

packages/core/src/common/disposable.ts

+18
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,21 @@ export class DisposableCollection implements Disposable {
6969
}
7070

7171
}
72+
73+
const disposedMessage = 'Disposed';
74+
75+
export function disposed(): Error {
76+
return new Error(disposedMessage);
77+
}
78+
79+
export function isDisposed(err: Error | undefined): boolean {
80+
return !!err && err.message === disposedMessage;
81+
}
82+
83+
export function checkDisposed(toDispose?: {
84+
readonly disposed: boolean
85+
}): void {
86+
if (!!toDispose && toDispose.disposed) {
87+
throw disposed();
88+
}
89+
}

packages/extension-manager/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
testproject_temp
1+
test-resources/*_temp

packages/extension-manager/extension.package.json

+3-5
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
"dependencies": {
66
"@theia/core": "^0.1.1",
77
"@theia/filesystem": "^0.1.1",
8-
"@types/request": "^2.0.0",
9-
"generator-theia": "^0.1.1",
10-
"request": "^2.81.0",
11-
"showdown": "^1.7.2",
8+
"@types/sanitize-html": "^1.13.31",
129
"@types/showdown": "^1.4.32",
10+
"generator-theia": "^0.1.1",
1311
"sanitize-html": "^1.14.1",
14-
"@types/sanitize-html": "^1.13.31"
12+
"showdown": "^1.7.2"
1513
},
1614
"theiaExtensions": [
1715
{

packages/extension-manager/src/node/app-project-installer.spec.ts

+20-10
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
*/
77

88
import * as path from 'path';
9+
import * as temp from 'temp';
910
import * as fs from 'fs-extra';
1011
import * as assert from 'assert';
1112
import { DidStopInstallationParam } from "../common/extension-protocol";
1213
import extensionNodeTestContainer from './test/extension-node-test-container';
1314
import { AppProject } from './app-project';
1415

16+
process.on('unhandledRejection', (reason, promise) => { throw reason; });
17+
1518
let appProject: AppProject;
16-
const appProjectPath = path.resolve(__dirname, '..', '..', 'test-resources', 'testproject_temp');
19+
let appProjectPath: string;
1720

1821
export async function assertInstallation(expectation: {
1922
added?: string[],
@@ -61,7 +64,10 @@ describe("AppProjectInstaller", function () {
6164

6265
beforeEach(function () {
6366
this.timeout(50000);
64-
fs.removeSync(appProjectPath);
67+
appProjectPath = temp.mkdirSync({
68+
dir: path.resolve(__dirname, '..', '..', 'test-resources'),
69+
suffix: '_temp'
70+
});
6571
appProject = extensionNodeTestContainer({
6672
path: appProjectPath,
6773
target: 'browser',
@@ -70,16 +76,16 @@ describe("AppProjectInstaller", function () {
7076
}).get(AppProject);
7177
});
7278

73-
afterEach(function () {
79+
afterEach(async function () {
7480
this.timeout(50000);
7581
appProject.dispose();
82+
await appProject.onDispose;
7683
fs.removeSync(appProjectPath);
7784
});
7885

7986
it("install local", async function () {
8087
this.timeout(600000);
81-
82-
fs.writeJSON(path.resolve(appProjectPath, '.yo-rc.json'), {
88+
fs.writeJsonSync(path.resolve(appProjectPath, '.yo-rc.json'), {
8389
"generator-theia": {
8490
"localDependencies": {
8591
"@theia/core": "../../../core",
@@ -88,7 +94,7 @@ describe("AppProjectInstaller", function () {
8894
"node_modulesPath": "../../../../node_modules"
8995
}
9096
});
91-
fs.writeJSON(path.resolve(appProjectPath, 'theia.package.json'), {
97+
fs.writeJsonSync(path.resolve(appProjectPath, 'theia.package.json'), {
9298
"private": true,
9399
"dependencies": {
94100
"@theia/core": "0.1.1",
@@ -99,7 +105,7 @@ describe("AppProjectInstaller", function () {
99105
linked: ['@theia/core', '@theia/filesystem']
100106
});
101107

102-
fs.writeJSON(path.resolve(appProjectPath, 'theia.package.json'), {
108+
fs.writeJsonSync(path.resolve(appProjectPath, 'theia.package.json'), {
103109
"private": true,
104110
"dependencies": {
105111
"@theia/core": "0.1.1"
@@ -114,8 +120,12 @@ describe("AppProjectInstaller", function () {
114120
it("install", async function () {
115121
this.timeout(1800000);
116122

117-
fs.writeJSON(path.resolve(appProjectPath, '.yo-rc.json'), {});
118-
fs.writeJSON(path.resolve(appProjectPath, 'theia.package.json'), {
123+
fs.writeJsonSync(path.resolve(appProjectPath, '.yo-rc.json'), {
124+
"generator-theia": {
125+
"node_modulesPath": "./node_modules"
126+
}
127+
});
128+
fs.writeJsonSync(path.resolve(appProjectPath, 'theia.package.json'), {
119129
"private": true,
120130
"dependencies": {
121131
"@theia/core": "0.1.1",
@@ -127,7 +137,7 @@ describe("AppProjectInstaller", function () {
127137
added: ['@theia/core', '@theia/filesystem']
128138
});
129139

130-
fs.writeJSON(path.resolve(appProjectPath, 'theia.package.json'), {
140+
fs.writeJsonSync(path.resolve(appProjectPath, 'theia.package.json'), {
131141
"private": true,
132142
"dependencies": {
133143
"@theia/core": "0.1.1"

packages/extension-manager/src/node/app-project.ts

+32-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { TheiaBrowserGenerator } from 'generator-theia/generators/browser/browse
1212
import { TheiaElectronGenerator } from 'generator-theia/generators/electron/electron-generator';
1313
import {
1414
MaybePromise, Disposable, DisposableCollection, Event, Emitter, ILogger,
15-
CancellationTokenSource, CancellationToken, isCancelled
15+
CancellationTokenSource, CancellationToken, isCancelled, isDisposed, checkDisposed
1616
} from "@theia/core";
1717
import { FileUri, ServerProcess } from "@theia/core/lib/node";
1818

@@ -65,11 +65,19 @@ export class AppProject implements Disposable {
6565
});
6666
this.toDispose.push(this.onWillInstallEmitter);
6767
this.toDispose.push(this.onDidInstallEmitter);
68+
this.toDispose.push(Disposable.create(() => this.installationTokenSource.cancel()));
6869
}
6970

7071
dispose(): void {
7172
this.toDispose.dispose();
7273
}
74+
get onDispose(): Promise<void> {
75+
if (this.toDispose.disposed) {
76+
return this.installed;
77+
}
78+
const disposed = new Promise<void>(resolve => this.toDispose.onDispose(resolve));
79+
return Promise.all([disposed, this.installed]).then(() => { });
80+
}
7381

7482
get onDidChangePackage(): Event<void> {
7583
return this.onChangePackageEmitter.event;
@@ -92,9 +100,10 @@ export class AppProject implements Disposable {
92100
}
93101

94102
load(): Promise<ProjectModel> {
95-
return this.generator.then(generator => generator.model);
103+
return this.getGenerator().then(generator => generator.model);
96104
}
97-
protected get generator(): Promise<CommonAppGenerator> {
105+
protected async getGenerator(): Promise<CommonAppGenerator> {
106+
await this.ensureProjectConfigExists();
98107
const generatorConstructor = this.options.target === 'browser' ? TheiaBrowserGenerator : TheiaElectronGenerator;
99108
const generator = new generatorConstructor([], {
100109
env: {
@@ -106,6 +115,17 @@ export class AppProject implements Disposable {
106115
generator.initializing();
107116
return generator.configuring().then(() => generator);
108117
}
118+
/**
119+
* If the project config does not exist yeoman will pick the parent directory with the config as a project directory.
120+
*/
121+
protected async ensureProjectConfigExists(): Promise<void> {
122+
const projectConfig = FileUri.create(this.options.path).resolve('.yo-rc.json').toString();
123+
try {
124+
await this.fileSystem.createFile(projectConfig, {
125+
content: '{}'
126+
});
127+
} catch { /* exist */ }
128+
}
109129

110130
async save(model: MaybePromise<ProjectModel>): Promise<void> {
111131
const resolved = await model;
@@ -148,9 +168,9 @@ export class AppProject implements Disposable {
148168
protected installed: Promise<void> = Promise.resolve();
149169
protected installationTokenSource = new CancellationTokenSource();
150170
async scheduleInstall(params: InstallParams = { force: false }): Promise<void> {
151-
if (this.installationTokenSource) {
152-
this.installationTokenSource.cancel();
153-
}
171+
checkDisposed(this.toDispose);
172+
this.installationTokenSource.cancel();
173+
154174
this.installationTokenSource = new CancellationTokenSource();
155175
const token = this.installationTokenSource.token;
156176
this.installed = this.installed.then(() => this.install(params, token));
@@ -169,6 +189,9 @@ export class AppProject implements Disposable {
169189
this.fireDidInstall();
170190
this.serverProcess.restart();
171191
} catch (err) {
192+
if (isDisposed(err)) {
193+
throw err;
194+
}
172195
if (isCancelled(err)) {
173196
this.logger.info('The app installation is cancelled');
174197
return;
@@ -184,7 +207,9 @@ export class AppProject implements Disposable {
184207
}
185208

186209
protected async installer(token?: CancellationToken): Promise<AppProjectInstaller> {
187-
const generator = await this.generator;
210+
checkDisposed(this.toDispose);
211+
212+
const generator = await this.getGenerator();
188213
return this.installerFactory({
189214
generator,
190215
projectPath: this.options.path,

packages/extension-manager/src/node/node-extension-server.spec.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import * as path from 'path';
99
import * as fs from 'fs-extra';
1010
import * as assert from 'assert';
11-
import { ExtensionChange, ExtensionClient, ExtensionServer } from '../common/extension-protocol';
11+
import { ExtensionClient, ExtensionServer } from '../common/extension-protocol';
1212
import extensionNodeTestContainer from './test/extension-node-test-container';
1313
import { AppProject } from './app-project';
1414

@@ -20,9 +20,7 @@ const appProjectPath = path.resolve(__dirname, '..', '..', 'test-resources', 'te
2020
export function waitForDidChange(): Promise<void> {
2121
return new Promise(resolve => {
2222
server.setClient(<ExtensionClient>{
23-
onDidChange: function (extensionChange: ExtensionChange) {
24-
resolve();
25-
}
23+
onDidChange: extensionChange => resolve()
2624
});
2725
});
2826
}
@@ -41,13 +39,13 @@ describe("NodeExtensionServer", function () {
4139
});
4240
server = container.get(ExtensionServer);
4341
appProject = container.get(AppProject);
44-
return waitForDidChange();
4542
});
4643

47-
afterEach(function () {
44+
afterEach(async function () {
4845
this.timeout(50000);
4946
server.dispose();
5047
appProject.dispose();
48+
await appProject.onDispose;
5149
fs.removeSync(appProjectPath);
5250
});
5351

0 commit comments

Comments
 (0)