Skip to content

Commit 5e3bb40

Browse files
committed
test: use random ports for local verdaccio npm servers
1 parent 736e945 commit 5e3bb40

File tree

4 files changed

+108
-86
lines changed

4 files changed

+108
-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-secure-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-secure-registry');
7278

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

tests/legacy-cli/e2e_runner.ts

+90-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, Server } from 'net';
1213

1314
Error.stackTraceLimit = Infinity;
1415

@@ -122,93 +123,99 @@ 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);
130+
setGlobalVariable('package-secure-registry', 'http://localhost:' + httpsPort);
129131

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-
}
132+
const registryProcess = await createNpmRegistry(httpPort, httpPort);
133+
const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true);
137134

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

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

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-
};
147+
const module = require(absoluteName);
148+
const originalEnvVariables = {
149+
...process.env,
150+
};
155151

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

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);
161+
let clean = true;
162+
let previousDir = null;
177163

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(
164+
return Promise.resolve()
165+
.then(() => printHeader(currentFileName, testIndex))
166+
.then(() => (previousDir = process.cwd()))
167+
.then(() => logStack.push(lastLogger().createChild(currentFileName)))
168+
.then(() => fn(() => (clean = false)))
169+
.then(
189170
() => logStack.pop(),
190171
(err) => {
191172
logStack.pop();
192173
throw err;
193174
},
175+
)
176+
.then(() => console.log('----'))
177+
.then(() => {
178+
// If we're not in a setup, change the directory back to where it was before the test.
179+
// This allows tests to chdir without worrying about keeping the original directory.
180+
if (!allSetups.includes(relativeName) && previousDir) {
181+
process.chdir(previousDir);
182+
183+
// Restore env variables before each test.
184+
console.log(' Restoring original environment variables...');
185+
process.env = originalEnvVariables;
186+
}
187+
})
188+
.then(() => {
189+
// Only clean after a real test, not a setup step. Also skip cleaning if the test
190+
// requested an exception.
191+
if (!allSetups.includes(relativeName) && clean) {
192+
logStack.push(new logging.NullLogger());
193+
return gitClean().then(
194+
() => logStack.pop(),
195+
(err) => {
196+
logStack.pop();
197+
throw err;
198+
},
199+
);
200+
}
201+
})
202+
.then(
203+
() => printFooter(currentFileName, start),
204+
(err) => {
205+
printFooter(currentFileName, start);
206+
console.error(err);
207+
throw err;
208+
},
194209
);
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())
210+
});
211+
}, Promise.resolve())
212+
.finally(() => {
213+
registryProcess.kill();
214+
secureRegistryProcess.kill();
215+
});
216+
})
207217
.then(
208218
() => {
209-
registryProcess.kill();
210-
secureRegistryProcess.kill();
211-
212219
console.log(colors.green('Done.'));
213220
process.exit(0);
214221
},
@@ -218,9 +225,6 @@ testsToRun
218225
console.error(colors.red(err.message));
219226
console.error(colors.red(err.stack));
220227

221-
registryProcess.kill();
222-
secureRegistryProcess.kill();
223-
224228
if (argv.debug) {
225229
console.log(`Current Directory: ${process.cwd()}`);
226230
console.log('Will loop forever while you debug... CTRL-C to quit.');
@@ -257,3 +261,15 @@ function printFooter(testName: string, startTime: number) {
257261
console.log(colors.green('Last step took ') + colors.bold.blue('' + t) + colors.green('s...'));
258262
console.log('');
259263
}
264+
265+
function findFreePort() {
266+
return new Promise<number>((resolve, reject) => {
267+
const srv = createServer();
268+
srv.once('listening', () => {
269+
const port = (srv.address() as AddressInfo).port;
270+
srv.close((e) => (e ? reject(e) : resolve(port)));
271+
});
272+
srv.once('error', (e) => srv.close(() => reject(e)));
273+
srv.listen();
274+
});
275+
}

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)