Skip to content

Commit c02fdca

Browse files
committed
test: use random ports for local verdaccio npm servers
1 parent e72fbcd commit c02fdca

File tree

4 files changed

+104
-86
lines changed

4 files changed

+104
-86
lines changed

tests/legacy-cli/e2e/utils/registry.ts

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
import { ChildProcess, spawn } from 'child_process';
2-
import { copyFileSync, mkdtempSync, realpathSync } from 'fs';
1+
import { spawn } from 'child_process';
2+
import { mkdtempSync, realpathSync } from 'fs';
33
import { tmpdir } from 'os';
44
import { join } from 'path';
5-
import { writeFile } from './fs';
5+
import { getGlobalVariable } from './env';
6+
import { writeFile, readFile } from './fs';
67

7-
export function createNpmRegistry(withAuthentication = false): ChildProcess {
8+
export async function createNpmRegistry(
9+
port: number,
10+
httpsPort: number,
11+
withAuthentication = false,
12+
) {
813
// Setup local package registry
914
const registryPath = mkdtempSync(join(realpathSync(tmpdir()), 'angular-cli-e2e-registry-'));
1015

11-
copyFileSync(
16+
let configContent = await readFile(
1217
join(__dirname, '../../', withAuthentication ? 'verdaccio_auth.yaml' : 'verdaccio.yaml'),
13-
join(registryPath, 'verdaccio.yaml'),
1418
);
19+
configContent = configContent.replace(/\$\{HTTP_PORT\}/g, String(port));
20+
configContent = configContent.replace(/\$\{HTTPS_PORT\}/g, String(httpsPort));
21+
await writeFile(join(registryPath, 'verdaccio.yaml'), configContent);
1522

1623
return spawn('node', [require.resolve('verdaccio/bin/verdaccio'), '-c', './verdaccio.yaml'], {
1724
cwd: registryPath,
@@ -21,7 +28,6 @@ export function createNpmRegistry(withAuthentication = false): ChildProcess {
2128

2229
// Token was generated using `echo -n 'testing:s3cret' | openssl base64`.
2330
const VALID_TOKEN = `dGVzdGluZzpzM2NyZXQ=`;
24-
const SECURE_REGISTRY = `//localhost:4876/`;
2531

2632
export function createNpmConfigForAuthentication(
2733
/**
@@ -42,7 +48,7 @@ export function createNpmConfigForAuthentication(
4248
invalidToken = false,
4349
): Promise<void> {
4450
const token = invalidToken ? `invalid=` : VALID_TOKEN;
45-
const registry = SECURE_REGISTRY;
51+
const registry = (getGlobalVariable('package-registry') as string).replace(/^\w+:/, '');
4652

4753
return writeFile(
4854
'.npmrc',
@@ -68,7 +74,7 @@ export function setNpmEnvVarsForAuthentication(
6874
delete process.env['NPM_CONFIG_REGISTRY'];
6975

7076
const registryKey = useYarnEnvVariable ? 'YARN_REGISTRY' : 'NPM_CONFIG_REGISTRY';
71-
process.env[registryKey] = `http:${SECURE_REGISTRY}`;
77+
process.env[registryKey] = getGlobalVariable('package-registry');
7278

7379
process.env['NPM_CONFIG__AUTH'] = invalidToken ? `invalid=` : VALID_TOKEN;
7480

tests/legacy-cli/e2e_runner.ts

+86-74
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as path from 'path';
99
import { setGlobalVariable } from './e2e/utils/env';
1010
import { gitClean } from './e2e/utils/git';
1111
import { createNpmRegistry } from './e2e/utils/registry';
12+
import { AddressInfo, createServer } from 'net';
1213

1314
Error.stackTraceLimit = Infinity;
1415

@@ -122,93 +123,98 @@ if (testsToRun.length == allTests.length) {
122123
setGlobalVariable('argv', argv);
123124
setGlobalVariable('ci', process.env['CI']?.toLowerCase() === 'true' || process.env['CI'] === '1');
124125
setGlobalVariable('package-manager', argv.yarn ? 'yarn' : 'npm');
125-
setGlobalVariable('package-registry', 'http://localhost:4873');
126126

127-
const registryProcess = createNpmRegistry();
128-
const secureRegistryProcess = createNpmRegistry(true);
127+
Promise.all([findFreePort(), findFreePort()])
128+
.then(async ([httpPort, httpsPort]) => {
129+
setGlobalVariable('package-registry', 'http://localhost:' + httpPort);
129130

130-
testsToRun
131-
.reduce((previous, relativeName, testIndex) => {
132-
// Make sure this is a windows compatible path.
133-
let absoluteName = path.join(e2eRoot, relativeName);
134-
if (/^win/.test(process.platform)) {
135-
absoluteName = absoluteName.replace(/\\/g, path.posix.sep);
136-
}
131+
const registryProcess = await createNpmRegistry(httpPort, httpPort);
132+
const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true);
137133

138-
return previous.then(() => {
139-
currentFileName = relativeName.replace(/\.ts$/, '');
140-
const start = +new Date();
134+
return testsToRun
135+
.reduce((previous, relativeName, testIndex) => {
136+
// Make sure this is a windows compatible path.
137+
let absoluteName = path.join(e2eRoot, relativeName);
138+
if (/^win/.test(process.platform)) {
139+
absoluteName = absoluteName.replace(/\\/g, path.posix.sep);
140+
}
141141

142-
const module = require(absoluteName);
143-
const originalEnvVariables = {
144-
...process.env,
145-
};
142+
return previous.then(() => {
143+
currentFileName = relativeName.replace(/\.ts$/, '');
144+
const start = +new Date();
146145

147-
const fn: (skipClean?: () => void) => Promise<void> | void =
148-
typeof module == 'function'
149-
? module
150-
: typeof module.default == 'function'
151-
? module.default
152-
: () => {
153-
throw new Error('Invalid test module.');
154-
};
146+
const module = require(absoluteName);
147+
const originalEnvVariables = {
148+
...process.env,
149+
};
155150

156-
let clean = true;
157-
let previousDir = null;
151+
const fn: (skipClean?: () => void) => Promise<void> | void =
152+
typeof module == 'function'
153+
? module
154+
: typeof module.default == 'function'
155+
? module.default
156+
: () => {
157+
throw new Error('Invalid test module.');
158+
};
158159

159-
return Promise.resolve()
160-
.then(() => printHeader(currentFileName, testIndex))
161-
.then(() => (previousDir = process.cwd()))
162-
.then(() => logStack.push(lastLogger().createChild(currentFileName)))
163-
.then(() => fn(() => (clean = false)))
164-
.then(
165-
() => logStack.pop(),
166-
(err) => {
167-
logStack.pop();
168-
throw err;
169-
},
170-
)
171-
.then(() => console.log('----'))
172-
.then(() => {
173-
// If we're not in a setup, change the directory back to where it was before the test.
174-
// This allows tests to chdir without worrying about keeping the original directory.
175-
if (!allSetups.includes(relativeName) && previousDir) {
176-
process.chdir(previousDir);
160+
let clean = true;
161+
let previousDir = null;
177162

178-
// Restore env variables before each test.
179-
console.log(' Restoring original environment variables...');
180-
process.env = originalEnvVariables;
181-
}
182-
})
183-
.then(() => {
184-
// Only clean after a real test, not a setup step. Also skip cleaning if the test
185-
// requested an exception.
186-
if (!allSetups.includes(relativeName) && clean) {
187-
logStack.push(new logging.NullLogger());
188-
return gitClean().then(
163+
return Promise.resolve()
164+
.then(() => printHeader(currentFileName, testIndex))
165+
.then(() => (previousDir = process.cwd()))
166+
.then(() => logStack.push(lastLogger().createChild(currentFileName)))
167+
.then(() => fn(() => (clean = false)))
168+
.then(
189169
() => logStack.pop(),
190170
(err) => {
191171
logStack.pop();
192172
throw err;
193173
},
174+
)
175+
.then(() => console.log('----'))
176+
.then(() => {
177+
// If we're not in a setup, change the directory back to where it was before the test.
178+
// This allows tests to chdir without worrying about keeping the original directory.
179+
if (!allSetups.includes(relativeName) && previousDir) {
180+
process.chdir(previousDir);
181+
182+
// Restore env variables before each test.
183+
console.log(' Restoring original environment variables...');
184+
process.env = originalEnvVariables;
185+
}
186+
})
187+
.then(() => {
188+
// Only clean after a real test, not a setup step. Also skip cleaning if the test
189+
// requested an exception.
190+
if (!allSetups.includes(relativeName) && clean) {
191+
logStack.push(new logging.NullLogger());
192+
return gitClean().then(
193+
() => logStack.pop(),
194+
(err) => {
195+
logStack.pop();
196+
throw err;
197+
},
198+
);
199+
}
200+
})
201+
.then(
202+
() => printFooter(currentFileName, start),
203+
(err) => {
204+
printFooter(currentFileName, start);
205+
console.error(err);
206+
throw err;
207+
},
194208
);
195-
}
196-
})
197-
.then(
198-
() => printFooter(currentFileName, start),
199-
(err) => {
200-
printFooter(currentFileName, start);
201-
console.error(err);
202-
throw err;
203-
},
204-
);
205-
});
206-
}, Promise.resolve())
209+
});
210+
}, Promise.resolve())
211+
.finally(() => {
212+
registryProcess.kill();
213+
secureRegistryProcess.kill();
214+
});
215+
})
207216
.then(
208217
() => {
209-
registryProcess.kill();
210-
secureRegistryProcess.kill();
211-
212218
console.log(colors.green('Done.'));
213219
process.exit(0);
214220
},
@@ -218,9 +224,6 @@ testsToRun
218224
console.error(colors.red(err.message));
219225
console.error(colors.red(err.stack));
220226

221-
registryProcess.kill();
222-
secureRegistryProcess.kill();
223-
224227
if (argv.debug) {
225228
console.log(`Current Directory: ${process.cwd()}`);
226229
console.log('Will loop forever while you debug... CTRL-C to quit.');
@@ -257,3 +260,12 @@ function printFooter(testName: string, startTime: number) {
257260
console.log(colors.green('Last step took ') + colors.bold.blue('' + t) + colors.green('s...'));
258261
console.log('');
259262
}
263+
264+
function findFreePort() {
265+
return new Promise<number>((resolve, reject) => {
266+
const srv = createServer();
267+
srv.once('listening', () => resolve((srv.address() as AddressInfo).port));
268+
srv.once('error', reject);
269+
srv.listen();
270+
});
271+
}

tests/legacy-cli/verdaccio.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ storage: ./storage
33
auth:
44
auth-memory:
55
users: {}
6-
listen: localhost:4873
6+
listen: localhost:${HTTP_PORT}
77
uplinks:
88
npmjs:
99
url: https://registry.npmjs.org/

tests/legacy-cli/verdaccio_auth.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ auth:
55
testing:
66
name: testing
77
password: s3cret
8-
listen: localhost:4876
8+
listen: localhost:${HTTPS_PORT}
99
uplinks:
1010
local:
11-
url: http://localhost:4873
11+
url: http://localhost:${HTTP_PORT}
1212
cache: false
1313
maxage: 20m
1414
max_fails: 32

0 commit comments

Comments
 (0)