-
Notifications
You must be signed in to change notification settings - Fork 342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow port option when run with target chromium #3188
base: master
Are you sure you want to change the base?
Changes from all commits
219b32b
01d737c
da9dd76
8b9a5e4
9eed3b6
5355435
62628b4
c8cae1e
7c1eeda
d0cdd3e
bd410f4
41ad45a
1f9754f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,52 @@ | ||||||||
import { createServer } from 'node:http'; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We don't really need http capabilities, |
||||||||
|
||||||||
import { UnusablePortError } from '../errors.js'; | ||||||||
|
||||||||
/** | ||||||||
* Determine if a port is available | ||||||||
* @param {number} port Port to test | ||||||||
* */ | ||||||||
async function isPortAvailable(port) { | ||||||||
return new Promise((resolve) => { | ||||||||
const server = createServer(); | ||||||||
server.once('listening', () => { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For simplicity, you could also consider passing the callback as a parameter to the |
||||||||
server.close(() => resolve(true)); | ||||||||
}); | ||||||||
server.once('error', () => resolve(false)); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This assumes that the only error is that the port is in use (in which case |
||||||||
server.listen(port); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
By default, To avoid these issues, explicitly pass in the localhost IP, i.e. |
||||||||
}); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Validate that requested port is a valid port | ||||||||
* @param {number} port Debugging port | ||||||||
* @returns {boolean} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This To avoid the strange "true / false / Error` tristate, you could consider dropping the boolean return values and just have error vs non-Error. // Raises an error if the port is invalid for any reason
await ensureValidPort(port); Another option is to have a boolean return value (port available or not) and throw one error ( |
||||||||
*/ | ||||||||
function isPortValid(port) { | ||||||||
if (!port) { | ||||||||
return false; | ||||||||
} | ||||||||
Comment on lines
+26
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The caller is expected to pass a port, this branch is unreachable. For simplicity let's just drop it (an error would be raised if |
||||||||
if (Number.isNaN(port) || !Number.isInteger(port)) { | ||||||||
throw new UnusablePortError(`Port provided is not an integer (${port})`); | ||||||||
} | ||||||||
if (port < 0 || port > 65535) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
throw new UnusablePortError(`Invalid port number: ${port}`); | ||||||||
} | ||||||||
|
||||||||
return true; | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Validate user-supplied port to ensure it is suitable for use | ||||||||
* @param {number} port User-supplied port request | ||||||||
* @param {string} chromiumBinary Chromium binary being requested for launch | ||||||||
* @param {string[]} chromeFlags Array of flags requested for launch | ||||||||
Comment on lines
+42
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
These parameters don't exist. |
||||||||
* @returns {boolean} Whether requested port is usable | ||||||||
*/ | ||||||||
export async function validatePort(port) { | ||||||||
if (!isPortValid(port)) { | ||||||||
return false; | ||||||||
} | ||||||||
|
||||||||
return isPortAvailable(port); | ||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,6 +193,15 @@ export class StubChildProcess extends EventEmitter { | |
stderr = new EventEmitter(); | ||
stdout = new EventEmitter(); | ||
kill = sinon.spy(() => {}); | ||
|
||
constructor(params = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop this all - it is not needed by |
||
super(); | ||
|
||
// mimic chrome-launch and set a port property, defaulting to a random port | ||
this.port = params.chromiumPort | ||
? params.chromiumPort | ||
: getRandomInt(1024, 65536); | ||
} | ||
} | ||
|
||
export function createFakeProcess() { | ||
|
@@ -336,3 +345,9 @@ export function mockModule({ | |
export function resetMockModules() { | ||
td.reset(); | ||
} | ||
|
||
export function getRandomInt(min, max) { | ||
const _min = Math.ceil(min); | ||
const _max = Math.floor(max); | ||
return Math.floor(Math.random() * (_max - _min) + _min); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -23,7 +23,7 @@ import isDirectory from '../../../src/util/is-directory.js'; | |||||||||
|
||||||||||
function prepareExtensionRunnerParams({ params } = {}) { | ||||||||||
const fakeChromeInstance = { | ||||||||||
process: new StubChildProcess(), | ||||||||||
process: new StubChildProcess(params), | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to more realistically mimic the result of chromium-launch, then you can assign the result to Here is the type from chrome-launcher: https://github.com/GoogleChrome/chrome-launcher/blob/v1.1.1/src/chrome-launcher.ts#L85 |
||||||||||
kill: sinon.spy(async () => {}), | ||||||||||
}; | ||||||||||
const runnerParams = { | ||||||||||
|
@@ -615,6 +615,36 @@ describe('util/extension-runners/chromium', async () => { | |||||||||
}), | ||||||||||
); | ||||||||||
|
||||||||||
it('does pass port to chrome', async () => { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This unit test only tests the good-weather behavior. You should also test the bad weather behavior, i.e. the error conditions. Here are the relevant cases:
|
||||||||||
const port = 9222; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This unit test will fail if 9222 is used at any point. You should choose a free port here. Note that we already have a utility to find a free port, at Line 233 in 1c01518
|
||||||||||
const { params } = prepareExtensionRunnerParams({ | ||||||||||
params: { chromiumPort: port }, | ||||||||||
}); | ||||||||||
|
||||||||||
const runnerInstance = new ChromiumExtensionRunner(params); | ||||||||||
await runnerInstance.run(); | ||||||||||
|
||||||||||
sinon.assert.calledOnce(params.chromiumLaunch); | ||||||||||
sinon.assert.calledWithMatch(params.chromiumLaunch, { | ||||||||||
port, | ||||||||||
}); | ||||||||||
assert.isDefined( | ||||||||||
runnerInstance.chromiumInstance, | ||||||||||
'returned process instance', | ||||||||||
); | ||||||||||
assert.isDefined( | ||||||||||
runnerInstance.chromiumInstance.process.port, | ||||||||||
'process instance has port value', | ||||||||||
); | ||||||||||
Comment on lines
+635
to
+638
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This assertion is not useful. It merely tests the behavior of the internal stub logic. |
||||||||||
assert.equal( | ||||||||||
runnerInstance.chromiumInstance.process.port, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||
port, | ||||||||||
'process instance configured with correct port', | ||||||||||
); | ||||||||||
|
||||||||||
await runnerInstance.exit(); | ||||||||||
}); | ||||||||||
|
||||||||||
describe('reloadAllExtensions', () => { | ||||||||||
let runnerInstance; | ||||||||||
let wsClient; | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you intentionally excluding
--chromium-port=0
here? The validation helpers that you have added are not 100% correct when0
is passed.The expected behavior when
0
is passed is to select a random port (which chrome-launcher does indeed).