diff --git a/tests/legacy-cli/e2e/utils/registry.ts b/tests/legacy-cli/e2e/utils/registry.ts index 4395e5b1ca..6b3b07ade9 100644 --- a/tests/legacy-cli/e2e/utils/registry.ts +++ b/tests/legacy-cli/e2e/utils/registry.ts @@ -1,17 +1,24 @@ -import { ChildProcess, spawn } from 'child_process'; -import { copyFileSync, mkdtempSync, realpathSync } from 'fs'; +import { spawn } from 'child_process'; +import { mkdtempSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; 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 const registryPath = mkdtempSync(join(realpathSync(tmpdir()), 'angular-cli-e2e-registry-')); - copyFileSync( + let configContent = await readFile( 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'], { cwd: registryPath, @@ -21,7 +28,6 @@ export function createNpmRegistry(withAuthentication = false): ChildProcess { // Token was generated using `echo -n 'testing:s3cret' | openssl base64`. const VALID_TOKEN = `dGVzdGluZzpzM2NyZXQ=`; -const SECURE_REGISTRY = `//localhost:4876/`; export function createNpmConfigForAuthentication( /** @@ -42,7 +48,7 @@ export function createNpmConfigForAuthentication( invalidToken = false, ): Promise { const token = invalidToken ? `invalid=` : VALID_TOKEN; - const registry = SECURE_REGISTRY; + const registry = (getGlobalVariable('package-secure-registry') as string).replace(/^\w+:/, ''); return writeFile( '.npmrc', @@ -68,7 +74,7 @@ export function setNpmEnvVarsForAuthentication( delete process.env['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; diff --git a/tests/legacy-cli/e2e_runner.ts b/tests/legacy-cli/e2e_runner.ts index c049e8ce0b..1581aa5acb 100644 --- a/tests/legacy-cli/e2e_runner.ts +++ b/tests/legacy-cli/e2e_runner.ts @@ -9,6 +9,7 @@ import * as path from 'path'; import { setGlobalVariable } from './e2e/utils/env'; import { gitClean } from './e2e/utils/git'; import { createNpmRegistry } from './e2e/utils/registry'; +import { AddressInfo, createServer, Server } from 'net'; Error.stackTraceLimit = Infinity; @@ -122,93 +123,99 @@ if (testsToRun.length == allTests.length) { setGlobalVariable('argv', argv); setGlobalVariable('ci', process.env['CI']?.toLowerCase() === 'true' || process.env['CI'] === '1'); setGlobalVariable('package-manager', argv.yarn ? 'yarn' : 'npm'); -setGlobalVariable('package-registry', 'http://localhost:4873'); -const registryProcess = createNpmRegistry(); -const secureRegistryProcess = createNpmRegistry(true); +Promise.all([findFreePort(), findFreePort()]) + .then(async ([httpPort, httpsPort]) => { + setGlobalVariable('package-registry', 'http://localhost:' + httpPort); + setGlobalVariable('package-secure-registry', 'http://localhost:' + httpsPort); -testsToRun - .reduce((previous, relativeName, testIndex) => { - // 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 registryProcess = await createNpmRegistry(httpPort, httpPort); + const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true); - return previous.then(() => { - currentFileName = relativeName.replace(/\.ts$/, ''); - const start = +new Date(); + return testsToRun + .reduce((previous, relativeName, testIndex) => { + // 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); - const originalEnvVariables = { - ...process.env, - }; + return previous.then(() => { + currentFileName = relativeName.replace(/\.ts$/, ''); + const start = +new Date(); - const fn: (skipClean?: () => void) => Promise | void = - typeof module == 'function' - ? module - : typeof module.default == 'function' - ? module.default - : () => { - throw new Error('Invalid test module.'); - }; + const module = require(absoluteName); + const originalEnvVariables = { + ...process.env, + }; - let clean = true; - let previousDir = null; + const fn: (skipClean?: () => void) => Promise | void = + typeof module == 'function' + ? module + : typeof module.default == 'function' + ? module.default + : () => { + throw new Error('Invalid test module.'); + }; - return Promise.resolve() - .then(() => printHeader(currentFileName, testIndex)) - .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); + let clean = true; + let previousDir = null; - // 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( + return Promise.resolve() + .then(() => printHeader(currentFileName, testIndex)) + .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. + 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; + }, ); - } - }) - .then( - () => printFooter(currentFileName, start), - (err) => { - printFooter(currentFileName, start); - console.error(err); - throw err; - }, - ); - }); - }, Promise.resolve()) + }); + }, Promise.resolve()) + .finally(() => { + registryProcess.kill(); + secureRegistryProcess.kill(); + }); + }) .then( () => { - registryProcess.kill(); - secureRegistryProcess.kill(); - console.log(colors.green('Done.')); process.exit(0); }, @@ -218,9 +225,6 @@ testsToRun console.error(colors.red(err.message)); console.error(colors.red(err.stack)); - registryProcess.kill(); - secureRegistryProcess.kill(); - if (argv.debug) { console.log(`Current Directory: ${process.cwd()}`); 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(''); } + +function findFreePort() { + return new Promise((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(); + }); +} diff --git a/tests/legacy-cli/verdaccio.yaml b/tests/legacy-cli/verdaccio.yaml index fb693847e6..075da2628c 100644 --- a/tests/legacy-cli/verdaccio.yaml +++ b/tests/legacy-cli/verdaccio.yaml @@ -3,7 +3,7 @@ storage: ./storage auth: auth-memory: users: {} -listen: localhost:4873 +listen: localhost:${HTTP_PORT} uplinks: npmjs: url: https://registry.npmjs.org/ diff --git a/tests/legacy-cli/verdaccio_auth.yaml b/tests/legacy-cli/verdaccio_auth.yaml index 25f510d850..e230030b10 100644 --- a/tests/legacy-cli/verdaccio_auth.yaml +++ b/tests/legacy-cli/verdaccio_auth.yaml @@ -5,10 +5,10 @@ auth: testing: name: testing password: s3cret -listen: localhost:4876 +listen: localhost:${HTTPS_PORT} uplinks: local: - url: http://localhost:4873 + url: http://localhost:${HTTP_PORT} cache: false maxage: 20m max_fails: 32