mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-22 17:47:53 +00:00
Wait for port to be freed before continuing
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"cross-spawn": "^5.0.1",
|
"cross-spawn": "^5.0.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
|
"portastic": "^1.0.1",
|
||||||
"rimraf": "^2.5.4",
|
"rimraf": "^2.5.4",
|
||||||
"selenium-standalone": "^5.9.0",
|
"selenium-standalone": "^5.9.0",
|
||||||
"tree-kill": "^1.1.0",
|
"tree-kill": "^1.1.0",
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import * as childProcess from 'child_process';
|
import * as childProcess from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as readline from 'readline';
|
import * as readline from 'readline';
|
||||||
|
import { waitUntilPortState } from './ports';
|
||||||
const treeKill = require('tree-kill');
|
const treeKill = require('tree-kill');
|
||||||
const crossSpawn: typeof childProcess.spawn = require('cross-spawn');
|
const crossSpawn: typeof childProcess.spawn = require('cross-spawn');
|
||||||
|
const defaultPort = 5000;
|
||||||
|
|
||||||
export const defaultUrl = 'http://localhost:5000';
|
export const defaultUrl = `http://localhost:${ defaultPort }`;
|
||||||
|
|
||||||
export enum AspNetCoreEnviroment {
|
export enum AspNetCoreEnviroment {
|
||||||
development,
|
development,
|
||||||
@@ -50,7 +52,7 @@ export class AspNetProcess {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Ensure the process isn't orphaned even if Node crashes before we're disposed
|
// Ensure the process isn't orphaned even if Node crashes before we're disposed
|
||||||
process.on('exit', () => this._killProcessSync());
|
process.on('exit', () => this._killAspNetProcess());
|
||||||
|
|
||||||
// Also track whether it exited on its own already
|
// Also track whether it exited on its own already
|
||||||
this._process.on('exit', () => {
|
this._process.on('exit', () => {
|
||||||
@@ -74,7 +76,7 @@ export class AspNetProcess {
|
|||||||
|
|
||||||
public dispose(): Promise<any> {
|
public dispose(): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._killProcessSync(err => {
|
this._killAspNetProcess(err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
@@ -84,11 +86,29 @@ export class AspNetProcess {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _killProcessSync(callback?: (err: any) => void) {
|
private _killAspNetProcess(callback?: (err: any) => void) {
|
||||||
|
callback = callback || (() => {});
|
||||||
if (!this._processHasExited) {
|
if (!this._processHasExited) {
|
||||||
// It's important to kill the whole tree, because 'dotnet run' launches a separate 'dotnet exec'
|
// It's important to kill the whole tree, because 'dotnet run' launches a separate 'dotnet exec'
|
||||||
// child process that would otherwise be left running
|
// child process that would otherwise be left running
|
||||||
treeKill(this._process.pid, 'SIGINT', callback);
|
treeKill(this._process.pid, 'SIGINT', err => {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
// It's not enough just to send a SIGINT to ASP.NET. It will stay open for a moment, completing
|
||||||
|
// any outstanding requests. We have to wait for it really to be gone before continuing, otherwise
|
||||||
|
// the next test might be unable to start because of the port still being in use.
|
||||||
|
console.log(`Waiting until port ${ defaultPort } is closed...`);
|
||||||
|
waitUntilPortState(defaultPort, /* isOpen */ true, /* timeoutMs */ 15000, err => {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
console.log(`Port ${ defaultPort } is now closed`);
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
test/templates/util/ports.ts
Normal file
23
test/templates/util/ports.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import * as portastic from 'portastic';
|
||||||
|
const pollInterval = 500;
|
||||||
|
|
||||||
|
export function waitUntilPortState(port: number, isOpen: boolean, timeoutMs: number, callback: (err: any) => void) {
|
||||||
|
if (!(timeoutMs > 0)) {
|
||||||
|
throw new Error(`Timed out after ${ timeoutMs }ms waiting for port ${ port } to become ${ isOpen ? 'free' : 'in use' }`);
|
||||||
|
}
|
||||||
|
|
||||||
|
portastic.test(port).then(
|
||||||
|
actualIsOpenState => {
|
||||||
|
if (actualIsOpenState === isOpen) {
|
||||||
|
// Desired state is reached
|
||||||
|
callback(null);
|
||||||
|
} else {
|
||||||
|
// Wait longer
|
||||||
|
setTimeout(() => {
|
||||||
|
waitUntilPortState(port, isOpen, timeoutMs - pollInterval, callback);
|
||||||
|
}, pollInterval);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user