From ee0aa71e7b35711740f48b1db17502f87a2786fc Mon Sep 17 00:00:00 2001 From: Matt Fellows Date: Sat, 9 Feb 2019 23:33:17 +1100 Subject: [PATCH] fix(port-check): make port check more resilient. Fixes #49 --- src/common/net.spec.ts | 18 +++++------------- src/common/net.ts | 29 ++++++++++++++++++++++------- src/pact.ts | 2 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/common/net.spec.ts b/src/common/net.spec.ts index 6c3b4881a..6f6edba45 100644 --- a/src/common/net.spec.ts +++ b/src/common/net.spec.ts @@ -8,7 +8,7 @@ const expect = chai.expect; chai.use(chaiAsPromised); describe("Net", () => { - const port = 1234; + const port = 4567; const host = "0.0.0.0"; const specialPort = process.platform.match("win") ? -1 : 80; @@ -21,22 +21,14 @@ describe("Net", () => { context("when the port is available", () => { it("should return a fulfilled promise", () => { - expect(isPortAvailable(port, host)).to.eventually.be.fulfilled; + expect(isPortAvailable(port + 1, host)).to.eventually.be.fulfilled; }); }); context("when the port is unavailable", () => { - it("should return a rejected promise", done => { - createServer(port).then((server: { close(): any }) => { - isPortAvailable(port, host).then( - () => { - server.close(); - done(new Error(`Port ${port} should not be available`)); - }, - (e: any) => { - done(); - } - ); + it("should return a rejected promise", () => { + createServer(port).then((_: { close(): any }) => { + expect(isPortAvailable(port, host)).to.eventually.be.rejected; }); }); }); diff --git a/src/common/net.ts b/src/common/net.ts index 6cfcc3520..02c66fb03 100644 --- a/src/common/net.ts +++ b/src/common/net.ts @@ -5,16 +5,31 @@ */ import * as net from "net"; +import { Promise as bluebird } from "bluebird"; -const isPortAvailable = (port: number, host: string): Promise => { +const isPortAvailable = (port: number, host: string): Promise => + Promise.resolve(bluebird.each([host, "127.0.0.1", "localhost", "0.0.0.0"], h => + portCheck(port, h) + ) + .then(() => Promise.resolve(undefined)) + .catch(e => Promise.reject(e))); + +const portCheck = (port: number, host: string): Promise => { return new Promise((resolve, reject) => { - const server: any = net.createServer() + const server: any = net + .createServer() .listen({ port, host, exclusive: true }) - .on("error", (e: any) => (e.code === "EADDRINUSE" ? reject(new Error(`Port ${port} is unavailable`)) : reject(e))) - .on("listening", () => server.once("close", () => resolve()).close()); + .on("error", (e: any) => { + if (e.code === "EADDRINUSE") { + reject(new Error(`Port ${port} is unavailable`)) + } else { + reject(e); + } + }) + .on("listening", () => { + server.once("close", () => resolve()).close(); + }); }); }; -export { - isPortAvailable, -}; +export { isPortAvailable, portCheck }; diff --git a/src/pact.ts b/src/pact.ts index e1ba600a6..32836f161 100644 --- a/src/pact.ts +++ b/src/pact.ts @@ -92,7 +92,7 @@ export class Pact { public setup(): Promise { return isPortAvailable(this.opts.port, this.opts.host) // Need to wrap it this way until we remove q.Promise from pact-node - .then(() => new Promise((resolve, reject) => this.server.start().then(() => resolve(), () => reject()))); + .then(() => new Promise((resolve, reject) => this.server.start().then(() => resolve(), (e: any) => reject(e)))) } /**