test(compiler-cli): load test files into memory only once (#38909)

Prior to this change, each invocation of `loadStandardTestFiles` would
load the necessary files from disk. This function is typically called
at the top-level of a test module in order to share the result across
tests. The `//packages/compiler-cli/test/ngtsc` target has 8 modules
where this call occurs, each loading their own copy of
`node_modules/typescript` which is ~60MB in size, so the memory overhead
used to be significant. This commit loads the individual packages into
a standalone `Folder` and mounts this folder into the filesystem of
standard test files, such that all file contents are no longer
duplicated in memory.

PR Close #38909
This commit is contained in:
JoostK
2020-09-20 01:06:19 +02:00
committed by Alex Rickabaugh
parent b627f7f02e
commit e790c8547e
2 changed files with 72 additions and 18 deletions

View File

@ -22,28 +22,43 @@ export function loadTestFiles(files: TestFile[]) {
});
}
/**
* A folder that is lazily loaded upon first access and then cached.
*/
class CachedFolder {
private folder: Folder|null = null;
constructor(private loader: () => Folder) {}
get(): Folder {
if (this.folder === null) {
this.folder = this.loader();
}
return this.folder;
}
}
const typescriptFolder = new CachedFolder(() => loadFolder(resolveNpmTreeArtifact('typescript')));
const angularFolder = new CachedFolder(loadAngularFolder);
const rxjsFolder = new CachedFolder(() => loadFolder(resolveNpmTreeArtifact('rxjs')));
export function loadStandardTestFiles(
{fakeCore = true, rxjs = false}: {fakeCore?: boolean, rxjs?: boolean} = {}): Folder {
const tmpFs = new MockFileSystemPosix(true);
const basePath = '/' as AbsoluteFsPath;
loadTestDirectory(
tmpFs, resolveNpmTreeArtifact('typescript'),
tmpFs.resolve(basePath, 'node_modules/typescript'));
tmpFs.mount(tmpFs.resolve('/node_modules/typescript'), typescriptFolder.get());
loadTsLib(tmpFs, basePath);
if (fakeCore) {
loadFakeCore(tmpFs, basePath);
} else {
getAngularPackagesFromRunfiles().forEach(({name, pkgPath}) => {
loadTestDirectory(tmpFs, pkgPath, tmpFs.resolve(basePath, 'node_modules/@angular', name));
});
tmpFs.mount(tmpFs.resolve('/node_modules/@angular'), angularFolder.get());
}
if (rxjs) {
loadTestDirectory(
tmpFs, resolveNpmTreeArtifact('rxjs'), tmpFs.resolve(basePath, 'node_modules/rxjs'));
tmpFs.mount(tmpFs.resolve('/node_modules/rxjs'), rxjsFolder.get());
}
return tmpFs.dump();
@ -60,6 +75,20 @@ export function loadFakeCore(fs: FileSystem, basePath: string = '/') {
fs.resolve(basePath, 'node_modules/@angular/core'));
}
function loadFolder(path: string): Folder {
const tmpFs = new MockFileSystemPosix(true);
loadTestDirectory(tmpFs, tmpFs.resolve(path), tmpFs.resolve('/'));
return tmpFs.dump();
}
function loadAngularFolder(): Folder {
const tmpFs = new MockFileSystemPosix(true);
getAngularPackagesFromRunfiles().forEach(({name, pkgPath}) => {
loadTestDirectory(tmpFs, pkgPath, tmpFs.resolve(name));
});
return tmpFs.dump();
}
/**
* Load real files from the real file-system into a mock file-system.
* @param fs the file-system where the directory is to be loaded.