mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-18 03:23:57 +08:00
test: use random ports for local verdaccio npm servers
This commit is contained in:
parent
ba93117e78
commit
aa30bb156d
@ -1,17 +1,24 @@
|
|||||||
import { ChildProcess, spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { copyFileSync, mkdtempSync, realpathSync } from 'fs';
|
import { mkdtempSync, realpathSync } from 'fs';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { writeFile } from './fs';
|
import { getGlobalVariable } from './env';
|
||||||
|
import { writeFile, readFile } from './fs';
|
||||||
|
|
||||||
export function createNpmRegistry(withAuthentication = false): ChildProcess {
|
export async function createNpmRegistry(
|
||||||
|
port: number,
|
||||||
|
httpsPort: number,
|
||||||
|
withAuthentication = false,
|
||||||
|
) {
|
||||||
// Setup local package registry
|
// Setup local package registry
|
||||||
const registryPath = mkdtempSync(join(realpathSync(tmpdir()), 'angular-cli-e2e-registry-'));
|
const registryPath = mkdtempSync(join(realpathSync(tmpdir()), 'angular-cli-e2e-registry-'));
|
||||||
|
|
||||||
copyFileSync(
|
let configContent = await readFile(
|
||||||
join(__dirname, '../../', withAuthentication ? 'verdaccio_auth.yaml' : 'verdaccio.yaml'),
|
join(__dirname, '../../', withAuthentication ? 'verdaccio_auth.yaml' : 'verdaccio.yaml'),
|
||||||
join(registryPath, 'verdaccio.yaml'),
|
|
||||||
);
|
);
|
||||||
|
configContent = configContent.replace(/\$\{HTTP_PORT\}/g, String(port));
|
||||||
|
configContent = configContent.replace(/\$\{HTTPS_PORT\}/g, String(httpsPort));
|
||||||
|
await writeFile(join(registryPath, 'verdaccio.yaml'), configContent);
|
||||||
|
|
||||||
return spawn('node', [require.resolve('verdaccio/bin/verdaccio'), '-c', './verdaccio.yaml'], {
|
return spawn('node', [require.resolve('verdaccio/bin/verdaccio'), '-c', './verdaccio.yaml'], {
|
||||||
cwd: registryPath,
|
cwd: registryPath,
|
||||||
@ -21,7 +28,6 @@ export function createNpmRegistry(withAuthentication = false): ChildProcess {
|
|||||||
|
|
||||||
// Token was generated using `echo -n 'testing:s3cret' | openssl base64`.
|
// Token was generated using `echo -n 'testing:s3cret' | openssl base64`.
|
||||||
const VALID_TOKEN = `dGVzdGluZzpzM2NyZXQ=`;
|
const VALID_TOKEN = `dGVzdGluZzpzM2NyZXQ=`;
|
||||||
const SECURE_REGISTRY = `//localhost:4876/`;
|
|
||||||
|
|
||||||
export function createNpmConfigForAuthentication(
|
export function createNpmConfigForAuthentication(
|
||||||
/**
|
/**
|
||||||
@ -42,7 +48,7 @@ export function createNpmConfigForAuthentication(
|
|||||||
invalidToken = false,
|
invalidToken = false,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const token = invalidToken ? `invalid=` : VALID_TOKEN;
|
const token = invalidToken ? `invalid=` : VALID_TOKEN;
|
||||||
const registry = SECURE_REGISTRY;
|
const registry = (getGlobalVariable('package-secure-registry') as string).replace(/^\w+:/, '');
|
||||||
|
|
||||||
return writeFile(
|
return writeFile(
|
||||||
'.npmrc',
|
'.npmrc',
|
||||||
@ -68,7 +74,7 @@ export function setNpmEnvVarsForAuthentication(
|
|||||||
delete process.env['NPM_CONFIG_REGISTRY'];
|
delete process.env['NPM_CONFIG_REGISTRY'];
|
||||||
|
|
||||||
const registryKey = useYarnEnvVariable ? 'YARN_REGISTRY' : 'NPM_CONFIG_REGISTRY';
|
const registryKey = useYarnEnvVariable ? 'YARN_REGISTRY' : 'NPM_CONFIG_REGISTRY';
|
||||||
process.env[registryKey] = `http:${SECURE_REGISTRY}`;
|
process.env[registryKey] = getGlobalVariable('package-secure-registry');
|
||||||
|
|
||||||
process.env['NPM_CONFIG__AUTH'] = invalidToken ? `invalid=` : VALID_TOKEN;
|
process.env['NPM_CONFIG__AUTH'] = invalidToken ? `invalid=` : VALID_TOKEN;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import * as path from 'path';
|
|||||||
import { setGlobalVariable } from './e2e/utils/env';
|
import { setGlobalVariable } from './e2e/utils/env';
|
||||||
import { gitClean } from './e2e/utils/git';
|
import { gitClean } from './e2e/utils/git';
|
||||||
import { createNpmRegistry } from './e2e/utils/registry';
|
import { createNpmRegistry } from './e2e/utils/registry';
|
||||||
|
import { AddressInfo, createServer, Server } from 'net';
|
||||||
|
|
||||||
Error.stackTraceLimit = Infinity;
|
Error.stackTraceLimit = Infinity;
|
||||||
|
|
||||||
@ -122,93 +123,99 @@ if (testsToRun.length == allTests.length) {
|
|||||||
setGlobalVariable('argv', argv);
|
setGlobalVariable('argv', argv);
|
||||||
setGlobalVariable('ci', process.env['CI']?.toLowerCase() === 'true' || process.env['CI'] === '1');
|
setGlobalVariable('ci', process.env['CI']?.toLowerCase() === 'true' || process.env['CI'] === '1');
|
||||||
setGlobalVariable('package-manager', argv.yarn ? 'yarn' : 'npm');
|
setGlobalVariable('package-manager', argv.yarn ? 'yarn' : 'npm');
|
||||||
setGlobalVariable('package-registry', 'http://localhost:4873');
|
|
||||||
|
|
||||||
const registryProcess = createNpmRegistry();
|
Promise.all([findFreePort(), findFreePort()])
|
||||||
const secureRegistryProcess = createNpmRegistry(true);
|
.then(async ([httpPort, httpsPort]) => {
|
||||||
|
setGlobalVariable('package-registry', 'http://localhost:' + httpPort);
|
||||||
|
setGlobalVariable('package-secure-registry', 'http://localhost:' + httpsPort);
|
||||||
|
|
||||||
testsToRun
|
const registryProcess = await createNpmRegistry(httpPort, httpPort);
|
||||||
.reduce((previous, relativeName, testIndex) => {
|
const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true);
|
||||||
// Make sure this is a windows compatible path.
|
|
||||||
let absoluteName = path.join(e2eRoot, relativeName);
|
|
||||||
if (/^win/.test(process.platform)) {
|
|
||||||
absoluteName = absoluteName.replace(/\\/g, path.posix.sep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return previous.then(() => {
|
return testsToRun
|
||||||
currentFileName = relativeName.replace(/\.ts$/, '');
|
.reduce((previous, relativeName, testIndex) => {
|
||||||
const start = +new Date();
|
// Make sure this is a windows compatible path.
|
||||||
|
let absoluteName = path.join(e2eRoot, relativeName);
|
||||||
|
if (/^win/.test(process.platform)) {
|
||||||
|
absoluteName = absoluteName.replace(/\\/g, path.posix.sep);
|
||||||
|
}
|
||||||
|
|
||||||
const module = require(absoluteName);
|
return previous.then(() => {
|
||||||
const originalEnvVariables = {
|
currentFileName = relativeName.replace(/\.ts$/, '');
|
||||||
...process.env,
|
const start = +new Date();
|
||||||
};
|
|
||||||
|
|
||||||
const fn: (skipClean?: () => void) => Promise<void> | void =
|
const module = require(absoluteName);
|
||||||
typeof module == 'function'
|
const originalEnvVariables = {
|
||||||
? module
|
...process.env,
|
||||||
: typeof module.default == 'function'
|
};
|
||||||
? module.default
|
|
||||||
: () => {
|
|
||||||
throw new Error('Invalid test module.');
|
|
||||||
};
|
|
||||||
|
|
||||||
let clean = true;
|
const fn: (skipClean?: () => void) => Promise<void> | void =
|
||||||
let previousDir = null;
|
typeof module == 'function'
|
||||||
|
? module
|
||||||
|
: typeof module.default == 'function'
|
||||||
|
? module.default
|
||||||
|
: () => {
|
||||||
|
throw new Error('Invalid test module.');
|
||||||
|
};
|
||||||
|
|
||||||
return Promise.resolve()
|
let clean = true;
|
||||||
.then(() => printHeader(currentFileName, testIndex))
|
let previousDir = null;
|
||||||
.then(() => (previousDir = process.cwd()))
|
|
||||||
.then(() => logStack.push(lastLogger().createChild(currentFileName)))
|
|
||||||
.then(() => fn(() => (clean = false)))
|
|
||||||
.then(
|
|
||||||
() => logStack.pop(),
|
|
||||||
(err) => {
|
|
||||||
logStack.pop();
|
|
||||||
throw err;
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.then(() => console.log('----'))
|
|
||||||
.then(() => {
|
|
||||||
// If we're not in a setup, change the directory back to where it was before the test.
|
|
||||||
// This allows tests to chdir without worrying about keeping the original directory.
|
|
||||||
if (!allSetups.includes(relativeName) && previousDir) {
|
|
||||||
process.chdir(previousDir);
|
|
||||||
|
|
||||||
// Restore env variables before each test.
|
return Promise.resolve()
|
||||||
console.log(' Restoring original environment variables...');
|
.then(() => printHeader(currentFileName, testIndex))
|
||||||
process.env = originalEnvVariables;
|
.then(() => (previousDir = process.cwd()))
|
||||||
}
|
.then(() => logStack.push(lastLogger().createChild(currentFileName)))
|
||||||
})
|
.then(() => fn(() => (clean = false)))
|
||||||
.then(() => {
|
.then(
|
||||||
// Only clean after a real test, not a setup step. Also skip cleaning if the test
|
|
||||||
// requested an exception.
|
|
||||||
if (!allSetups.includes(relativeName) && clean) {
|
|
||||||
logStack.push(new logging.NullLogger());
|
|
||||||
return gitClean().then(
|
|
||||||
() => logStack.pop(),
|
() => logStack.pop(),
|
||||||
(err) => {
|
(err) => {
|
||||||
logStack.pop();
|
logStack.pop();
|
||||||
throw err;
|
throw err;
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
.then(() => console.log('----'))
|
||||||
|
.then(() => {
|
||||||
|
// If we're not in a setup, change the directory back to where it was before the test.
|
||||||
|
// This allows tests to chdir without worrying about keeping the original directory.
|
||||||
|
if (!allSetups.includes(relativeName) && previousDir) {
|
||||||
|
process.chdir(previousDir);
|
||||||
|
|
||||||
|
// Restore env variables before each test.
|
||||||
|
console.log(' Restoring original environment variables...');
|
||||||
|
process.env = originalEnvVariables;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Only clean after a real test, not a setup step. Also skip cleaning if the test
|
||||||
|
// requested an exception.
|
||||||
|
if (!allSetups.includes(relativeName) && clean) {
|
||||||
|
logStack.push(new logging.NullLogger());
|
||||||
|
return gitClean().then(
|
||||||
|
() => logStack.pop(),
|
||||||
|
(err) => {
|
||||||
|
logStack.pop();
|
||||||
|
throw err;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
() => printFooter(currentFileName, start),
|
||||||
|
(err) => {
|
||||||
|
printFooter(currentFileName, start);
|
||||||
|
console.error(err);
|
||||||
|
throw err;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
})
|
}, Promise.resolve())
|
||||||
.then(
|
.finally(() => {
|
||||||
() => printFooter(currentFileName, start),
|
registryProcess.kill();
|
||||||
(err) => {
|
secureRegistryProcess.kill();
|
||||||
printFooter(currentFileName, start);
|
});
|
||||||
console.error(err);
|
})
|
||||||
throw err;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, Promise.resolve())
|
|
||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
registryProcess.kill();
|
|
||||||
secureRegistryProcess.kill();
|
|
||||||
|
|
||||||
console.log(colors.green('Done.'));
|
console.log(colors.green('Done.'));
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
},
|
},
|
||||||
@ -218,9 +225,6 @@ testsToRun
|
|||||||
console.error(colors.red(err.message));
|
console.error(colors.red(err.message));
|
||||||
console.error(colors.red(err.stack));
|
console.error(colors.red(err.stack));
|
||||||
|
|
||||||
registryProcess.kill();
|
|
||||||
secureRegistryProcess.kill();
|
|
||||||
|
|
||||||
if (argv.debug) {
|
if (argv.debug) {
|
||||||
console.log(`Current Directory: ${process.cwd()}`);
|
console.log(`Current Directory: ${process.cwd()}`);
|
||||||
console.log('Will loop forever while you debug... CTRL-C to quit.');
|
console.log('Will loop forever while you debug... CTRL-C to quit.');
|
||||||
@ -257,3 +261,15 @@ function printFooter(testName: string, startTime: number) {
|
|||||||
console.log(colors.green('Last step took ') + colors.bold.blue('' + t) + colors.green('s...'));
|
console.log(colors.green('Last step took ') + colors.bold.blue('' + t) + colors.green('s...'));
|
||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findFreePort() {
|
||||||
|
return new Promise<number>((resolve, reject) => {
|
||||||
|
const srv = createServer();
|
||||||
|
srv.once('listening', () => {
|
||||||
|
const port = (srv.address() as AddressInfo).port;
|
||||||
|
srv.close((e) => (e ? reject(e) : resolve(port)));
|
||||||
|
});
|
||||||
|
srv.once('error', (e) => srv.close(() => reject(e)));
|
||||||
|
srv.listen();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ storage: ./storage
|
|||||||
auth:
|
auth:
|
||||||
auth-memory:
|
auth-memory:
|
||||||
users: {}
|
users: {}
|
||||||
listen: localhost:4873
|
listen: localhost:${HTTP_PORT}
|
||||||
uplinks:
|
uplinks:
|
||||||
npmjs:
|
npmjs:
|
||||||
url: https://registry.npmjs.org/
|
url: https://registry.npmjs.org/
|
||||||
|
@ -5,10 +5,10 @@ auth:
|
|||||||
testing:
|
testing:
|
||||||
name: testing
|
name: testing
|
||||||
password: s3cret
|
password: s3cret
|
||||||
listen: localhost:4876
|
listen: localhost:${HTTPS_PORT}
|
||||||
uplinks:
|
uplinks:
|
||||||
local:
|
local:
|
||||||
url: http://localhost:4873
|
url: http://localhost:${HTTP_PORT}
|
||||||
cache: false
|
cache: false
|
||||||
maxage: 20m
|
maxage: 20m
|
||||||
max_fails: 32
|
max_fails: 32
|
||||||
|
Loading…
x
Reference in New Issue
Block a user