Skip to content

Commit 3e3dffb

Browse files
filipesilvaclydin
authored andcommitted
fix(@angular-devkit/architect): unsubscribe on timeout in runTargetSpec
This way cleanup logic runs on timeout. It also simplifies timeout definition for runTargetSpec and Jasmine.
1 parent b9a8fd1 commit 3e3dffb

39 files changed

+195
-179
lines changed

packages/angular_devkit/architect/testing/run-target-spec.ts

+26-4
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,47 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { Path, experimental, logging, normalize } from '@angular-devkit/core';
10-
import { Observable } from 'rxjs';
11-
import { concatMap } from 'rxjs/operators';
9+
import { experimental, logging, normalize } from '@angular-devkit/core';
10+
import { Observable, merge, throwError, timer } from 'rxjs';
11+
import { concatMap, concatMapTo, finalize, takeUntil } from 'rxjs/operators';
1212
import { Architect, BuildEvent, TargetSpecifier } from '../src';
1313
import { TestProjectHost } from './test-project-host';
1414

15+
export const DefaultTimeout = 45000;
1516

1617
export function runTargetSpec(
1718
host: TestProjectHost,
1819
targetSpec: TargetSpecifier,
1920
overrides = {},
21+
timeout = DefaultTimeout,
2022
logger: logging.Logger = new logging.NullLogger(),
2123
): Observable<BuildEvent> {
2224
targetSpec = { ...targetSpec, overrides };
2325
const workspaceFile = normalize('angular.json');
2426
const workspace = new experimental.workspace.Workspace(host.root(), host);
2527

26-
return workspace.loadWorkspaceFromHost(workspaceFile).pipe(
28+
// Emit when runArchitect$ completes or errors.
29+
// TODO: There must be a better way of doing this...
30+
let finalizeCB = () => { };
31+
const runArchitectFinalize$ = new Observable(obs => {
32+
finalizeCB = () => obs.next();
33+
});
34+
35+
// Load the workspace from the root of the host, then run a target.
36+
const runArchitect$ = workspace.loadWorkspaceFromHost(workspaceFile).pipe(
2737
concatMap(ws => new Architect(ws).loadArchitect()),
2838
concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec), { logger })),
39+
finalize(() => finalizeCB()),
40+
);
41+
42+
// Error out after the timeout if runArchitect$ hasn't finalized.
43+
const timeout$ = timer(timeout).pipe(
44+
takeUntil(runArchitectFinalize$),
45+
concatMapTo(throwError(`runTargetSpec timeout (${timeout}) reached.`)),
46+
);
47+
48+
return merge(
49+
timeout$,
50+
runArchitect$,
2951
);
3052
}

packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { runTargetSpec } from '@angular-devkit/architect/testing';
8+
import { DefaultTimeout, runTargetSpec } from '@angular-devkit/architect/testing';
99
import { normalize, virtualFs } from '@angular-devkit/core';
1010
import { tap } from 'rxjs/operators';
11-
import { Timeout, host } from '../utils';
11+
import { host } from '../utils';
1212

1313

1414
describe('AppShell Builder', () => {
@@ -38,14 +38,13 @@ describe('AppShell Builder', () => {
3838
`,
3939
});
4040

41-
runTargetSpec(host, { project: 'app', target: 'app-shell' }).pipe(
41+
runTargetSpec(host, { project: 'app', target: 'app-shell' }, DefaultTimeout * 2).pipe(
4242
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
4343
tap(() => {
4444
const fileName = 'dist/index.html';
4545
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
4646
expect(content).toMatch(/Welcome to app!/);
4747
}),
4848
).toPromise().then(done, done.fail);
49-
50-
}, Timeout.Complex);
49+
});
5150
});

packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { tap } from 'rxjs/operators';
11-
import { Timeout, browserTargetSpec, host } from '../utils';
11+
import { browserTargetSpec, host } from '../utils';
1212

1313

1414
describe('Browser Builder allow js', () => {
@@ -27,7 +27,7 @@ describe('Browser Builder allow js', () => {
2727
runTargetSpec(host, browserTargetSpec).pipe(
2828
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
2929
).toPromise().then(done, done.fail);
30-
}, Timeout.Basic);
30+
});
3131

3232
it('works with aot', (done) => {
3333
host.writeMultipleFiles({
@@ -40,5 +40,5 @@ describe('Browser Builder allow js', () => {
4040
runTargetSpec(host, browserTargetSpec, overrides).pipe(
4141
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
4242
).toPromise().then(done, done.fail);
43-
}, Timeout.Basic);
43+
});
4444
});

packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { tap } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder AOT', () => {
@@ -29,5 +29,5 @@ describe('Browser Builder AOT', () => {
2929
expect(content).toMatch(/platformBrowser.*bootstrapModuleFactory.*AppModuleNgFactory/);
3030
}),
3131
).toPromise().then(done, done.fail);
32-
}, Timeout.Standard);
32+
});
3333
});

packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { normalize, virtualFs } from '@angular-devkit/core';
1111
import { tap, toArray } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder assets', () => {
@@ -57,7 +57,7 @@ describe('Browser Builder assets', () => {
5757
expect(host.scopedSync().exists(normalize('./dist/folder/.gitkeep'))).toBe(false);
5858
}),
5959
).toPromise().then(done, done.fail);
60-
}, Timeout.Basic);
60+
});
6161

6262
it('fails with non-absolute output path', (done) => {
6363
const assets: { [path: string]: string } = {
@@ -76,7 +76,7 @@ describe('Browser Builder assets', () => {
7676
// The node_modules folder must be deleted, otherwise code that tries to find the
7777
// node_modules folder will hit this one and can fail.
7878
host.scopedSync().delete(normalize('./node_modules'));
79-
}, Timeout.Basic);
79+
});
8080

8181
it('fails with non-source root input path', (done) => {
8282
const assets: { [path: string]: string } = {
@@ -93,7 +93,7 @@ describe('Browser Builder assets', () => {
9393
// The node_modules folder must be deleted, otherwise code that tries to find the
9494
// node_modules folder will hit this one and can fail.
9595
host.scopedSync().delete(normalize('./node_modules'));
96-
}, Timeout.Basic);
96+
});
9797

9898
it('still builds with empty asset array', (done) => {
9999
const overrides = {
@@ -104,5 +104,5 @@ describe('Browser Builder assets', () => {
104104
toArray(),
105105
tap((buildEvents) => expect(buildEvents.length).toBe(1)),
106106
).toPromise().then(done, done.fail);
107-
}, Timeout.Basic);
107+
});
108108
});

packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { tap } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder base href', () => {
@@ -34,5 +34,5 @@ describe('Browser Builder base href', () => {
3434
expect(content).toMatch(/<base href="\/myUrl">/);
3535
}),
3636
).toPromise().then(done, done.fail);
37-
}, Timeout.Basic);
37+
});
3838
});

packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { tap } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder build optimizer', () => {
@@ -28,5 +28,5 @@ describe('Browser Builder build optimizer', () => {
2828
expect(content).not.toMatch(/\.decorators =/);
2929
}),
3030
).toPromise().then(done, done.fail);
31-
}, Timeout.Basic);
31+
});
3232
});

packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
9+
import { DefaultTimeout, TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { tap } from 'rxjs/operators';
11-
import { Timeout, browserTargetSpec, host } from '../utils';
11+
import { browserTargetSpec, host } from '../utils';
1212

1313

1414
describe('Browser Builder bundle budgets', () => {
@@ -24,22 +24,22 @@ describe('Browser Builder bundle budgets', () => {
2424

2525
const logger = new TestLogger('rebuild-type-errors');
2626

27-
runTargetSpec(host, browserTargetSpec, overrides, logger).pipe(
27+
runTargetSpec(host, browserTargetSpec, overrides, DefaultTimeout * 2, logger).pipe(
2828
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
2929
tap(() => expect(logger.includes('WARNING')).toBe(false)),
3030
).toPromise().then(done, done.fail);
31-
}, Timeout.Complex);
31+
});
3232

3333
it('shows errors', (done) => {
3434
const overrides = {
3535
optimization: true,
3636
budgets: [{ type: 'all', maximumError: '100b' }],
3737
};
3838

39-
runTargetSpec(host, browserTargetSpec, overrides).pipe(
39+
runTargetSpec(host, browserTargetSpec, overrides, DefaultTimeout * 2).pipe(
4040
tap((buildEvent) => expect(buildEvent.success).toBe(false)),
4141
).toPromise().then(done, done.fail);
42-
}, Timeout.Complex);
42+
});
4343

4444
it('shows warnings', (done) => {
4545
const overrides = {
@@ -49,9 +49,9 @@ describe('Browser Builder bundle budgets', () => {
4949

5050
const logger = new TestLogger('rebuild-type-errors');
5151

52-
runTargetSpec(host, browserTargetSpec, overrides, logger).pipe(
52+
runTargetSpec(host, browserTargetSpec, overrides, DefaultTimeout * 2, logger).pipe(
5353
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
5454
tap(() => expect(logger.includes('WARNING')).toBe(true)),
5555
).toPromise().then(done, done.fail);
56-
}, Timeout.Complex);
56+
});
5757
});

packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
9+
import { DefaultTimeout, TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { tap } from 'rxjs/operators';
11-
import { Timeout, browserTargetSpec, host } from '../utils';
11+
import { browserTargetSpec, host } from '../utils';
1212

1313

1414
describe('Browser Builder circular dependency detection', () => {
@@ -22,9 +22,9 @@ describe('Browser Builder circular dependency detection', () => {
2222
const overrides = { baseHref: '/myUrl' };
2323
const logger = new TestLogger('circular-dependencies');
2424

25-
runTargetSpec(host, browserTargetSpec, overrides, logger).pipe(
25+
runTargetSpec(host, browserTargetSpec, overrides, DefaultTimeout, logger).pipe(
2626
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
2727
tap(() => expect(logger.includes('Circular dependency detected')).toBe(true)),
2828
).toPromise().then(done, done.fail);
29-
}, Timeout.Basic);
29+
});
3030
});

packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { concatMap, tap } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder deploy url', () => {
@@ -37,7 +37,7 @@ describe('Browser Builder deploy url', () => {
3737
expect(content).toContain('http://example.com/some/path/main.js');
3838
}),
3939
).toPromise().then(done, done.fail);
40-
}, Timeout.Basic);
40+
});
4141

4242
it('uses deploy url for in webpack runtime', (done) => {
4343
const overrides = { deployUrl: 'deployUrl/' };
@@ -50,6 +50,6 @@ describe('Browser Builder deploy url', () => {
5050
expect(content).toContain('deployUrl/');
5151
}),
5252
).toPromise().then(done, done.fail);
53-
}, Timeout.Basic);
53+
});
5454

5555
});

packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
9+
import { DefaultTimeout, TestLogger, runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { tap } from 'rxjs/operators';
11-
import { Timeout, browserTargetSpec, host } from '../utils';
11+
import { browserTargetSpec, host } from '../utils';
1212

1313

1414
describe('Browser Builder errors', () => {
@@ -22,36 +22,36 @@ describe('Browser Builder errors', () => {
2222
`);
2323
const logger = new TestLogger('errors-compilation');
2424

25-
runTargetSpec(host, browserTargetSpec, undefined, logger).pipe(
25+
runTargetSpec(host, browserTargetSpec, {}, DefaultTimeout, logger).pipe(
2626
tap((buildEvent) => {
2727
expect(buildEvent.success).toBe(false);
2828
expect(logger.includes('polyfills.ts is missing from the TypeScript')).toBe(true);
2929
}),
3030
).toPromise().then(done, done.fail);
31-
}, Timeout.Basic);
31+
});
3232

3333
it('shows TS syntax errors', (done) => {
3434
host.appendToFile('src/app/app.component.ts', ']]]');
3535
const logger = new TestLogger('errors-syntax');
3636

37-
runTargetSpec(host, browserTargetSpec, undefined, logger).pipe(
37+
runTargetSpec(host, browserTargetSpec, {}, DefaultTimeout, logger).pipe(
3838
tap((buildEvent) => {
3939
expect(buildEvent.success).toBe(false);
4040
expect(logger.includes('Declaration or statement expected.')).toBe(true);
4141
}),
4242
).toPromise().then(done, done.fail);
43-
}, Timeout.Basic);
43+
});
4444

4545
it('shows static analysis errors', (done) => {
4646
host.replaceInFile('src/app/app.component.ts', `'app-root'`, `(() => 'app-root')()`);
4747
const logger = new TestLogger('errors-static');
4848

49-
runTargetSpec(host, browserTargetSpec, { aot: true }, logger).pipe(
49+
runTargetSpec(host, browserTargetSpec, { aot: true }, DefaultTimeout, logger).pipe(
5050
tap((buildEvent) => {
5151
expect(buildEvent.success).toBe(false);
5252
expect(logger.includes('Function expressions are not supported in')).toBe(true);
5353
}),
5454
).toPromise().then(done, done.fail);
55-
}, Timeout.Basic);
55+
});
5656

5757
});

packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { runTargetSpec } from '@angular-devkit/architect/testing';
1010
import { join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { tap } from 'rxjs/operators';
12-
import { Timeout, browserTargetSpec, host } from '../utils';
12+
import { browserTargetSpec, host } from '../utils';
1313

1414

1515
describe('Browser Builder i18n', () => {
@@ -62,7 +62,7 @@ describe('Browser Builder i18n', () => {
6262
expect(content).toMatch(/Bonjour i18n!/);
6363
}),
6464
).toPromise().then(done, done.fail);
65-
}, Timeout.Basic);
65+
});
6666

6767
it('ignores missing translations', (done) => {
6868
const overrides = {
@@ -84,7 +84,7 @@ describe('Browser Builder i18n', () => {
8484
expect(content).toMatch(/Other content/);
8585
}),
8686
).toPromise().then(done, done.fail);
87-
}, Timeout.Basic);
87+
});
8888

8989
it('reports errors for missing translations', (done) => {
9090
const overrides = {
@@ -101,7 +101,7 @@ describe('Browser Builder i18n', () => {
101101
runTargetSpec(host, browserTargetSpec, overrides).pipe(
102102
tap((buildEvent) => expect(buildEvent.success).toBe(false)),
103103
).toPromise().then(done, done.fail);
104-
}, Timeout.Basic);
104+
});
105105

106106
it('register locales', (done) => {
107107
const overrides = { aot: true, i18nLocale: 'fr_FR' };
@@ -115,5 +115,5 @@ describe('Browser Builder i18n', () => {
115115
expect(content).toMatch(/angular_common_locales_fr/);
116116
}),
117117
).toPromise().then(done, done.fail);
118-
}, Timeout.Basic);
118+
});
119119
});

0 commit comments

Comments
 (0)