diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 1e660b8de77056..080d52123523e2 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -13,67 +13,67 @@ parserOptions: rules: # Possible Errors # http://eslint.org/docs/rules/#possible-errors - comma-dangle: [2, only-multiline] - no-control-regex: 2 - no-debugger: 2 - no-dupe-args: 2 - no-dupe-keys: 2 - no-duplicate-case: 2 - no-empty-character-class: 2 - no-ex-assign: 2 - no-extra-boolean-cast: 2 - no-extra-parens: [2, functions] - no-extra-semi: 2 - no-func-assign: 2 - no-invalid-regexp: 2 - no-irregular-whitespace: 2 - no-obj-calls: 2 - no-proto: 2 - no-template-curly-in-string: 2 - no-unexpected-multiline: 2 - no-unreachable: 2 - no-unsafe-negation: 2 - use-isnan: 2 - valid-typeof: 2 + comma-dangle: [error, only-multiline] + no-control-regex: error + no-debugger: error + no-dupe-args: error + no-dupe-keys: error + no-duplicate-case: error + no-empty-character-class: error + no-ex-assign: error + no-extra-boolean-cast: error + no-extra-parens: [error, functions] + no-extra-semi: error + no-func-assign: error + no-invalid-regexp: error + no-irregular-whitespace: error + no-obj-calls: error + no-proto: error + no-template-curly-in-string: error + no-unexpected-multiline: error + no-unreachable: error + no-unsafe-negation: error + use-isnan: error + valid-typeof: error # Best Practices # http://eslint.org/docs/rules/#best-practices - dot-location: [2, property] - no-fallthrough: 2 - no-global-assign: 2 - no-multi-spaces: [2, {ignoreEOLComments: true}] - no-octal: 2 - no-redeclare: 2 - no-self-assign: 2 - no-unused-labels: 2 - no-useless-call: 2 - no-useless-concat: 2 - no-useless-escape: 2 - no-useless-return: 2 - no-void: 2 - no-with: 2 + dot-location: [error, property] + no-fallthrough: error + no-global-assign: error + no-multi-spaces: [error, {ignoreEOLComments: true}] + no-octal: error + no-redeclare: error + no-self-assign: error + no-unused-labels: error + no-useless-call: error + no-useless-concat: error + no-useless-escape: error + no-useless-return: error + no-void: error + no-with: error # Strict Mode # http://eslint.org/docs/rules/#strict-mode - strict: [2, global] + strict: [error, global] # Variables # http://eslint.org/docs/rules/#variables - no-delete-var: 2 - no-undef: 2 - no-unused-vars: [2, {args: none}] - no-use-before-define: [2, {classes: true, - functions: false, - variables: false}] + no-delete-var: error + no-undef: error + no-unused-vars: [error, {args: none}] + no-use-before-define: [error, {classes: true, + functions: false, + variables: false}] # Node.js and CommonJS # http://eslint.org/docs/rules/#nodejs-and-commonjs - no-mixed-requires: 2 - no-new-require: 2 - no-path-concat: 2 - no-restricted-modules: [2, sys, _linklist] + no-mixed-requires: error + no-new-require: error + no-path-concat: error + no-restricted-modules: [error, sys, _linklist] no-restricted-properties: - - 2 + - error - object: assert property: deepEqual message: Use assert.deepStrictEqual(). @@ -90,33 +90,39 @@ rules: # Stylistic Issues # http://eslint.org/docs/rules/#stylistic-issues - block-spacing: 2 - brace-style: [2, 1tbs, {allowSingleLine: true}] - comma-spacing: 2 - comma-style: 2 - computed-property-spacing: 2 - eol-last: 2 - func-call-spacing: 2 - func-name-matching: 2 - func-style: [2, declaration, {allowArrowFunctions: true}] - indent: [2, 2, {ArrayExpression: first, - CallExpression: {arguments: first}, - FunctionDeclaration: {parameters: first}, - FunctionExpression: {parameters: first}, - MemberExpression: off, - ObjectExpression: first, - SwitchCase: 1}] - key-spacing: [2, {mode: minimum}] - keyword-spacing: 2 - linebreak-style: [2, unix] - max-len: [2, {code: 80, - ignoreRegExpLiterals: true, - ignoreUrls: true, - tabWidth: 2}] - new-parens: 2 - no-mixed-spaces-and-tabs: 2 - no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] - no-restricted-syntax: [2, { + block-spacing: error + brace-style: [error, 1tbs, {allowSingleLine: true}] + comma-spacing: error + comma-style: error + computed-property-spacing: error + eol-last: error + func-call-spacing: error + func-name-matching: error + func-style: [error, declaration, {allowArrowFunctions: true}] + indent: [error, 2, {ArrayExpression: first, + CallExpression: {arguments: first}, + FunctionDeclaration: {parameters: first}, + FunctionExpression: {parameters: first}, + MemberExpression: off, + ObjectExpression: first, + SwitchCase: 1}] + key-spacing: [error, {mode: minimum}] + keyword-spacing: error + linebreak-style: [error, unix] + max-len: [error, {code: 80, + ignoreRegExpLiterals: true, + ignoreUrls: true, + tabWidth: 2}] + new-parens: error + no-mixed-spaces-and-tabs: error + no-multiple-empty-lines: [error, {max: 2, maxEOF: 0, maxBOF: 0}] + no-restricted-syntax: [error, { + selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.1.type='Literal']:not([arguments.1.regex])", + message: "use a regular expression for second argument of assert.throws()" + }, { + selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.length<2]", + message: "assert.throws() must be invoked with at least two arguments." + }, { selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]", message: "setTimeout() must be invoked with at least two arguments." }, { @@ -129,39 +135,38 @@ rules: selector: "CallExpression[callee.object.name='assert'][callee.property.name='fail'][arguments.length=1]", message: "assert.fail() message should be third argument" }] - no-tabs: 2 - no-trailing-spaces: 2 - operator-linebreak: [2, after, {overrides: {'?': ignore, ':': ignore}}] - quotes: [2, single, avoid-escape] - semi: 2 - semi-spacing: 2 - space-before-blocks: [2, always] - space-before-function-paren: [2, { + no-tabs: error + no-trailing-spaces: error + operator-linebreak: [error, after, {overrides: {'?': ignore, ':': ignore}}] + quotes: [error, single, avoid-escape] + semi: error + semi-spacing: error + space-before-blocks: [error, always] + space-before-function-paren: [error, { "anonymous": "never", "named": "never", "asyncArrow": "always" }] - space-in-parens: [2, never] - space-infix-ops: 2 - space-unary-ops: 2 + space-in-parens: [error, never] + space-infix-ops: error + space-unary-ops: error # ECMAScript 6 # http://eslint.org/docs/rules/#ecmascript-6 - arrow-parens: [2, always] - arrow-spacing: [2, {before: true, after: true}] - constructor-super: 2 - no-class-assign: 2 - no-confusing-arrow: 2 - no-const-assign: 2 - no-dupe-class-members: 2 - no-new-symbol: 2 - no-this-before-super: 2 - prefer-const: [2, {ignoreReadBeforeAssign: true}] - rest-spread-spacing: 2 - template-curly-spacing: 2 + arrow-parens: [error, always] + arrow-spacing: [error, {before: true, after: true}] + constructor-super: error + no-class-assign: error + no-confusing-arrow: error + no-const-assign: error + no-dupe-class-members: error + no-new-symbol: error + no-this-before-super: error + prefer-const: [error, {ignoreReadBeforeAssign: true}] + rest-spread-spacing: error + template-curly-spacing: error # Custom rules in tools/eslint-rules - assert-throws-arguments: [2, { requireTwo: true }] # Global scoped method and vars globals: diff --git a/BUILDING.md b/BUILDING.md index f000720c3f13ae..e6579f3e4ef2c1 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -94,6 +94,8 @@ More Developer Tools...`. This step will install `clang`, `clang++`, and * You may want to setup [firewall rules](tools/macosx-firewall.sh) to avoid popups asking to accept incoming network connections when running tests: +If the path to your build directory contains a space, the build will likely fail. + ```console $ sudo ./tools/macosx-firewall.sh ``` @@ -127,6 +129,25 @@ To run the tests: $ make test ``` +To run the tests and generate code coverage reports: + +```console +$ ./configure --coverage +$ make coverage +``` + +This will generate coverage reports for both JavaScript and C++ tests (if you +only want to run the JavaScript tests then you do not need to run the first +command `./configure --coverage`). + +The `make coverage` command downloads some tools to the project root directory +and overwrites the `lib/` directory. To clean up after generating the coverage +reports: + +```console +make coverage-clean +``` + To build the documentation: This will build Node.js first (if necessary) and then use it to build the docs: @@ -135,7 +156,7 @@ This will build Node.js first (if necessary) and then use it to build the docs: $ make doc ``` -If you have an existing Node.js you can build just the docs with: +If you have an existing Node.js build, you can build just the docs with: ```console $ NODE=/path/to/node make doc-only @@ -174,6 +195,8 @@ Prerequisites: [Git for Windows](http://git-scm.com/download/win) includes Git Bash and tools which can be included in the global `PATH`. +If the path to your build directory contains a space, the build will likely fail. + ```console > .\vcbuild nosign ``` diff --git a/CHANGELOG.md b/CHANGELOG.md index b159dc31727017..3652dd6a5e8d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,8 @@ release. -6.11.3
+6.11.4
+6.11.3
6.11.2
6.11.1
6.11.0
diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 116624a79aefd0..5aa0fb49cd68a6 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -8,7 +8,7 @@ - [Internal vs. Public API](#internal-vs-public-api) - [Breaking Changes](#breaking-changes) - [Deprecations](#deprecations) - - [Involving the CTC](#involving-the-ctc) + - [Involving the TSC](#involving-the-TSC) * [Landing Pull Requests](#landing-pull-requests) - [Technical HOWTO](#technical-howto) - [I Just Made a Mistake](#i-just-made-a-mistake) @@ -30,7 +30,7 @@ pull requests to the Node.js project. Collaborators should feel free to take full responsibility for managing issues and pull requests they feel qualified to handle, as long as this is done while being mindful of these guidelines, the -opinions of other Collaborators and guidance of the CTC. +opinions of other Collaborators and guidance of the TSC. Collaborators may **close** any issue or pull request they believe is not relevant for the future of the Node.js project. Where this is @@ -46,7 +46,7 @@ necessary. All modifications to the Node.js code and documentation should be performed via GitHub pull requests, including modifications by -Collaborators and CTC members. +Collaborators and TSC members. All pull requests must be reviewed and accepted by a Collaborator with sufficient expertise who is able to take full responsibility for the @@ -70,16 +70,16 @@ For non-breaking changes, if there is no disagreement amongst Collaborators, a pull request may be landed given appropriate review. Where there is discussion amongst Collaborators, consensus should be sought if possible. The lack of consensus may indicate the need to -elevate discussion to the CTC for resolution (see below). +elevate discussion to the TSC for resolution (see below). Breaking changes (that is, pull requests that require an increase in the major version number, known as `semver-major` changes) must be -elevated for review by the CTC. This does not necessarily mean that the -PR must be put onto the CTC meeting agenda. If multiple CTC members +elevated for review by the TSC. This does not necessarily mean that the +PR must be put onto the TSC meeting agenda. If multiple TSC members approve (`LGTM`) the PR and no Collaborators oppose the PR, it can be -landed. Where there is disagreement among CTC members or objections +landed. Where there is disagreement among TSC members or objections from one or more Collaborators, `semver-major` pull requests should be -put on the CTC meeting agenda. +put on the TSC meeting agenda. All bugfixes require a test case which demonstrates the defect. The test should *fail* before the change, and *pass* after the change. @@ -150,7 +150,7 @@ Exception to each of these points can be made if use or behavior of a given internal API can be demonstrated to be sufficiently relied upon by the Node.js ecosystem such that any changes would cause too much breakage. The threshold for what qualifies as "too much breakage" is to be decided on a case-by-case -basis by the CTC. +basis by the TSC. If it is determined that a currently undocumented object, property, method, argument, or event *should* be documented, then a pull request adding the @@ -171,7 +171,7 @@ making and reviewing such changes. Before landing such commits, an effort must be made to determine the potential impact of the change in the ecosystem by analyzing current use and by validating such changes through ecosystem testing using the [Canary in the Goldmine](https://github.com/nodejs/citgm) -tool. If a change cannot be made without ecosystem breakage, then CTC review is +tool. If a change cannot be made without ecosystem breakage, then TSC review is required before landing the change as anything less than semver-major. If a determination is made that a particular internal API (for instance, an @@ -183,7 +183,7 @@ breaking changes are made. ### Breaking Changes Backwards-incompatible changes may land on the master branch at any time after -sufficient review by collaborators and approval of at least two CTC members. +sufficient review by collaborators and approval of at least two TSC members. Examples of breaking changes include, but are not necessarily limited to, removal or redefinition of existing API arguments, changing return values @@ -209,7 +209,7 @@ Exception to this rule is given in the following cases: Such changes *must* be handled as semver-major changes but MAY be landed without a [Deprecation cycle](#deprecation-cycle). -From time-to-time, in particularly exceptional cases, the CTC may be asked to +From time-to-time, in particularly exceptional cases, the TSC may be asked to consider and approve additional exceptions to this rule. Purely additive changes (e.g. adding new events to EventEmitter @@ -244,7 +244,7 @@ Specifically: * Resolving critical security issues. * Fixing a critical bug (e.g. fixing a memory leak) requires a breaking change. - * There is CTC consensus that the change is required. + * There is TSC consensus that the change is required. * If a breaking commit does accidentally land in a Current or LTS branch, an attempt to fix the issue will be made before the next release; If no fix is provided then the commit will be reverted. @@ -263,6 +263,32 @@ multiple commits. Commit metadata and the reason for the revert should be appended. Commit message rules about line length and subsystem can be ignored. A Pull Request should be raised and approved like any other change. +### Introducing New Modules + +Semver-minor commits that introduce new core modules should be treated with +extra care. + +The name of the new core module should not conflict with any existing +module in the ecosystem unless a written agreement with the owner of those +modules is reached to transfer ownership. + +If the new module name is free, a Collaborator should register a placeholder +in the module registry as soon as possible, linking to the pull request that +introduces the new core module. + +Pull requests introducing new core modules: + +* Must be left open for at least one week for review. +* Must be labeled using the `ctc-review` label. +* Must have signoff from at least two CTC members. + +New core modules must be landed with a [Stability Index][] of Experimental, +and must remain Experimental until a semver-major release. + +For new modules that involve significant effort, non-trivial additions to +Node.js or significant new capabilities, an [Enhancement Proposal][] is +recommended but not required. + ### Deprecations Deprecation refers to the identification of Public APIs that should no longer @@ -294,7 +320,7 @@ operation of running code and therefore should not be viewed as breaking changes. Runtime Deprecations and End-of-life APIs (internal or public) *must* be -handled as semver-major changes unless there is CTC consensus to land the +handled as semver-major changes unless there is TSC consensus to land the deprecation as a semver-minor. All Documentation-Only and Runtime deprecations will be assigned a unique @@ -320,10 +346,10 @@ request adding the deprecation lands in master). All deprecations included in a Node.js release should be listed prominently in the "Notable Changes" section of the release notes. -### Involving the CTC +### Involving the TSC -Collaborators may opt to elevate pull requests or issues to the CTC for -discussion by assigning the `ctc-review` label. This should be done +Collaborators may opt to elevate pull requests or issues to the TSC for +discussion by assigning the `tsc-review` label. This should be done where a pull request: - has a significant impact on the codebase, @@ -331,7 +357,7 @@ where a pull request: - has failed to reach consensus amongst the Collaborators who are actively participating in the discussion. -The CTC should serve as the final arbiter where required. +The TSC should serve as the final arbiter where required. ## Landing Pull Requests @@ -512,9 +538,36 @@ your pull request shows the purple merged status then you should still add the "Landed in .." comment if you added multiple commits. +### Troubleshooting + +Sometimes, when running `git push upstream master`, you may get an error message +like this: + +```console +To https://github.com/nodejs/node + ! [rejected] master -> master (fetch first) +error: failed to push some refs to 'https://github.com/nodejs/node' +hint: Updates were rejected because the remote contains work that you do +hint: not have locally. This is usually caused by another repository pushing +hint: to the same ref. You may want to first integrate the remote changes +hint: (e.g., 'git pull ...') before pushing again. +hint: See the 'Note about fast-forwards' in 'git push --help' for details. +``` + +That means a commit has landed since your last rebase against `upstream/master`. +To fix this, fetch, rebase, run the tests again (to make sure no interactions +between your changes and the new changes cause any problems), and push again: + +```sh +git fetch upstream +git rebase upstream/master +make -j4 test +git push upstream master +``` + ### I Just Made a Mistake -* Ping a CTC member. +* Ping a TSC member. * `#node-dev` on freenode * With `git`, there's a way to override remote trees by force pushing (`git push -f`). This should generally be seen as forbidden (since @@ -543,9 +596,9 @@ Once a Current branch enters LTS, changes in that branch are limited to bug fixes, security updates, possible npm updates, documentation updates, and certain performance improvements that can be demonstrated to not break existing applications. Semver-minor changes are only permitted if required for bug fixes -and then only on a case-by-case basis with LTS WG and possibly Core Technical -Committee (CTC) review. Semver-major changes are permitted only if required for -security related fixes. +and then only on a case-by-case basis with LTS WG and possibly Technical +Steering Committee (TSC) review. Semver-major changes are permitted only if +required for security related fixes. Once a Current branch moves into Maintenance mode, only **critical** bugs, **critical** security fixes, and documentation updates will be permitted. @@ -553,7 +606,7 @@ Once a Current branch moves into Maintenance mode, only **critical** bugs, #### Landing semver-minor commits in LTS The default policy is to not land semver-minor or higher commits in any LTS -branch. However, the LTS WG or CTC can evaluate any individual semver-minor +branch. However, the LTS WG or TSC can evaluate any individual semver-minor commit and decide whether a special exception ought to be made. It is expected that such exceptions would be evaluated, in part, on the scope and impact of the changes on the code, the risk to ecosystem stability @@ -563,7 +616,7 @@ commit will have for the ecosystem. Any collaborator who feels a semver-minor commit should be landed in an LTS branch should attach the `lts-agenda` label to the pull request. The LTS WG will discuss the issue and, if necessary, will escalate the issue up to the -CTC for further discussion. +TSC for further discussion. #### How are LTS Branches Managed? @@ -615,3 +668,5 @@ release. This process of making a release will be a collaboration between the LTS working group and the Release team. [backporting guide]: doc/guides/backporting-to-release-lines.md +[Stability Index]: https://github.com/nodejs/node/pull/doc/api/documentation.md#stability-index +[Enhancement Proposal]: https://github.com/nodejs/node-eps diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c012c2258ca84c..b69f2e0708fa9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -176,7 +176,8 @@ Running `make test`/`vcbuild test` will run the linter as well unless one or more tests fail. If you want to run the linter without running tests, use -`make lint`/`vcbuild lint`. +`make lint`/`vcbuild lint`. It will run both JavaScript linting and +C++ linting. If you are updating tests and just want to run a single test to check it, you can use this syntax to run it exactly as the test harness would: diff --git a/GOVERNANCE.md b/GOVERNANCE.md index d7d60671ac1ad2..20b75bd9718be2 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,17 +1,30 @@ # Node.js Project Governance -The Node.js project is governed by its Collaborators, including a Core Technical -Committee (CTC) which is responsible for high-level guidance of the project. +The Node.js project is governed by its Collaborators, including a Technical +Steering Committee (TSC) which is responsible for high-level guidance of the +project. ## Collaborators The [nodejs/node](https://github.com/nodejs/node) GitHub repository is -maintained by Collaborators who are added by the CTC on an ongoing basis. +maintained by Collaborators who are added by the TSC on an ongoing basis. -Individuals identified by the CTC as making significant and valuable -contributions are made Collaborators and given commit access to the project. If -you make a significant contribution and are not considered for commit access, -log an issue or contact a CTC member directly. +Individuals identified by the TSC as making significant and valuable +contributions across any Node.js repository may be made Collaborators and given +commit access to the project. Activities taken into consideration include (but +are not limited to) the quality of: + +* code commits and pull requests +* documentation commits and pull requests +* comments on issues and pull requests +* contributions to the Node.js website +* assistance provided to end users and novice contributors +* participation in Working Groups +* other participation in the wider Node.js community + +If individuals making valuable contributions do not believe they have been +considered for commit access, they may log an issue or contact a TSC member +directly. Modifications of the contents of the nodejs/node repository are made on a collaborative basis. Anybody with a GitHub account may propose a @@ -28,13 +41,13 @@ be accepted unless: * Discussions and/or additional changes result in no Collaborators objecting to the change. Previously-objecting Collaborators do not necessarily have to sign-off on the change, but they should not be opposed to it. -* The change is escalated to the CTC and the CTC votes to approve the change. +* The change is escalated to the TSC and the TSC votes to approve the change. This should only happen if disagreements between Collaborators cannot be resolved through discussion. Collaborators may opt to elevate significant or controversial modifications to -the CTC by assigning the `ctc-review` label to a pull request or issue. The -CTC should serve as the final arbiter where required. +the TSC by assigning the `tsc-review` label to a pull request or issue. The +TSC should serve as the final arbiter where required. * [Current list of Collaborators](./README.md#current-project-team-members) * [A guide for Collaborators](./COLLABORATOR_GUIDE.md) @@ -49,13 +62,13 @@ Typical activities of a Collaborator include: * participation in working groups * merging pull requests -The CTC periodically reviews the Collaborator list to identify inactive +The TSC periodically reviews the Collaborator list to identify inactive Collaborators. Past Collaborators are typically given _Emeritus_ status. Emeriti -may request that the CTC restore them to active status. +may request that the TSC restore them to active status. -## Core Technical Committee +## Technical Steering Committee -The Core Technical Committee (CTC) has final authority over this project +The Technical Steering Committee (TSC) has final authority over this project including: * Technical direction @@ -65,59 +78,19 @@ including: * Conduct guidelines * Maintaining the list of additional Collaborators -* [Current list of CTC members](./README.md#current-project-team-members) - -## CTC Membership - -CTC seats are not time-limited. There is no fixed size of the CTC. The CTC -should be of such a size as to ensure adequate coverage of important areas of -expertise balanced with the ability to make decisions efficiently. - -There is no specific set of requirements or qualifications for CTC -membership beyond these rules. - -The CTC may add additional members to the CTC by a standard CTC motion. - -When a CTC member's participation in [CTC activities](#ctc-activities) has -become minimal for a sustained period of time, the CTC will request that the -member either indicate an intention to increase participation or voluntarily -resign. +* [Current list of TSC members](./README.md#current-project-team-members) -CTC members may only be removed by voluntary resignation or through a standard -CTC motion. +The operations of the TSC are governed by the [TSC Charter][] as approved by +the Node.js Foundation Board of Directors. -Changes to CTC membership should be posted in the agenda, and may be -suggested as any other agenda item (see [CTC Meetings](#ctc-meetings) below). +### TSC Meetings -No more than 1/3 of the CTC members may be affiliated with the same -employer. If removal or resignation of a CTC member, or a change of -employment by a CTC member, creates a situation where more than 1/3 of -the CTC membership shares an employer, then the situation must be -immediately remedied by the resignation or removal of one or more CTC -members affiliated with the over-represented employer(s). - -### CTC Activities - -Typical activities of a CTC member include: - -* attending the weekly meeting -* commenting on the weekly CTC meeting issue and issues labeled `ctc-review` -* participating in CTC email threads -* volunteering for tasks that arise from CTC meetings and related discussions -* other activities (beyond those typical of Collaborators) that facilitate the - smooth day-to-day operation of the Node.js project - -Note that CTC members are also Collaborators and therefore typically perform -Collaborator activities as well. - -### CTC Meetings - -The CTC meets weekly in a voice conference call. The meeting is run by a -designated meeting chair approved by the CTC. Each meeting is streamed on +The TSC meets regularly in a voice conference call. The meeting is run by a +designated meeting chair approved by the TSC. Each meeting is streamed on YouTube. -Items are added to the CTC agenda which are considered contentious or -are modifications of governance, contribution policy, CTC membership, +Items are added to the TSC agenda which are considered contentious or +are modifications of governance, contribution policy, TSC membership, or release process. The intention of the agenda is not to approve or review all patches. @@ -125,49 +98,40 @@ That should happen continuously on GitHub and be handled by the larger group of Collaborators. Any community member or contributor can ask that something be reviewed -by the CTC by logging a GitHub issue. Any Collaborator, CTC member, or the -meeting chair can bring the issue to the CTC's attention by applying the -`ctc-review` label. If consensus-seeking among CTC members fails for a -particular issue, it may be added to the CTC meeting agenda by adding the -`ctc-agenda` label. - -Prior to each CTC meeting, the meeting chair will share the agenda with -members of the CTC. CTC members can also add items to the agenda at the -beginning of each meeting. The meeting chair and the CTC cannot veto or remove +by the TSC by logging a GitHub issue. Any Collaborator, TSC member, or the +meeting chair can bring the issue to the TSC's attention by applying the +`tsc-review` label. If consensus-seeking among TSC members fails for a +particular issue, it may be added to the TSC meeting agenda by adding the +`tsc-agenda` label. + +Prior to each TSC meeting, the meeting chair will share the agenda with +members of the TSC. TSC members can also add items to the agenda at the +beginning of each meeting. The meeting chair and the TSC cannot veto or remove items. -The CTC may invite persons or representatives from certain projects to -participate in a non-voting capacity. +The TSC may invite additional persons to participate in a non-voting capacity. The meeting chair is responsible for ensuring that minutes are taken and that a pull request with the minutes is submitted after the meeting. Due to the challenges of scheduling a global meeting with participants in -several timezones, the CTC will seek to resolve as many agenda items as possible +several timezones, the TSC will seek to resolve as many agenda items as possible outside of meetings using -[the CTC issue tracker](https://github.com/nodejs/CTC/issues). The process in +[the TSC issue tracker](https://github.com/nodejs/TSC/issues). The process in the issue tracker is: -* A CTC member opens an issue explaining the proposal/issue and @-mentions - @nodejs/ctc. -* After 72 hours, if there are two or more `LGTM`s from other CTC members and no - explicit opposition from other CTC members, then the proposal is approved. -* If there are any CTC members objecting, then a conversation ensues until +* A TSC member opens an issue explaining the proposal/issue and @-mentions + @nodejs/tsc. +* After 72 hours, if there are two or more `LGTM`s from other TSC members and no + explicit opposition from other TSC members, then the proposal is approved. +* If there are any TSC members objecting, then a conversation ensues until either the proposal is dropped or the objecting members are persuaded. If there is an extended impasse, a motion for a vote may be made. ## Consensus Seeking Process -The CTC follows a -[Consensus Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making) -decision making model. - -When an agenda item has appeared to reach a consensus, the meeting chair will -ask "Does anyone object?" as a final call for dissent from the consensus. +The TSC follows a [Consensus Seeking][] decision making model as described by +the [TSC Charter][]. -If an agenda item cannot reach a consensus, a CTC member can call for either a -closing vote or a vote to table the issue to the next meeting. All votes -(including votes to close or table) pass if and only if more than 50% of the CTC -members (excluding individuals who explicitly abstain) vote in favor. For -example, if there are 20 CTC members, and 5 of those members indicate that they -abstain, then 8 votes in favor are required for a resolution to pass. +[TSC Charter]: https://github.com/nodejs/TSC/blob/master/TSC-Charter.md +[Consensus Seeking]: http://en.wikipedia.org/wiki/Consensus-seeking_decision-making diff --git a/README.md b/README.md index b3f3e7784af374..03c725bdcd13c1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If you need help using or installing Node.js, please use the * [Building Node.js](#building-nodejs) * [Security](#security) * [Current Project Team Members](#current-project-team-members) - * [CTC (Core Technical Committee)](#ctc-core-technical-committee) + * [TSC (Technical Steering Committee)](#tsc-technical-steering-committee) * [Collaborators](#collaborators) * [Release Team](#release-team) @@ -55,9 +55,9 @@ If you need help using or installing Node.js, please use the channel. _Please note that unofficial resources are neither managed by (nor necessarily -endorsed by) the Node.js TSC/CTC. Specifically, such resources are not +endorsed by) the Node.js TSC. Specifically, such resources are not currently covered by the [Node.js Moderation Policy][] and the selection and -actions of resource operators/moderators are not subject to TSC/CTC oversight._ +actions of resource operators/moderators are not subject to TSC oversight._ ## Release Types @@ -114,11 +114,11 @@ documentation of the latest stable version. ### Verifying Binaries -Current, LTS and Nightly download directories all contain a _SHASUM256.txt_ +Current, LTS and Nightly download directories all contain a _SHASUMS256.txt_ file that lists the SHA checksums for each file available for download. -The _SHASUM256.txt_ can be downloaded using curl. +The _SHASUMS256.txt_ can be downloaded using curl. ```console $ curl -O https://nodejs.org/dist/vx.y.z/SHASUMS256.txt @@ -135,10 +135,10 @@ _(Where "node-vx.y.z.tar.gz" is the name of the file you have downloaded)_ Additionally, Current and LTS releases (not Nightlies) have GPG signed -copies of SHASUM256.txt files available as SHASUM256.txt.asc. You can use +copies of SHASUMS256.txt files available as SHASUMS256.txt.asc. You can use `gpg` to verify that the file has not been tampered with. -To verify a SHASUM256.txt.asc, you will first need to import all of +To verify a SHASUMS256.txt.asc, you will first need to import all of the GPG keys of individuals authorized to create releases. They are listed at the bottom of this README under [Release Team](#release-team). Use a command such as this to import the keys: @@ -172,14 +172,59 @@ Your email will be acknowledged within 24 hours, and you’ll receive a more detailed response to your email within 48 hours indicating the next steps in handling your report. +There are no hard and fast rules to determine if a bug is worth reporting as +a security issue. The general rule is any issue worth reporting +must allow an attacker to compromise the confidentiality, integrity +or availability of the Node.js application or its system for which the attacker +does not already have the capability. + +To illustrate the point, here are some examples of past issues and what the +Security Reponse Team thinks of them. When in doubt, however, please do send +us a report nonetheless. + + +### Public disclosure preferred + +- [#14519](https://github.com/nodejs/node/issues/14519): _Internal domain + function can be used to cause segfaults_. Causing program termination using + either the public Javascript APIs or the private bindings layer APIs requires + the ability to execute arbitrary Javascript code, which is already the highest + level of privilege possible. + +- [#12141](https://github.com/nodejs/node/pull/12141): _buffer: zero fill + Buffer(num) by default_. The buffer constructor behaviour was documented, + but found to be prone to [mis-use](https://snyk.io/blog/exploiting-buffer/). + It has since been changed, but despite much debate, was not considered misuse + prone enough to justify fixing in older release lines and breaking our + API stability contract. + +### Private disclosure preferred + +- [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): + _Fix invalid wildcard certificate validation check_. This is a high severity + defect that would allow a malicious TLS server to serve an invalid wildcard + certificate for its hostname and be improperly validated by a Node.js client. + +- [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes + the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities + in the TLS/SSL protocols also effect Node.js. + +- [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): + _Fix defects in HTTP header parsing for requests and responses that can allow + response splitting_. While the impact of this vulnerability is application and + network dependent, it is remotely exploitable in the HTTP protocol. + +When in doubt, please do send us a report. + + ## Current Project Team Members The Node.js project team comprises a group of core collaborators and a sub-group -that forms the _Core Technical Committee_ (CTC) which governs the project. For -more information about the governance of the Node.js project, see +that forms the _Technical Steering Committee_ (TSC) which governs the project. +For more information about the governance of the Node.js project, see [GOVERNANCE.md](./GOVERNANCE.md). -### CTC (Core Technical Committee) +### TSC (Technical Steering Committee) * [addaleax](https://github.com/addaleax) - **Anna Henningsen** <anna@addaleax.net> (she/her) @@ -199,14 +244,14 @@ more information about the governance of the Node.js project, see **Fedor Indutny** <fedor.indutny@gmail.com> * [jasnell](https://github.com/jasnell) - **James M Snell** <jasnell@gmail.com> (he/him) +* [joshgav](https://github.com/joshgav) - +**Josh Gavant** <josh.gavant@outlook.com> * [joyeecheung](https://github.com/joyeecheung) - **Joyee Cheung** <joyeec9h3@gmail.com> (she/her) * [mcollina](https://github.com/mcollina) - **Matteo Collina** <matteo.collina@gmail.com> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <michael_dawson@ca.ibm.com> (he/him) -* [misterdjules](https://github.com/misterdjules) - -**Julien Gilli** <jgilli@nodejs.org> * [mscdex](https://github.com/mscdex) - **Brian White** <mscdex@mscdex.net> * [MylesBorins](https://github.com/MylesBorins) - @@ -226,7 +271,7 @@ more information about the governance of the Node.js project, see * [Trott](https://github.com/Trott) - **Rich Trott** <rtrott@gmail.com> (he/him) -### CTC Emeriti +### TSC Emeriti * [chrisdickinson](https://github.com/chrisdickinson) - **Chris Dickinson** <christopher.s.dickinson@gmail.com> @@ -236,6 +281,8 @@ more information about the governance of the Node.js project, see **Alexis Campailla** <orangemocha@nodejs.org> * [piscisaureus](https://github.com/piscisaureus) - **Bert Belder** <bertbelder@gmail.com> +* [nebrius](https://github.com/nebrius) - +**Bryan Hughes** <bryan@nebri.us> ### Collaborators @@ -263,6 +310,8 @@ more information about the governance of the Node.js project, see **Ben Noordhuis** <info@bnoordhuis.nl> * [brendanashworth](https://github.com/brendanashworth) - **Brendan Ashworth** <brendan.ashworth@me.com> +* [BridgeAR](https://github.com/BridgeAR) - +**Ruben Bridgewater** <ruben@bridgewater.de> * [bzoz](https://github.com/bzoz) - **Bartosz Sosnowski** <bartosz@janeasystems.com> * [calvinmetcalf](https://github.com/calvinmetcalf) - @@ -509,7 +558,7 @@ Previous releases may also have been signed with one of the following GPG keys: ### Working Groups Information on the current Node.js Working Groups can be found in the -[CTC repository](https://github.com/nodejs/CTC/blob/master/WORKING_GROUPS.md). +[TSC repository](https://github.com/nodejs/TSC/blob/master/WORKING_GROUPS.md). [npm]: https://www.npmjs.com [Website]: https://nodejs.org/en/ diff --git a/benchmark/arrays/var-int.js b/benchmark/arrays/var-int.js index 36b0a908a59a4f..b284074e6e712a 100644 --- a/benchmark/arrays/var-int.js +++ b/benchmark/arrays/var-int.js @@ -1,28 +1,26 @@ 'use strict'; -var common = require('../common.js'); +const common = require('../common.js'); -var types = [ - 'Array', - 'Buffer', - 'Int8Array', - 'Uint8Array', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array' -]; - -var bench = common.createBenchmark(main, { - type: types, +const bench = common.createBenchmark(main, { + type: [ + 'Array', + 'Buffer', + 'Int8Array', + 'Uint8Array', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array' + ], n: [25] }); function main(conf) { - var type = conf.type; - var clazz = global[type]; - var n = +conf.n; + const type = conf.type; + const clazz = global[type]; + const n = +conf.n; bench.start(); var arr = new clazz(n * 1e6); diff --git a/benchmark/arrays/zero-float.js b/benchmark/arrays/zero-float.js index 047e179234f33a..5df9ddaa739423 100644 --- a/benchmark/arrays/zero-float.js +++ b/benchmark/arrays/zero-float.js @@ -1,28 +1,26 @@ 'use strict'; -var common = require('../common.js'); +const common = require('../common.js'); -var types = [ - 'Array', - 'Buffer', - 'Int8Array', - 'Uint8Array', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array' -]; - -var bench = common.createBenchmark(main, { - type: types, +const bench = common.createBenchmark(main, { + type: [ + 'Array', + 'Buffer', + 'Int8Array', + 'Uint8Array', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array' + ], n: [25] }); function main(conf) { - var type = conf.type; - var clazz = global[type]; - var n = +conf.n; + const type = conf.type; + const clazz = global[type]; + const n = +conf.n; bench.start(); var arr = new clazz(n * 1e6); diff --git a/benchmark/arrays/zero-int.js b/benchmark/arrays/zero-int.js index 4e5c97e8af0b9c..62583e0965d3b8 100644 --- a/benchmark/arrays/zero-int.js +++ b/benchmark/arrays/zero-int.js @@ -1,28 +1,26 @@ 'use strict'; -var common = require('../common.js'); +const common = require('../common.js'); -var types = [ - 'Array', - 'Buffer', - 'Int8Array', - 'Uint8Array', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array' -]; - -var bench = common.createBenchmark(main, { - type: types, +const bench = common.createBenchmark(main, { + type: [ + 'Array', + 'Buffer', + 'Int8Array', + 'Uint8Array', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array' + ], n: [25] }); function main(conf) { - var type = conf.type; - var clazz = global[type]; - var n = +conf.n; + const type = conf.type; + const clazz = global[type]; + const n = +conf.n; bench.start(); var arr = new clazz(n * 1e6); diff --git a/benchmark/dgram/bind-params.js b/benchmark/dgram/bind-params.js index 6f641f7f570667..ae179f4ffce8a7 100644 --- a/benchmark/dgram/bind-params.js +++ b/benchmark/dgram/bind-params.js @@ -10,6 +10,7 @@ const configs = { }; const bench = common.createBenchmark(main, configs); +const noop = () => {}; function main(conf) { const n = +conf.n; @@ -19,19 +20,27 @@ function main(conf) { if (port !== undefined && address !== undefined) { bench.start(); for (let i = 0; i < n; i++) { - dgram.createSocket('udp4').bind(port, address).unref(); + dgram.createSocket('udp4').bind(port, address) + .on('error', noop) + .unref(); } bench.end(n); } else if (port !== undefined) { bench.start(); for (let i = 0; i < n; i++) { - dgram.createSocket('udp4').bind(port).unref(); + dgram.createSocket('udp4') + .bind(port) + .on('error', noop) + .unref(); } bench.end(n); } else if (port === undefined && address === undefined) { bench.start(); for (let i = 0; i < n; i++) { - dgram.createSocket('udp4').bind().unref(); + dgram.createSocket('udp4') + .bind() + .on('error', noop) + .unref(); } bench.end(n); } diff --git a/configure b/configure index 8cff260660f63c..7272e19261b238 100755 --- a/configure +++ b/configure @@ -1,4 +1,15 @@ -#!/usr/bin/env python +#!/bin/sh + +# Locate python2 interpreter and re-execute the script. Note that the +# mix of single and double quotes is intentional, as is the fact that +# the ] goes on a new line. +_=[ 'exec' '/bin/sh' '-c' ''' +which python2.7 >/dev/null && exec python2.7 "$0" "$@" +which python2 >/dev/null && exec python2 "$0" "$@" +exec python "$0" "$@" +''' "$0" "$@" +] +del _ import sys if sys.version_info[0] != 2 or sys.version_info[1] not in (6, 7): diff --git a/deps/openssl/config/opensslconf.h b/deps/openssl/config/opensslconf.h index 9b20fb6485aa84..1c89babcf6c864 100644 --- a/deps/openssl/config/opensslconf.h +++ b/deps/openssl/config/opensslconf.h @@ -37,6 +37,8 @@ | solaris | x64 | solaris64-x86_64-gcc | o | | freebsd | ia32 | BSD-x86 | o | | freebsd | x64 | BSD-x86_64 | o | + | netbsd | ia32 | BSD-x86 | o | + | netbsd | x64 | BSD-x86_64 | o | | openbsd | ia32 | BSD-x86 | - | | openbsd | x64 | BSD-x86_64 | - | | others | others | linux-elf | - | @@ -51,6 +53,7 @@ | mac | __APPLE__ && __MACH__ | | solaris | __sun | | freebsd | __FreeBSD__ | + | netbsd | __NetBSD__ | | openbsd | __OpenBSD__ | | linux (not andorid)| __linux__ && !__ANDROID__ | | android | __ANDROID__ | @@ -94,6 +97,11 @@ # define OPENSSL_LINUX 1 #endif +#undef OPENSSL_BSD +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# define OPENSSL_BSD 1 +#endif + #if defined(OPENSSL_LINUX) && defined(__i386__) # include "./archs/linux-elf/opensslconf.h" #elif defined(OPENSSL_LINUX) && defined(__ILP32__) @@ -112,9 +120,9 @@ # include "./archs/VC-WIN32/opensslconf.h" #elif defined(_WIN32) && defined(_M_X64) # include "./archs/VC-WIN64A/opensslconf.h" -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(__i386__) +#elif defined(OPENSSL_BSD) && defined(__i386__) # include "./archs/BSD-x86/opensslconf.h" -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(__x86_64__) +#elif defined(OPENSSL_BSD) && defined(__x86_64__) # include "./archs/BSD-x86_64/opensslconf.h" #elif defined(__sun) && defined(__i386__) # include "./archs/solaris-x86-gcc/opensslconf.h" diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 955fcd5646cef5..e7931da11e423f 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 1 #define V8_BUILD_NUMBER 281 -#define V8_PATCH_LEVEL 107 +#define V8_PATCH_LEVEL 108 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/debug/debug-scopes.cc b/deps/v8/src/debug/debug-scopes.cc index d9c615b01b4c58..88024021143ffe 100644 --- a/deps/v8/src/debug/debug-scopes.cc +++ b/deps/v8/src/debug/debug-scopes.cc @@ -842,6 +842,12 @@ bool ScopeIterator::CopyContextExtensionToScopeObject( void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope, int position) { + if (scope->is_function_scope()) { + // Do not collect scopes of nested inner functions inside the current one. + Handle function = + Handle::cast(frame_inspector_->GetFunction()); + if (scope->end_position() < function->shared()->end_position()) return; + } if (!scope->is_eval_scope()) { nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate), scope->start_position(), diff --git a/deps/v8/src/regexp/jsregexp.cc b/deps/v8/src/regexp/jsregexp.cc index bbbfbeb79924ad..4cfeab0d4f88f3 100644 --- a/deps/v8/src/regexp/jsregexp.cc +++ b/deps/v8/src/regexp/jsregexp.cc @@ -1131,7 +1131,7 @@ RegExpEngine::CompilationResult RegExpCompiler::Assemble( Handle code = macro_assembler_->GetCode(pattern); heap->IncreaseTotalRegexpCodeGenerated(code->Size()); work_list_ = NULL; -#ifdef ENABLE_DISASSEMBLER +#if defined(ENABLE_DISASSEMBLER) && !defined(V8_INTERPRETED_REGEXP) if (FLAG_print_code) { CodeTracer::Scope trace_scope(heap->isolate()->GetCodeTracer()); OFStream os(trace_scope.file()); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-621361.js b/deps/v8/test/mjsunit/regress/regress-crbug-621361.js new file mode 100644 index 00000000000000..f9496ae87d9f8b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-621361.js @@ -0,0 +1,40 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-debug-as debug + +var Debug = debug.Debug; +var steps = 0; +var exception = null; + +function listener(event, execState, eventData, data) { + if (event != Debug.DebugEvent.Break) return; + try { + assertEquals([ debug.ScopeType.Local, + debug.ScopeType.Script, + debug.ScopeType.Global], + execState.frame().allScopes().map(s => s.scopeType())); + var x_value = execState.frame().evaluate("x").value(); + if (steps < 2) { + assertEquals(undefined, x_value); + execState.prepareStep(Debug.StepAction.StepIn); + } else { + assertEquals("l => l", x_value.toString()); + } + steps++; + } catch (e) { + exception = e; + } +} + +Debug.setListener(listener); + +(function() { + debugger; + var x = l => l; +})(); + +Debug.setListener(null); +assertNull(exception); +assertEquals(3, steps); diff --git a/doc/.eslintrc.yaml b/doc/.eslintrc.yaml index b4fbf847be7aaf..a0334a79c25cf7 100644 --- a/doc/.eslintrc.yaml +++ b/doc/.eslintrc.yaml @@ -2,11 +2,11 @@ rules: # ease some restrictions in doc examples - no-restricted-properties: 0 - no-undef: 0 - no-unused-vars: 0 - strict: 0 + no-restricted-properties: off + no-undef: off + no-unused-vars: off + strict: off # add new ECMAScript features gradually - no-var: 2 - prefer-const: 2 + no-var: error + prefer-const: error diff --git a/doc/api/_toc.md b/doc/api/_toc.md index 2527ad84e2e360..5f7bca59e87d75 100644 --- a/doc/api/_toc.md +++ b/doc/api/_toc.md @@ -22,6 +22,7 @@ * [Globals](globals.html) * [HTTP](http.html) * [HTTPS](https.html) +* [Internationalization](intl.html) * [Modules](modules.html) * [Net](net.html) * [OS](os.html) diff --git a/doc/api/addons.md b/doc/api/addons.md index 4d29b718ab9dcd..b17c1c9e5c51c7 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -1,5 +1,7 @@ # C/C++ Addons + + Node.js Addons are dynamically-linked shared objects, written in C or C++, that can be loaded into Node.js using the [`require()`][require] function, and used just as if they were an ordinary Node.js module. They are used primarily to @@ -1053,7 +1055,6 @@ The following `addon.cc` implements AtExit: ```cpp // addon.cc -#undef NDEBUG #include #include #include @@ -1090,10 +1091,10 @@ static void sanity_check(void*) { } void init(Local exports) { - AtExit(sanity_check); AtExit(at_exit_cb2, cookie); AtExit(at_exit_cb2, cookie); AtExit(at_exit_cb1, exports->GetIsolate()); + AtExit(sanity_check); } NODE_MODULE(addon, init) @@ -1105,7 +1106,7 @@ Test in JavaScript by running: ```js // test.js -const addon = require('./build/Release/addon'); +require('./build/Release/addon'); ``` [bindings]: https://github.com/TooTallNate/node-bindings diff --git a/doc/api/all.md b/doc/api/all.md index 93c7a300a162e9..e2428cf376c1c4 100644 --- a/doc/api/all.md +++ b/doc/api/all.md @@ -18,6 +18,7 @@ @include globals @include http @include https +@include intl @include modules @include net @include os diff --git a/doc/api/assert.md b/doc/api/assert.md index 0b7621520b688f..a0eb8d7a4a188e 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -1,5 +1,7 @@ # Assert + + > Stability: 2 - Stable The `assert` module provides a simple set of assertion tests that can be used to @@ -192,7 +194,7 @@ If the values are not equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a default error message is assigned. -## assert.fail(actual, expected, message, operator) +## assert.fail(actual, expected[, message[, operator[, stackStartFunction]]]) @@ -200,10 +202,13 @@ added: v0.1.21 * `expected` {any} * `message` {any} * `operator` {string} +* `stackStartFunction` {function} (default: `assert.fail`) Throws an `AssertionError`. If `message` is falsy, the error message is set as the values of `actual` and `expected` separated by the provided `operator`. Otherwise, the error message is the value of `message`. +If `stackStartFunction` is provided, all stack frames above that function will +be removed from stacktrace (see [`Error.captureStackTrace`]). ```js const assert = require('assert'); @@ -211,10 +216,25 @@ const assert = require('assert'); assert.fail(1, 2, undefined, '>'); // AssertionError: 1 > 2 +assert.fail(1, 2, 'fail'); +// AssertionError: fail + assert.fail(1, 2, 'whoops', '>'); // AssertionError: whoops ``` +Example use of `stackStartFunction` for truncating the exception's stacktrace: +```js +function suppressFrame() { + assert.fail('a', 'b', undefined, '!==', suppressFrame); +} +suppressFrame(); +// AssertionError: 'a' !== 'b' +// at repl:1:1 +// at ContextifyScript.Script.runInThisContext (vm.js:44:33) +// ... +``` + ## assert.ifError(value) + ```js // THIS IS A MISTAKE! DO NOT DO THIS! assert.throws(myFunction, 'missing foo', 'did not throw with expected message'); @@ -492,5 +512,6 @@ assert.throws(myFunction, /missing foo/, 'did not throw with expected message'); [`assert.ok()`]: #assert_assert_ok_value_message [`assert.throws()`]: #assert_assert_throws_block_error_message [`Error`]: errors.html#errors_class_error +[`Error.captureStackTrace`]: errors.html#errors_error_capturestacktrace_targetobject_constructoropt [`RegExp`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions [`TypeError`]: errors.html#errors_class_typeerror diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 69e800ae09e761..eb2447f4cfff04 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1,5 +1,7 @@ # Buffer + + > Stability: 2 - Stable Prior to the introduction of [`TypedArray`] in ECMAScript 2015 (ES6), the @@ -833,7 +835,7 @@ const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex'); console.log(buf2.toString()); ``` -A `TypeError` will be thrown if `str` is not a string. +A `TypeError` will be thrown if `string` is not a string. ### Class Method: Buffer.isBuffer(obj) + > Stability: 2 - Stable The `child_process` module provides the ability to spawn child processes in @@ -611,8 +613,8 @@ the `SIGTERM` signal and does not exit, the parent process will still wait until the child process has exited.* If the process times out, or has a non-zero exit code, this method ***will*** -throw. The [`Error`][] object will contain the entire result from -[`child_process.spawnSync()`][] +throw an [`Error`][] that will include the full result of the underlying +[`child_process.spawnSync()`][]. ### child_process.execSync(command[, options]) Node.js comes with a variety of CLI options. These options expose built-in @@ -249,15 +250,15 @@ added: v6.11.0 --> Use OpenSSL's default CA store or use bundled Mozilla CA store as supplied by -current NodeJS version. The default store is selectable at build-time. +current Node.js version. The default store is selectable at build-time. Using OpenSSL store allows for external modifications of the store. For most Linux and BSD distributions, this store is maintained by the distribution maintainers and system administrators. OpenSSL CA store location is dependent on configuration of the OpenSSL library but this can be altered at runtime using -environmental variables. +environment variables. -The bundled CA store, as supplied by NodeJS, is a snapshot of Mozilla CA store +The bundled CA store, as supplied by Node.js, is a snapshot of Mozilla CA store that is fixed at release time. It is identical on all supported platforms. See `SSL_CERT_DIR` and `SSL_CERT_FILE`. diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 1d605503848963..a846ef0b55d2a0 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -1,5 +1,7 @@ # Cluster + + > Stability: 2 - Stable A single instance of Node.js runs in a single thread. To take advantage of diff --git a/doc/api/console.md b/doc/api/console.md index f3652a56561316..93ac3bd81ea4de 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -1,5 +1,7 @@ # Console + + > Stability: 2 - Stable The `console` module provides a simple debugging console that is similar to the diff --git a/doc/api/crypto.md b/doc/api/crypto.md index a40178db22e6ab..7d94ffd6c77f72 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1,5 +1,7 @@ # Crypto + + > Stability: 2 - Stable The `crypto` module provides cryptographic functionality that includes a set of @@ -1540,7 +1542,8 @@ console.log( `${buf.length} bytes of random data: ${buf.toString('hex')}`); ``` -The `crypto.randomBytes()` method will block until there is sufficient entropy. +The `crypto.randomBytes()` method will not complete until there is +sufficient entropy available. This should normally never take longer than a few milliseconds. The only time when generating the random bytes may conceivably block for a longer period of time is right after boot, when the whole system is still low on entropy. diff --git a/doc/api/debugger.md b/doc/api/debugger.md index 1c9b1049e82491..a24437021b7bea 100644 --- a/doc/api/debugger.md +++ b/doc/api/debugger.md @@ -1,5 +1,7 @@ # Debugger + + > Stability: 2 - Stable diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 2aec4abb254643..73e86baa0e175d 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -1,5 +1,7 @@ # UDP / Datagram Sockets + + > Stability: 2 - Stable diff --git a/doc/api/dns.md b/doc/api/dns.md index 457559d0ce692c..0a34f6efa8052d 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -1,5 +1,7 @@ # DNS + + > Stability: 2 - Stable The `dns` module contains functions belonging to two different categories: diff --git a/doc/api/documentation.md b/doc/api/documentation.md index f4b0c876c057c1..8109206ae2f055 100644 --- a/doc/api/documentation.md +++ b/doc/api/documentation.md @@ -1,5 +1,6 @@ # About this Documentation + The goal of this documentation is to comprehensively explain the Node.js diff --git a/doc/api/domain.md b/doc/api/domain.md index e98ccc87a0e346..08d6edc7d8cb24 100644 --- a/doc/api/domain.md +++ b/doc/api/domain.md @@ -1,5 +1,7 @@ # Domain + + > Stability: 0 - Deprecated **This module is pending deprecation**. Once a replacement API has been diff --git a/doc/api/errors.md b/doc/api/errors.md index 10a930ddd73c4b..49b4bac595a6dc 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1,5 +1,6 @@ # Errors + Applications running in Node.js will generally experience four categories of diff --git a/doc/api/events.md b/doc/api/events.md index 7462902e09479a..1cffb5e2d5855f 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -1,5 +1,7 @@ # Events + + > Stability: 2 - Stable diff --git a/doc/api/fs.md b/doc/api/fs.md index 381bf422006b44..7e446f28dcd6e4 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1,5 +1,7 @@ # File System + + > Stability: 2 - Stable @@ -1308,8 +1310,10 @@ Read data from the file specified by `fd`. `length` is an integer specifying the number of bytes to read. -`position` is an integer specifying where to begin reading from in the file. -If `position` is `null`, data will be read from the current file position. +`position` is an argument specifying where to begin reading from in the file. +If `position` is `null`, data will be read from the current file position, +and the file position will be updated. +If `position` is an integer, the file position will remain unchanged. The callback is given the three arguments, `(err, bytesRead, buffer)`. diff --git a/doc/api/globals.md b/doc/api/globals.md index b0467cdacde3a5..054bc2300bd411 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -1,5 +1,6 @@ # Global Objects + These objects are available in all modules. Some of these objects aren't diff --git a/doc/api/http.md b/doc/api/http.md index 94f2ec75529278..2f087d39b36767 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1,5 +1,7 @@ # HTTP + + > Stability: 2 - Stable To use the HTTP server and client one must `require('http')`. @@ -1476,8 +1478,8 @@ added: v0.3.6 Since most requests are GET requests without bodies, Node.js provides this convenience method. The only difference between this method and [`http.request()`][] is that it sets the method to GET and calls `req.end()` -automatically. Note that response data must be consumed in the callback -for reasons stated in [`http.ClientRequest`][] section. +automatically. Note that the callback must take care to consume the response +data for reasons stated in [`http.ClientRequest`][] section. The `callback` is invoked with a single argument that is an instance of [`http.IncomingMessage`][] diff --git a/doc/api/https.md b/doc/api/https.md index ea99d8bcdb99b0..6f2a385b270434 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -1,5 +1,7 @@ # HTTPS + + > Stability: 2 - Stable HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a diff --git a/doc/api/intl.md b/doc/api/intl.md new file mode 100644 index 00000000000000..075d02879fe719 --- /dev/null +++ b/doc/api/intl.md @@ -0,0 +1,198 @@ +# Internationalization Support + +Node.js has many features that make it easier to write internationalized +programs. Some of them are: + +- Locale-sensitive or Unicode-aware functions in the [ECMAScript Language + Specification][ECMA-262]: + - [`String.prototype.normalize()`][] + - [`String.prototype.toLowerCase()`][] + - [`String.prototype.toUpperCase()`][] +- All functionality described in the [ECMAScript Internationalization API + Specification][ECMA-402] (aka ECMA-402): + - [`Intl`][] object + - Locale-sensitive methods like [`String.prototype.localeCompare()`][] and + [`Date.prototype.toLocaleString()`][] + +Node.js (and its underlying V8 engine) uses [ICU][] to implement these features +in native C/C++ code. However, some of them require a very large ICU data file +in order to support all locales of the world. Because it is expected that most +Node.js users will make use of only a small portion of ICU functionality, only +a subset of the full ICU data set is provided by Node.js by default. Several +options are provided for customizing and expanding the ICU data set either when +building or running Node.js. + +## Options for building Node.js + +To control how ICU is used in Node.js, four `configure` options are available +during compilation. Additional details on how to compile Node.js are documented +in [BUILDING.md][]. + +- `--with-intl=none` / `--without-intl` +- `--with-intl=system-icu` +- `--with-intl=small-icu` (default) +- `--with-intl=full-icu` + +An overview of available Node.js and JavaScript features for each `configure` +option: + +| | `none` | `system-icu` | `small-icu` | `full-icu` +|-----------------------------------------|-----------------------------------|------------------------------|------------------------|------------ +| [`String.prototype.normalize()`][] | none (function is no-op) | full | full | full +| `String.prototype.to*Case()` | full | full | full | full +| [`Intl`][] | none (object does not exist) | partial/full (depends on OS) | partial (English-only) | full +| [`String.prototype.localeCompare()`][] | partial (not locale-aware) | full | full | full +| `String.prototype.toLocale*Case()` | partial (not locale-aware) | full | full | full +| [`Number.prototype.toLocaleString()`][] | partial (not locale-aware) | partial/full (depends on OS) | partial (English-only) | full +| `Date.prototype.toLocale*String()` | partial (not locale-aware) | partial/full (depends on OS) | partial (English-only) | full + +*Note*: The "(not locale-aware)" designation denotes that the function carries +out its operation just like the non-`Locale` version of the function, if one +exists. For example, under `none` mode, `Date.prototype.toLocaleString()`'s +operation is identical to that of `Date.prototype.toString()`. + +### Disable all internationalization features (`none`) + +If this option is chosen, most internationalization features mentioned above +will be **unavailable** in the resulting `node` binary. + +### Build with a pre-installed ICU (`system-icu`) + +Node.js can link against an ICU build already installed on the system. In fact, +most Linux distributions already come with ICU installed, and this option would +make it possible to reuse the same set of data used by other components in the +OS. + +Functionalities that only require the ICU library itself, such as +[`String.prototype.normalize()`][], are fully supported under `system-icu`. +Features that require ICU locale data in addition, such as +[`Intl.DateTimeFormat`][] *may* be fully or partially supported, depending on +the completeness of the ICU data installed on the system. + +### Embed a limited set of ICU data (`small-icu`) + +This option makes the resulting binary link against the ICU library statically, +and includes a subset of ICU data (typically only the English locale) within +the `node` executable. + +Functionalities that only require the ICU library itself, such as +[`String.prototype.normalize()`][], are fully supported under `small-icu`. +Features that require ICU locale data in addition, such as +[`Intl.DateTimeFormat`][], generally only work with the English locale: + +```js +const january = new Date(9e8); +const english = new Intl.DateTimeFormat('en', { month: 'long' }); +const spanish = new Intl.DateTimeFormat('es', { month: 'long' }); + +console.log(english.format(january)); +// Prints "January" +console.log(spanish.format(january)); +// Prints "January" or "M01" on small-icu +// Should print "enero" +``` + +This mode provides a good balance between features and binary size, and it is +the default behavior if no `--with-intl` flag is passed. The official binaries +are also built in this mode. + +#### Providing ICU data at runtime + +If the `small-icu` option is used, one can still provide additional locale data +at runtime so that the JS methods would work for all ICU locales. Assuming the +data file is stored at `/some/directory`, it can be made available to ICU +through either: + +* The [`NODE_ICU_DATA`][] environment variable: + + ```shell + env NODE_ICU_DATA=/some/directory node + ``` + +* The [`--icu-data-dir`][] CLI parameter: + + ```shell + node --icu-data-dir=/some/directory + ``` + +(If both are specified, the `--icu-data-dir` CLI parameter takes precedence.) + +ICU is able to automatically find and load a variety of data formats, but the +data must be appropriate for the ICU version, and the file correctly named. +The most common name for the data file is `icudt5X[bl].dat`, where `5X` denotes +the intended ICU version, and `b` or `l` indicates the system's endianness. +Check ["ICU Data"][] article in the ICU User Guide for other supported formats +and more details on ICU data in general. + +The [full-icu][] npm module can greatly simplify ICU data installation by +detecting the ICU version of the running `node` executable and downloading the +appropriate data file. After installing the module through `npm i full-icu`, +the data file will be available at `./node_modules/full-icu`. This path can be +then passed either to `NODE_ICU_DATA` or `--icu-data-dir` as shown above to +enable full `Intl` support. + +### Embed the entire ICU (`full-icu`) + +This option makes the resulting binary link against ICU statically and include +a full set of ICU data. A binary created this way has no further external +dependencies and supports all locales, but might be rather large. See +[BUILDING.md][BUILDING.md#full-icu] on how to compile a binary using this mode. + +## Detecting internationalization support + +To verify that ICU is enabled at all (`system-icu`, `small-icu`, or +`full-icu`), simply checking the existence of `Intl` should suffice: + +```js +const hasICU = typeof Intl === 'object'; +``` + +Alternatively, checking for `process.versions.icu`, a property defined only +when ICU is enabled, works too: + +```js +const hasICU = typeof process.versions.icu === 'string'; +``` + +To check for support for a non-English locale (i.e. `full-icu` or +`system-icu`), [`Intl.DateTimeFormat`][] can be a good distinguishing factor: + +```js +const hasFullICU = (() => { + try { + const january = new Date(9e8); + const spanish = new Intl.DateTimeFormat('es', { month: 'long' }); + return spanish.format(january) === 'enero'; + } catch (err) { + return false; + } +})(); +``` + +For more verbose tests for `Intl` support, the following resources may be found +to be helpful: + +- [btest402][]: Generally used to check whether Node.js with `Intl` support is + built correctly. +- [Test262][]: ECMAScript's official conformance test suite includes a section + dedicated to ECMA-402. + +[btest402]: https://github.com/srl295/btest402 +[BUILDING.md]: https://github.com/nodejs/node/blob/master/BUILDING.md +[BUILDING.md#full-icu]: https://github.com/nodejs/node/blob/master/BUILDING.md#build-with-full-icu-support-all-locales-supported-by-icu +[`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString +[ECMA-262]: https://tc39.github.io/ecma262/ +[ECMA-402]: https://tc39.github.io/ecma402/ +[full-icu]: https://www.npmjs.com/package/full-icu +[ICU]: http://icu-project.org/ +["ICU Data"]: http://userguide.icu-project.org/icudata +[`--icu-data-dir`]: cli.html#cli_icu_data_dir_file +[`Intl`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl +[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat +[`NODE_ICU_DATA`]: cli.html#cli_node_icu_data_file +[`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString +[`String.prototype.localeCompare()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare +[`String.prototype.normalize()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/normalize +[`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase +[`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase +[Test262]: https://github.com/tc39/test262/tree/master/test/intl402 diff --git a/doc/api/modules.md b/doc/api/modules.md index 480f9e10ea57be..7e89a94924ba48 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -1,5 +1,7 @@ # Modules + + > Stability: 2 - Stable diff --git a/doc/api/net.md b/doc/api/net.md index 5a566dc7cb89c8..3308fc27f0edef 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1,5 +1,7 @@ # Net + + > Stability: 2 - Stable The `net` module provides you with an asynchronous network wrapper. It contains diff --git a/doc/api/os.md b/doc/api/os.md index 84cb2ba3ff6b7c..3dc2561ad72626 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -1,5 +1,7 @@ # OS + + > Stability: 2 - Stable The `os` module provides a number of operating system-related utility methods. @@ -46,7 +48,7 @@ added: v6.3.0 Returns an object containing commonly used operating system specific constants for error codes, process signals, and so on. The specific constants currently -defined are described in [OS Constants][]. +defined are described in [OS Constants](#os_os_constants_1). ## os.cpus() + > Stability: 2 - Stable The `path` module provides utilities for working with file and directory paths. diff --git a/doc/api/process.md b/doc/api/process.md index 0e8c17af7e605c..885569a4ad48f6 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1,5 +1,6 @@ # Process + The `process` object is a `global` that provides information about, and control diff --git a/doc/api/punycode.md b/doc/api/punycode.md index 87d1c7d80ad431..f1aedc0cb86cc6 100644 --- a/doc/api/punycode.md +++ b/doc/api/punycode.md @@ -1,5 +1,7 @@ # Punycode + + > Stability: 0 - Deprecated **The version of the punycode module bundled in Node.js is being deprecated**. diff --git a/doc/api/querystring.md b/doc/api/querystring.md index f1f48fadd5fc29..6d39bebbc83b0a 100644 --- a/doc/api/querystring.md +++ b/doc/api/querystring.md @@ -1,5 +1,7 @@ # Query String + + > Stability: 2 - Stable diff --git a/doc/api/readline.md b/doc/api/readline.md index fab1e9b3ed80f3..bccee609ed3e8e 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -1,5 +1,7 @@ # Readline + + > Stability: 2 - Stable The `readline` module provides an interface for reading data from a [Readable][] @@ -362,7 +364,9 @@ added: v0.1.98 * `crlfDelay` {number} If the delay between `\r` and `\n` exceeds `crlfDelay` milliseconds, both `\r` and `\n` will be treated as separate end-of-line input. Default to `100` milliseconds. - `crlfDelay` will be coerced to `[100, 2000]` range. + `crlfDelay` will be coerced to a number no less than `100`. It can be set to + `Infinity`, in which case `\r` followed by `\n` will always be considered a + single newline. * `removeHistoryDuplicates` {boolean} If `true`, when a new input line added to the history list duplicates an older one, this removes the older line from the list. Defaults to `false`. @@ -450,6 +454,10 @@ autocompletion is disabled when copy-pasted input is detected. If the `stream` is a [TTY][], then it must be in raw mode. +*Note*: This is automatically called by any readline instance on its `input` +if the `input` is a terminal. Closing the `readline` instance does not stop +the `input` from emitting `'keypress'` events. + ```js readline.emitKeypressEvents(process.stdin); if (process.stdin.isTTY) diff --git a/doc/api/repl.md b/doc/api/repl.md index ed1425350d19f1..3cac76497a0a47 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -1,5 +1,7 @@ # REPL + + > Stability: 2 - Stable The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that @@ -487,7 +489,7 @@ by the `NODE_REPL_HISTORY` variable, as documented in the ### Using the Node.js REPL with advanced line-editors -For advanced line-editors, start Node.js with the environmental variable +For advanced line-editors, start Node.js with the environment variable `NODE_NO_READLINE=1`. This will start the main and debugger REPL in canonical terminal settings which will allow you to use with `rlwrap`. diff --git a/doc/api/stream.md b/doc/api/stream.md index 2a49b4b34f9fb1..c4378a2f8ac7af 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1,5 +1,7 @@ # Stream + + > Stability: 2 - Stable A stream is an abstract interface for working with streaming data in Node.js. @@ -66,8 +68,8 @@ buffer that can be retrieved using `writable._writableState.getBuffer()` or The amount of data potentially buffered depends on the `highWaterMark` option passed into the streams constructor. For normal streams, the `highWaterMark` -option specifies a total number of bytes. For streams operating in object mode, -the `highWaterMark` specifies a total number of objects. +option specifies a [total number of bytes][hwm-gotcha]. For streams operating +in object mode, the `highWaterMark` specifies a total number of objects. Data is buffered in Readable streams when the implementation calls [`stream.push(chunk)`][stream-push]. If the consumer of the Stream does not @@ -863,7 +865,7 @@ in object mode. The optional `size` argument specifies a specific number of bytes to read. If `size` bytes are not available to be read, `null` will be returned *unless* the stream has ended, in which case all of the data remaining in the internal -buffer will be returned (*even if it exceeds `size` bytes*). +buffer will be returned. If the `size` argument is not specified, all of the data contained in the internal buffer will be returned. @@ -1415,9 +1417,9 @@ constructor and implement the `readable._read()` method. #### new stream.Readable([options]) * `options` {Object} - * `highWaterMark` {number} The maximum number of bytes to store in - the internal buffer before ceasing to read from the underlying - resource. Defaults to `16384` (16kb), or `16` for `objectMode` streams + * `highWaterMark` {number} The maximum [number of bytes][hwm-gotcha] to store + in the internal buffer before ceasing to read from the underlying resource. + Defaults to `16384` (16kb), or `16` for `objectMode` streams * `encoding` {string} If specified, then buffers will be decoded to strings using the specified encoding. Defaults to `null` * `objectMode` {boolean} Whether this stream should behave @@ -1922,7 +1924,7 @@ user programs. `transform._transform()` is never called in parallel; streams implement a queue mechanism, and to receive the next chunk, `callback` must be -called, either synchronously or asychronously. +called, either synchronously or asynchronously. #### Class: stream.PassThrough @@ -2031,6 +2033,19 @@ has an interesting side effect. Because it *is* a call to However, because the argument is an empty string, no data is added to the readable buffer so there is nothing for a user to consume. +### `highWaterMark` discrepency after calling `readable.setEncoding()` + +The use of `readable.setEncoding()` will change the behavior of how the +`highWaterMark` operates in non-object mode. + +Typically, the size of the current buffer is measured against the +`highWaterMark` in _bytes_. However, after `setEncoding()` is called, the +comparison function will begin to measure the buffer's size in _characters_. + +This is not a problem in common cases with `latin1` or `ascii`. But it is +advised to be mindful about this behavior when working with strings that could +contain multi-byte characters. + [`'data'`]: #stream_event_data [`'drain'`]: #stream_event_drain [`'end'`]: #stream_event_end @@ -2065,6 +2080,8 @@ readable buffer so there is nothing for a user to consume. [http-incoming-message]: http.html#http_class_http_incomingmessage [Readable]: #stream_class_stream_readable [zlib]: zlib.html +[hwm-gotcha]: #stream_highWaterMark_discrepency_after_calling_readable_setencoding +[Readable]: #stream_class_stream_readable [stream-_flush]: #stream_transform_flush_callback [stream-_read]: #stream_readable_read_size_1 [stream-_transform]: #stream_transform_transform_chunk_encoding_callback diff --git a/doc/api/string_decoder.md b/doc/api/string_decoder.md index 17bacf33cbfb9b..2b47317cf0e036 100644 --- a/doc/api/string_decoder.md +++ b/doc/api/string_decoder.md @@ -1,5 +1,7 @@ # String Decoder + + > Stability: 2 - Stable The `string_decoder` module provides an API for decoding `Buffer` objects into diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index 5e4e22a38b9375..3a9c871d5d5cdc 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -1,5 +1,6 @@ # Usage + `node [options] [v8 options] [script.js | -e "script"] [arguments]` diff --git a/doc/api/timers.md b/doc/api/timers.md index df48905001e19b..010809032c5542 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -1,5 +1,7 @@ # Timers + + > Stability: 2 - Stable The `timer` module exposes a global API for scheduling functions to diff --git a/doc/api/tls.md b/doc/api/tls.md index b7e5c8f15e2bf4..12e27959c1c047 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -1,5 +1,7 @@ # TLS (SSL) + + > Stability: 2 - Stable The `tls` module provides an implementation of the Transport Layer Security diff --git a/doc/api/tty.md b/doc/api/tty.md index 963de892cbc0fd..2950eb6db1a396 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -1,5 +1,7 @@ # TTY + + > Stability: 2 - Stable The `tty` module provides the `tty.ReadStream` and `tty.WriteStream` classes. diff --git a/doc/api/url.md b/doc/api/url.md index 1cb3e2f89f0fd8..6d0911da81d899 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1,5 +1,7 @@ # URL + + > Stability: 2 - Stable The `url` module provides utilities for URL resolution and parsing. It can be diff --git a/doc/api/util.md b/doc/api/util.md index 0ab3ba0390bc9d..e44d38706f2c37 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1,5 +1,7 @@ # Util + + > Stability: 2 - Stable The `util` module is primarily designed to support the needs of Node.js' own diff --git a/doc/api/v8.md b/doc/api/v8.md index 0941596084aea1..234835376bd3e0 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -1,5 +1,7 @@ # V8 + + The `v8` module exposes APIs that are specific to the version of [V8][] built into the Node.js binary. It can be accessed using: diff --git a/doc/api/vm.md b/doc/api/vm.md index 7d04cbd4d1689d..cd47bc04ea85f6 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -1,5 +1,7 @@ # VM (Executing JavaScript) + + > Stability: 2 - Stable diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 17a1464b159de3..9edcc7eae37d88 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -1,5 +1,7 @@ # Zlib + + > Stability: 2 - Stable The `zlib` module provides compression functionality implemented using Gzip and diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 55dfbb187f18d0..53e6f0aa8624a3 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -81,6 +81,73 @@ em code { #gtoc { font-size: .8em; + margin-bottom: 1em; +} + +#gtoc ul { + list-style: none; + margin-left: 0; +} + +#gtoc li { + display: inline; + border-right: 1px #000 solid; + margin-right: 0.4em; + padding-right: 0.4em; +} + +#gtoc li:last-child { + border-right: none; + margin-right: 0; + padding-right: 0; +} + +li.version-picker { + position: relative; +} + +li.version-picker:hover > ol { + display: block; +} + +li.version-picker a span { + font-size: .7em; +} + +ol.version-picker { + background: #fff; + border: 1px #43853d solid; + border-radius: 2px; + display: none; + list-style: none; + position: absolute; + right: -2px; + width: 101%; +} + +#gtoc ol.version-picker li { + display: block; + border-right: 0; + margin-right: 0; + width: 100%; +} + +ol.version-picker li a { + border-radius: 0; + display: block; + margin: 0; + padding: .1em; + padding-left: 1em; +} + +ol.version-picker li:first-child a { + border-top-right-radius: 1px; + border-top-left-radius: 1px; +} + +ol.version-picker li:last-child a { + border-bottom-right-radius: 1px; + border-bottom-left-radius: 1px; } .line { @@ -93,7 +160,8 @@ em code { color: white !important; margin: 0 0 1em 0; font-family: "Lato", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; - font-weight: 700; + padding: 1em; + line-height: 1.5; } .api_stability * { @@ -495,6 +563,9 @@ th > *:last-child, td > *:last-child { #content { font-size: 3.5em; } + #gtoc { + font-size: 0.6em; + } } @media print { diff --git a/doc/changelogs/CHANGELOG_V6.md b/doc/changelogs/CHANGELOG_V6.md index 3e4e22bd321b29..2134efa73c23da 100644 --- a/doc/changelogs/CHANGELOG_V6.md +++ b/doc/changelogs/CHANGELOG_V6.md @@ -7,6 +7,7 @@ +6.11.4
6.11.3
6.11.2
6.11.1
@@ -52,6 +53,111 @@ [Node.js Long Term Support Plan](https://github.com/nodejs/LTS) and will be supported actively until April 2018 and maintained until April 2019. + +## 2017-10-03, Version 6.11.4 'Boron' (LTS), @MylesBorins + +This LTS release comes with 91 commits. This includes 29 which are test related, +28 which are doc related, 11 which are build / tool related and 3 commits which are updates to dependencies. + +### Notable Changes + +* **net**: + - support passing undefined to listen() to match behavior in v4.x and v8.x (Sam Roberts) [#14234](https://github.com/nodejs/node/pull/14234) + +### Commits + +* [[`73416b46e4`](https://github.com/nodejs/node/commit/73416b46e4)] - **assert**: refactor the code (Ruben Bridgewater) [#13862](https://github.com/nodejs/node/pull/13862) +* [[`a8b917ee2f`](https://github.com/nodejs/node/commit/a8b917ee2f)] - **benchmark**: fix dgram/bind-params.js benchmark (Rich Trott) [#14948](https://github.com/nodejs/node/pull/14948) +* [[`855d7ae326`](https://github.com/nodejs/node/commit/855d7ae326)] - **benchmark**: convert var to es6 const (Sebastian Murphy) [#12886](https://github.com/nodejs/node/pull/12886) +* [[`6a7e46ed9c`](https://github.com/nodejs/node/commit/6a7e46ed9c)] - **build**: add NetBSD support to opensslconf.h (Roy Marples) [#14313](https://github.com/nodejs/node/pull/14313) +* [[`66dd898be8`](https://github.com/nodejs/node/commit/66dd898be8)] - **build**: better support for python3 systems (Ben Noordhuis) [#14737](https://github.com/nodejs/node/pull/14737) +* [[`14cc1abb56`](https://github.com/nodejs/node/commit/14cc1abb56)] - **build**: split up cpplint to avoid long cmd lines (Kyle Farnung) [#14116](https://github.com/nodejs/node/pull/14116) +* [[`c9ae894277`](https://github.com/nodejs/node/commit/c9ae894277)] - **build**: add lint option to vcbuild.bat help (Morgan Brenner) [#11992](https://github.com/nodejs/node/pull/11992) +* [[`66cdcd9d5b`](https://github.com/nodejs/node/commit/66cdcd9d5b)] - **build**: add cpp linting to windows build (liusi) [#11856](https://github.com/nodejs/node/pull/11856) +* [[`25be2a3be3`](https://github.com/nodejs/node/commit/25be2a3be3)] - **crypto**: naming anonymous functions. (solebox) [#8993](https://github.com/nodejs/node/pull/8993) +* [[`4e1a50a079`](https://github.com/nodejs/node/commit/4e1a50a079)] - **deps**: backport 0353a1e from V8 upstream (jBarz) [#15287](https://github.com/nodejs/node/pull/15287) +* [[`921876dcd1`](https://github.com/nodejs/node/commit/921876dcd1)] - **deps**: backport 071b655 from V8 upstream (Michaël Zasso) [#15215](https://github.com/nodejs/node/pull/15215) +* [[`a13ac69ff9`](https://github.com/nodejs/node/commit/a13ac69ff9)] - **doc**: prevent displaying empty version picker (Chris Young) [#15420](https://github.com/nodejs/node/pull/15420) +* [[`ecea33b277`](https://github.com/nodejs/node/commit/ecea33b277)] - **doc**: add links to alternative versions of doc (Chris Young) [#10958](https://github.com/nodejs/node/pull/10958) +* [[`feb6863a5c`](https://github.com/nodejs/node/commit/feb6863a5c)] - **doc**: document bytes to chars after setEncoding (Jessica Quynh Tran) [#13442](https://github.com/nodejs/node/pull/13442) +* [[`33fdbb5417`](https://github.com/nodejs/node/commit/33fdbb5417)] - **doc**: describe what security issues are (Sam Roberts) [#14485](https://github.com/nodejs/node/pull/14485) +* [[`a260190717`](https://github.com/nodejs/node/commit/a260190717)] - **doc**: instructions for generating coverage reports (Simon Brewster) [#15190](https://github.com/nodejs/node/pull/15190) +* [[`1b0e660c25`](https://github.com/nodejs/node/commit/1b0e660c25)] - **doc**: /s/SHASUM256/SHASUMS256 (Jon Moss) [#15101](https://github.com/nodejs/node/pull/15101) +* [[`5696223534`](https://github.com/nodejs/node/commit/5696223534)] - **doc**: clarify http.get data consumption requirement (AJ Jordan) [#15049](https://github.com/nodejs/node/pull/15049) +* [[`4c26913dab`](https://github.com/nodejs/node/commit/4c26913dab)] - **doc**: crypto.randomBytes does not block when async (Sam Roberts) [#14993](https://github.com/nodejs/node/pull/14993) +* [[`605a02b613`](https://github.com/nodejs/node/commit/605a02b613)] - **doc**: environmental-\>environment & NodeJS-\>Node.js (Rod Vagg) [#14974](https://github.com/nodejs/node/pull/14974) +* [[`b10bc31030`](https://github.com/nodejs/node/commit/b10bc31030)] - **doc**: fix typo in Buffer.from(string, \[encoding\]) (Michał Wadas) [#15013](https://github.com/nodejs/node/pull/15013) +* [[`29de000938`](https://github.com/nodejs/node/commit/29de000938)] - **doc**: add note for Windows build path (Kyle Lamse) [#14354](https://github.com/nodejs/node/pull/14354) +* [[`7546eef262`](https://github.com/nodejs/node/commit/7546eef262)] - **doc**: rephrase text of child_process.execSync() (hafiz) [#14953](https://github.com/nodejs/node/pull/14953) +* [[`70e9a6ece3`](https://github.com/nodejs/node/commit/70e9a6ece3)] - **doc**: link to correct "OS Constants" heading in docs (James Kyle) [#14969](https://github.com/nodejs/node/pull/14969) +* [[`55dc14ec61`](https://github.com/nodejs/node/commit/55dc14ec61)] - **doc**: remove misterdjules from the CTC members list (Julien Gilli) [#1498](https://github.com/nodejs/node/pull/1498) +* [[`c76a54f318`](https://github.com/nodejs/node/commit/c76a54f318)] - **doc**: add missing word (Jon Moss) [#14924](https://github.com/nodejs/node/pull/14924) +* [[`27b6737d85`](https://github.com/nodejs/node/commit/27b6737d85)] - **doc**: explain what to do if git push is rejected (Rich Trott) [#14848](https://github.com/nodejs/node/pull/14848) +* [[`d75e9b7d44`](https://github.com/nodejs/node/commit/d75e9b7d44)] - **doc**: add BridgeAR to collaborators (Ruben Bridgewater) [#14862](https://github.com/nodejs/node/pull/14862) +* [[`a63cd82003`](https://github.com/nodejs/node/commit/a63cd82003)] - **doc**: fix word wrapping for api stability boxes (Saad Quadri) [#14809](https://github.com/nodejs/node/pull/14809) +* [[`f8fbac7842`](https://github.com/nodejs/node/commit/f8fbac7842)] - **doc**: improve fs.read() doc text (Rich Trott) [#14631](https://github.com/nodejs/node/pull/14631) +* [[`5a7a49f505`](https://github.com/nodejs/node/commit/5a7a49f505)] - **doc**: clarify the position argument for fs.read (dcharbonnier) [#14631](https://github.com/nodejs/node/pull/14631) +* [[`b5904a2054`](https://github.com/nodejs/node/commit/b5904a2054)] - **doc**: remove undef NDEBUG from addons.md (Daniel Bevenius) [#14048](https://github.com/nodejs/node/pull/14048) +* [[`c0e47e4f22`](https://github.com/nodejs/node/commit/c0e47e4f22)] - **doc**: fix order of AtExit callbacks in addons.md (Daniel Bevenius) [#14048](https://github.com/nodejs/node/pull/14048) +* [[`dcdc9053b4`](https://github.com/nodejs/node/commit/dcdc9053b4)] - **doc**: fix typo in stream.md (Marc Hernández Cabot) [#14364](https://github.com/nodejs/node/pull/14364) +* [[`594e3c2115`](https://github.com/nodejs/node/commit/594e3c2115)] - **doc**: add readline.emitKeypressEvents note (Samuel Reed) [#9447](https://github.com/nodejs/node/pull/9447) +* [[`90fcccd7a3`](https://github.com/nodejs/node/commit/90fcccd7a3)] - **doc**: add documentation on ICU (Timothy Gu) [#13916](https://github.com/nodejs/node/pull/13916) +* [[`38ae5c4e34`](https://github.com/nodejs/node/commit/38ae5c4e34)] - **doc, lib, test**: do not re-require needlessly (Vse Mozhet Byt) [#14244](https://github.com/nodejs/node/pull/14244) +* [[`abf6355936`](https://github.com/nodejs/node/commit/abf6355936)] - **doc,assert**: document stackStartFunction in fail (Ruben Bridgewater) [#13862](https://github.com/nodejs/node/pull/13862) +* [[`f0328f631a`](https://github.com/nodejs/node/commit/f0328f631a)] - **doc,stream**: remove wrong remark on readable.read (Jan Schär) [#15014](https://github.com/nodejs/node/pull/15014) +* [[`0c670e0339`](https://github.com/nodejs/node/commit/0c670e0339)] - **http**: eliminate capture of ClientRequest in Agent (Evan Torrie) [#10134](https://github.com/nodejs/node/pull/10134) +* [[`67074113dc`](https://github.com/nodejs/node/commit/67074113dc)] - **http**: reset stream to unconsumed in `unconsume()` (Anna Henningsen) [#14410](https://github.com/nodejs/node/pull/14410) +* [[`e65c9ec7f4`](https://github.com/nodejs/node/commit/e65c9ec7f4)] - **http**: assert parser.consume argument's type (Gireesh Punathil) [#12288](https://github.com/nodejs/node/pull/12288) +* [[`4e717820a0`](https://github.com/nodejs/node/commit/4e717820a0)] - **lib**: clean up usage of threw (Jackson Tian) [#10534](https://github.com/nodejs/node/pull/10534) +* [[`e014178362`](https://github.com/nodejs/node/commit/e014178362)] - **meta**: merge TSC and CTC back into a single body (James M Snell) [#14973](https://github.com/nodejs/node/pull/14973) +* [[`4ee066eaba`](https://github.com/nodejs/node/commit/4ee066eaba)] - **meta**: considerations for new core modules (James M Snell) [#15022](https://github.com/nodejs/node/pull/15022) +* [[`948a7d70e7`](https://github.com/nodejs/node/commit/948a7d70e7)] - **meta**: improve definition of a collaborator (James M Snell) [#14981](https://github.com/nodejs/node/pull/14981) +* [[`caeee38b1d`](https://github.com/nodejs/node/commit/caeee38b1d)] - **net**: support passing undefined to listen() (Sam Roberts) [#14234](https://github.com/nodejs/node/pull/14234) +* [[`792acc17bf`](https://github.com/nodejs/node/commit/792acc17bf)] - **net**: fix abort on bad address input (Ruben Bridgewater) [#13726](https://github.com/nodejs/node/pull/13726) +* [[`8604772960`](https://github.com/nodejs/node/commit/8604772960)] - **readline**: remove max limit of crlfDelay (Azard) [#13497](https://github.com/nodejs/node/pull/13497) +* [[`362a7c0d8b`](https://github.com/nodejs/node/commit/362a7c0d8b)] - **repl**: do not consider `...` as a REPL command (Shivanth MP) [#14467](https://github.com/nodejs/node/pull/14467) +* [[`968121bbfe`](https://github.com/nodejs/node/commit/968121bbfe)] - **src**: remove unnecessary helper function (Brian White) [#14959](https://github.com/nodejs/node/pull/14959) +* [[`b2112f8d36`](https://github.com/nodejs/node/commit/b2112f8d36)] - **src**: detect nul bytes in InternalModuleReadFile() (Ben Noordhuis) [#14854](https://github.com/nodejs/node/pull/14854) +* [[`d20b7bfb6e`](https://github.com/nodejs/node/commit/d20b7bfb6e)] - **src**: use local isolate instead of args.GetIsolate (Daniel Bevenius) [#14768](https://github.com/nodejs/node/pull/14768) +* [[`66187fa044`](https://github.com/nodejs/node/commit/66187fa044)] - **stream**: fix Writable instanceof for subclasses (Anna Henningsen) [#14945](https://github.com/nodejs/node/pull/14945) +* [[`2c8fe9748c`](https://github.com/nodejs/node/commit/2c8fe9748c)] - **test**: remove envPlus, use Object.assign everywhere (Gibson Fahnestock) [#14845](https://github.com/nodejs/node/pull/14845) +* [[`8e00315506`](https://github.com/nodejs/node/commit/8e00315506)] - **test**: check zlib version for createDeflateRaw (Daniel Bevenius) [#13697](https://github.com/nodejs/node/pull/13697) +* [[`2babae4cd4`](https://github.com/nodejs/node/commit/2babae4cd4)] - **test**: refactor test-fs-readfile-unlink (Rich Trott) [#15173](https://github.com/nodejs/node/pull/15173) +* [[`8b045747e0`](https://github.com/nodejs/node/commit/8b045747e0)] - **test**: pipe some error output if npm fails (Jeremiah Senkpiel) [#12490](https://github.com/nodejs/node/pull/12490) +* [[`6540e99547`](https://github.com/nodejs/node/commit/6540e99547)] - **test**: simplify test-tls-client-default-ciphers (Jon Moss) [#14928](https://github.com/nodejs/node/pull/14928) +* [[`ad1d745498`](https://github.com/nodejs/node/commit/ad1d745498)] - **test**: extend async addon test (Anna Henningsen) [#14922](https://github.com/nodejs/node/pull/14922) +* [[`1e231ba8c7`](https://github.com/nodejs/node/commit/1e231ba8c7)] - **test**: add known issue for vm module (Franziska Hinkelmann) [#14661](https://github.com/nodejs/node/pull/14661) +* [[`644d9905a0`](https://github.com/nodejs/node/commit/644d9905a0)] - **test**: do not modify fixtures in test-fs-chmod (Rich Trott) [#14926](https://github.com/nodejs/node/pull/14926) +* [[`168f73c5f4`](https://github.com/nodejs/node/commit/168f73c5f4)] - **test**: improve assertion fail messages (Refael Ackermann) [#14949](https://github.com/nodejs/node/pull/14949) +* [[`915b56b963`](https://github.com/nodejs/node/commit/915b56b963)] - **test**: remove unused arguments from function (Ankit Parashar) [#14931](https://github.com/nodejs/node/pull/14931) +* [[`724508295d`](https://github.com/nodejs/node/commit/724508295d)] - **test**: make timers-blocking-callback more reliable (Rich Trott) [#14831](https://github.com/nodejs/node/pull/14831) +* [[`4fb4fbea1c`](https://github.com/nodejs/node/commit/4fb4fbea1c)] - **test**: add missing console.error to exec-maxBuffer (Beth Griggs) [#14796](https://github.com/nodejs/node/pull/14796) +* [[`a284ee6129`](https://github.com/nodejs/node/commit/a284ee6129)] - **test**: invoke callback with common.mustCall() (Griffith Tchenpan) [#8597](https://github.com/nodejs/node/pull/8597) +* [[`32260b91f2`](https://github.com/nodejs/node/commit/32260b91f2)] - **test**: check crypto before requiring tls module (Daniel Bevenius) [#14708](https://github.com/nodejs/node/pull/14708) +* [[`68cf7f0b30`](https://github.com/nodejs/node/commit/68cf7f0b30)] - **test**: improve multiple zlib tests (James M Snell) [#14455](https://github.com/nodejs/node/pull/14455) +* [[`f35f06d04c`](https://github.com/nodejs/node/commit/f35f06d04c)] - **test**: improve multiple vm tests (James M Snell) [#14458](https://github.com/nodejs/node/pull/14458) +* [[`1aac05b087`](https://github.com/nodejs/node/commit/1aac05b087)] - **test**: cover all HTTP methods that parser supports (Oky Antoro) [#14773](https://github.com/nodejs/node/pull/14773) +* [[`9f330250b5`](https://github.com/nodejs/node/commit/9f330250b5)] - **test**: remove redundant `using` in cctest (XadillaX) [#14739](https://github.com/nodejs/node/pull/14739) +* [[`91649b913c`](https://github.com/nodejs/node/commit/91649b913c)] - **test**: make test-tls-connect checks more strict (Rich Trott) [#14695](https://github.com/nodejs/node/pull/14695) +* [[`9ed2c4cb0e`](https://github.com/nodejs/node/commit/9ed2c4cb0e)] - **test**: add block scoping to test-readline-interface (Rich Trott) [#14615](https://github.com/nodejs/node/pull/14615) +* [[`4fb755c432`](https://github.com/nodejs/node/commit/4fb755c432)] - **test**: set module loading error for aix (Prakash Palaniappan) [#14511](https://github.com/nodejs/node/pull/14511) +* [[`9d8464161e`](https://github.com/nodejs/node/commit/9d8464161e)] - **test**: fix conversion of microseconds in test (Nick Stanish) [#14706](https://github.com/nodejs/node/pull/14706) +* [[`28b77d1f8b`](https://github.com/nodejs/node/commit/28b77d1f8b)] - **test**: improve check in test-os (Rich Trott) [#14655](https://github.com/nodejs/node/pull/14655) +* [[`fc49cf41ea`](https://github.com/nodejs/node/commit/fc49cf41ea)] - **test**: improve multiple timers tests (James M Snell) [#14616](https://github.com/nodejs/node/pull/14616) +* [[`c88f99f1f3`](https://github.com/nodejs/node/commit/c88f99f1f3)] - **test**: improvements to various http tests (James M Snell) [#14315](https://github.com/nodejs/node/pull/14315) +* [[`860c6198c0`](https://github.com/nodejs/node/commit/860c6198c0)] - **test**: use ciphers supported by shared OpenSSL (Jérémy Lal) [#14566](https://github.com/nodejs/node/pull/14566) +* [[`8b9a05c04b`](https://github.com/nodejs/node/commit/8b9a05c04b)] - **test**: read proper inspector message size (Bartosz Sosnowski) [#14596](https://github.com/nodejs/node/pull/14596) +* [[`86497f1acc`](https://github.com/nodejs/node/commit/86497f1acc)] - **test**: mark inspector-port-zero-cluster as flaky (Refael Ackermann) +* [[`8dfc2838c8`](https://github.com/nodejs/node/commit/8dfc2838c8)] - **test**: fix test-readline-interface (Azard) [#14677](https://github.com/nodejs/node/pull/14677) +* [[`3a6392b283`](https://github.com/nodejs/node/commit/3a6392b283)] - **tls**: fix empty issuer/subject/infoAccess parsing (Ben Noordhuis) [#14473](https://github.com/nodejs/node/pull/14473) +* [[`37dd2adbac`](https://github.com/nodejs/node/commit/37dd2adbac)] - **tools**: fix linter error in html.js (Michaël Zasso) [#15063](https://github.com/nodejs/node/pull/15063) +* [[`8b3ac4b2a2`](https://github.com/nodejs/node/commit/8b3ac4b2a2)] - **tools**: add custom private key option (Ruslan Bekenev) [#14401](https://github.com/nodejs/node/pull/14401) +* [[`cac4beb764`](https://github.com/nodejs/node/commit/cac4beb764)] - **tools**: fix update-eslint.sh (Myles Borins) [#14850](https://github.com/nodejs/node/pull/14850) +* [[`debea1c531`](https://github.com/nodejs/node/commit/debea1c531)] - **tools**: delete an unused argument (phisixersai) [#14251](https://github.com/nodejs/node/pull/14251) +* [[`ca61f3bd80`](https://github.com/nodejs/node/commit/ca61f3bd80)] - **tools**: fix tools/addon-verify.js (Daniel Bevenius) [#14048](https://github.com/nodejs/node/pull/14048) +* [[`f7b6d198b9`](https://github.com/nodejs/node/commit/f7b6d198b9)] - **tools**: eslint - use `error` and `off` (Refael Ackermann) [#14061](https://github.com/nodejs/node/pull/14061) +* [[`f8b85e16cd`](https://github.com/nodejs/node/commit/f8b85e16cd)] - **tools**: replace assert-throw-arguments custom lint (Rich Trott) [#14547](https://github.com/nodejs/node/pull/14547) + ## 2017-09-05, Version 6.11.3 'Boron' (LTS), @MylesBorins diff --git a/doc/node.1 b/doc/node.1 index 5ce4b7f2daef91..2167f245216e04 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -175,15 +175,15 @@ used to enable FIPS-compliant crypto if Node.js is built with .TP .BR \-\-use\-openssl\-ca,\-\-use\-bundled\-ca Use OpenSSL's default CA store or use bundled Mozilla CA store as supplied by -current NodeJS version. The default store is selectable at build-time. +current Node.js version. The default store is selectable at build-time. Using OpenSSL store allows for external modifications of the store. For most Linux and BSD distributions, this store is maintained by the distribution maintainers and system administrators. OpenSSL CA store location is dependent on configuration of the OpenSSL library but this can be altered at runtime using -environmental variables. +environment variables. -The bundled CA store, as supplied by NodeJS, is a snapshot of Mozilla CA store +The bundled CA store, as supplied by Node.js, is a snapshot of Mozilla CA store that is fixed at release time. It is identical on all supported platforms. See \fBSSL_CERT_DIR\fR and \fBSSL_CERT_FILE\fR. diff --git a/doc/onboarding.md b/doc/onboarding.md index e1e10d88b30243..2702c9b993768d 100644 --- a/doc/onboarding.md +++ b/doc/onboarding.md @@ -43,7 +43,7 @@ onboarding session. * Use [https://github.com/notifications](https://github.com/notifications) or set up email * Watching the main repo will flood your inbox (several hundred notifications on typical weekdays), so be prepared - * `#node-dev` on [webchat.freenode.net](https://webchat.freenode.net/) is the best place to interact with the CTC / other Collaborators + * `#node-dev` on [webchat.freenode.net](https://webchat.freenode.net/) is the best place to interact with the TSC / other Collaborators * If there are any questions after the session, a good place to ask is there! * Presence is not mandatory, but please drop a note there if force-pushing to `master` @@ -67,7 +67,7 @@ onboarding session. * [**See "Labels"**](./onboarding-extras.md#labels) * There is [a bot](https://github.com/nodejs-github-bot/github-bot) that applies subsystem labels (for example, `doc`, `test`, `assert`, or `buffer`) so that we know what parts of the code base the pull request modifies. It is not perfect, of course. Feel free to apply relevant labels and remove irrelevant labels from pull requests and issues. - * Use the `ctc-review` label if a topic is controversial or isn't coming to + * Use the `tsc-review` label if a topic is controversial or isn't coming to a conclusion after an extended time. * `semver-{minor,major}`: * If a change has the remote *chance* of breaking something, use the `semver-major` label @@ -166,7 +166,7 @@ onboarding session. * Almost any mistake you could make can be fixed or reverted. * The existing Collaborators trust you and are grateful for your help! * Other repositories: - * [https://github.com/nodejs/CTC](https://github.com/nodejs/CTC) + * [https://github.com/nodejs/TSC](https://github.com/nodejs/TSC) * [https://github.com/nodejs/build](https://github.com/nodejs/build) * [https://github.com/nodejs/nodejs.org](https://github.com/nodejs/nodejs.org) * [https://github.com/nodejs/readable-stream](https://github.com/nodejs/readable-stream) diff --git a/doc/template.html b/doc/template.html index 572197beff44fe..165e47022c8124 100644 --- a/doc/template.html +++ b/doc/template.html @@ -23,11 +23,18 @@

Node.js __VERSION__ Documentation

-

- Index | - View on single page | - View as JSON -

+

diff --git a/lib/.eslintrc.yaml b/lib/.eslintrc.yaml index d8e34f85b5759d..24f54e682636ee 100644 --- a/lib/.eslintrc.yaml +++ b/lib/.eslintrc.yaml @@ -1,5 +1,5 @@ rules: # Custom rules in tools/eslint-rules - require-buffer: 2 - buffer-constructor: 2 - no-let-in-for-declaration: 2 + require-buffer: error + buffer-constructor: error + no-let-in-for-declaration: error diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 6ea801c3ed2af6..8b79d14ff12166 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -206,37 +206,41 @@ Agent.prototype.createSocket = function(req, options, cb) { } self.sockets[name].push(s); debug('sockets', name, self.sockets[name].length); - - function onFree() { - self.emit('free', s, options); - } - s.on('free', onFree); - - function onClose(err) { - debug('CLIENT socket onClose'); - // This is the only place where sockets get removed from the Agent. - // If you want to remove a socket from the pool, just close it. - // All socket errors end in a close event anyway. - self.removeSocket(s, options); - } - s.on('close', onClose); - - function onRemove() { - // We need this function for cases like HTTP 'upgrade' - // (defined by WebSockets) where we need to remove a socket from the - // pool because it'll be locked up indefinitely - debug('CLIENT socket onRemove'); - self.removeSocket(s, options); - s.removeListener('close', onClose); - s.removeListener('free', onFree); - s.removeListener('agentRemove', onRemove); - } - s.on('agentRemove', onRemove); + installListeners(self, s, options); cb(null, s); } }; -Agent.prototype.removeSocket = function(s, options) { +function installListeners(agent, s, options) { + function onFree() { + debug('CLIENT socket onFree'); + agent.emit('free', s, options); + } + s.on('free', onFree); + + function onClose(err) { + debug('CLIENT socket onClose'); + // This is the only place where sockets get removed from the Agent. + // If you want to remove a socket from the pool, just close it. + // All socket errors end in a close event anyway. + agent.removeSocket(s, options); + } + s.on('close', onClose); + + function onRemove() { + // We need this function for cases like HTTP 'upgrade' + // (defined by WebSockets) where we need to remove a socket from the + // pool because it'll be locked up indefinitely + debug('CLIENT socket onRemove'); + agent.removeSocket(s, options); + s.removeListener('close', onClose); + s.removeListener('free', onFree); + s.removeListener('agentRemove', onRemove); + } + s.on('agentRemove', onRemove); +} + +Agent.prototype.removeSocket = function removeSocket(s, options) { var name = this.getName(options); debug('removeSocket', name, 'writable:', s.writable); var sets = [this.sockets]; diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 6cf7390b841a33..8251e8e219a519 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -144,6 +144,8 @@ if (typeof Symbol === 'function' && Symbol.hasInstance) { value: function(object) { if (realHasInstance.call(this, object)) return true; + if (this !== Writable) + return false; return object && object._writableState instanceof WritableState; } diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 669110d826f7bd..5b37c119718c24 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -149,12 +149,12 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) { if (!c) return null; - if (c.issuer) c.issuer = tls.parseCertString(c.issuer); - if (c.issuerCertificate && c.issuerCertificate !== c) { + if (c.issuer != null) c.issuer = tls.parseCertString(c.issuer); + if (c.issuerCertificate != null && c.issuerCertificate !== c) { c.issuerCertificate = translatePeerCertificate(c.issuerCertificate); } - if (c.subject) c.subject = tls.parseCertString(c.subject); - if (c.infoAccess) { + if (c.subject != null) c.subject = tls.parseCertString(c.subject); + if (c.infoAccess != null) { var info = c.infoAccess; c.infoAccess = {}; diff --git a/lib/assert.js b/lib/assert.js index 219842f953a12c..cfc7addbcb0fcc 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -20,8 +20,7 @@ 'use strict'; -// UTILITY -const compare = process.binding('buffer').compare; +const { compare } = process.binding('buffer'); const util = require('util'); const Buffer = require('buffer').Buffer; const pToString = (obj) => Object.prototype.toString.call(obj); @@ -49,7 +48,7 @@ assert.AssertionError = function AssertionError(options) { this.message = getMessage(this); this.generatedMessage = true; } - var stackStartFunction = options.stackStartFunction || fail; + const stackStartFunction = options.stackStartFunction || fail; Error.captureStackTrace(this, stackStartFunction); }; @@ -73,7 +72,7 @@ function getMessage(self) { // All of the following functions must throw an AssertionError // when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide +// may be undefined if not provided. All assertion methods provide // both the actual and expected values to the assertion error for // display purposes. @@ -86,25 +85,16 @@ function fail(actual, expected, message, operator, stackStartFunction) { stackStartFunction: stackStartFunction }); } - -// EXTENSION! allows for well behaved errors defined elsewhere. assert.fail = fail; // Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. - +// by !!value. function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); + if (!value) fail(value, true, message, '==', ok); } assert.ok = ok; -// The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); +// The equality assertion tests shallow, coercive equality with ==. /* eslint-disable no-restricted-properties */ assert.equal = function equal(actual, expected, message) { if (actual != expected) fail(actual, expected, message, '==', assert.equal); @@ -112,31 +102,27 @@ assert.equal = function equal(actual, expected, message) { // The non-equality assertion tests for whether two objects are not // equal with !=. -// assert.notEqual(actual, expected, message_opt); - assert.notEqual = function notEqual(actual, expected, message) { if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); + fail(actual, expected, message, '!=', notEqual); } }; // The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); - assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); + if (!innerDeepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', deepEqual); } }; /* eslint-enable */ assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + if (!innerDeepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', deepStrictEqual); } }; -function _deepEqual(actual, expected, strict, memos) { +function innerDeepEqual(actual, expected, strict, memos) { // All identical values are equivalent, as determined by ===. if (actual === expected) { return true; @@ -247,45 +233,40 @@ function objEquiv(a, b, strict, actualVisitedObjects) { // Possibly expensive deep test: for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; - if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + if (!innerDeepEqual(a[key], b[key], strict, actualVisitedObjects)) return false; } return true; } // The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + if (innerDeepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', notDeepEqual); } }; assert.notDeepStrictEqual = notDeepStrictEqual; function notDeepStrictEqual(actual, expected, message) { - if (_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + if (innerDeepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', + notDeepStrictEqual); } } // The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - assert.strictEqual = function strictEqual(actual, expected, message) { if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); + fail(actual, expected, message, '===', strictEqual); } }; // The strict non-equality assertion tests for strict inequality, as // determined by !==. -// assert.notStrictEqual(actual, expected, message_opt); - assert.notStrictEqual = function notStrictEqual(actual, expected, message) { if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); + fail(actual, expected, message, '!==', notStrictEqual); } }; @@ -314,7 +295,7 @@ function expectedException(actual, expected) { return expected.call({}, actual) === true; } -function _tryBlock(block) { +function tryBlock(block) { var error; try { block(); @@ -324,9 +305,7 @@ function _tryBlock(block) { return error; } -function _throws(shouldThrow, block, expected, message) { - var actual; - +function innerThrows(shouldThrow, block, expected, message) { if (typeof block !== 'function') { throw new TypeError('"block" argument must be a function'); } @@ -336,13 +315,13 @@ function _throws(shouldThrow, block, expected, message) { expected = null; } - actual = _tryBlock(block); + const actual = tryBlock(block); message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + (message ? ' ' + message : '.'); if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); + fail(actual, expected, 'Missing expected exception' + message, fail); } const userProvidedMessage = typeof message === 'string'; @@ -353,7 +332,7 @@ function _throws(shouldThrow, block, expected, message) { userProvidedMessage && expectedException(actual, expected)) || isUnexpectedException) { - fail(actual, expected, 'Got unwanted exception' + message); + fail(actual, expected, 'Got unwanted exception' + message, fail); } if ((shouldThrow && actual && expected && @@ -363,15 +342,12 @@ function _throws(shouldThrow, block, expected, message) { } // Expected to throw an error. -// assert.throws(block, Error_opt, message_opt); - -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws(true, block, error, message); +assert.throws = function throws(block, error, message) { + innerThrows(true, block, error, message); }; -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws(false, block, error, message); +assert.doesNotThrow = function doesNotThrow(block, error, message) { + innerThrows(false, block, error, message); }; -assert.ifError = function(err) { if (err) throw err; }; +assert.ifError = function ifError(err) { if (err) throw err; }; diff --git a/lib/crypto.js b/lib/crypto.js index 439a446ac2219d..f2dede115487b0 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -59,24 +59,24 @@ function Hash(algorithm, options) { util.inherits(Hash, LazyTransform); -Hash.prototype._transform = function(chunk, encoding, callback) { +Hash.prototype._transform = function _transform(chunk, encoding, callback) { this._handle.update(chunk, encoding); callback(); }; -Hash.prototype._flush = function(callback) { +Hash.prototype._flush = function _flush(callback) { this.push(this._handle.digest()); callback(); }; -Hash.prototype.update = function(data, encoding) { +Hash.prototype.update = function update(data, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; this._handle.update(data, encoding); return this; }; -Hash.prototype.digest = function(outputEncoding) { +Hash.prototype.digest = function digest(outputEncoding) { outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; // Explicit conversion for backward compatibility. return this._handle.digest(`${outputEncoding}`); @@ -123,12 +123,12 @@ function Cipher(cipher, password, options) { util.inherits(Cipher, LazyTransform); -Cipher.prototype._transform = function(chunk, encoding, callback) { +Cipher.prototype._transform = function _transform(chunk, encoding, callback) { this.push(this._handle.update(chunk, encoding)); callback(); }; -Cipher.prototype._flush = function(callback) { +Cipher.prototype._flush = function _flush(callback) { try { this.push(this._handle.final()); } catch (e) { @@ -138,7 +138,7 @@ Cipher.prototype._flush = function(callback) { callback(); }; -Cipher.prototype.update = function(data, inputEncoding, outputEncoding) { +Cipher.prototype.update = function update(data, inputEncoding, outputEncoding) { inputEncoding = inputEncoding || exports.DEFAULT_ENCODING; outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; @@ -153,7 +153,7 @@ Cipher.prototype.update = function(data, inputEncoding, outputEncoding) { }; -Cipher.prototype.final = function(outputEncoding) { +Cipher.prototype.final = function final(outputEncoding) { outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; var ret = this._handle.final(); @@ -166,22 +166,22 @@ Cipher.prototype.final = function(outputEncoding) { }; -Cipher.prototype.setAutoPadding = function(ap) { +Cipher.prototype.setAutoPadding = function setAutoPadding(ap) { this._handle.setAutoPadding(ap); return this; }; -Cipher.prototype.getAuthTag = function() { +Cipher.prototype.getAuthTag = function getAuthTag() { return this._handle.getAuthTag(); }; -Cipher.prototype.setAuthTag = function(tagbuf) { +Cipher.prototype.setAuthTag = function setAuthTag(tagbuf) { this._handle.setAuthTag(tagbuf); return this; }; -Cipher.prototype.setAAD = function(aadbuf) { +Cipher.prototype.setAAD = function setAAD(aadbuf) { this._handle.setAAD(aadbuf); return this; }; @@ -270,14 +270,14 @@ function Sign(algorithm, options) { util.inherits(Sign, stream.Writable); -Sign.prototype._write = function(chunk, encoding, callback) { +Sign.prototype._write = function _write(chunk, encoding, callback) { this._handle.update(chunk, encoding); callback(); }; Sign.prototype.update = Hash.prototype.update; -Sign.prototype.sign = function(options, encoding) { +Sign.prototype.sign = function sign(options, encoding) { if (!options) throw new Error('No key provided to sign'); @@ -309,7 +309,7 @@ util.inherits(Verify, stream.Writable); Verify.prototype._write = Sign.prototype._write; Verify.prototype.update = Sign.prototype.update; -Verify.prototype.verify = function(object, signature, sigEncoding) { +Verify.prototype.verify = function verify(object, signature, sigEncoding) { sigEncoding = sigEncoding || exports.DEFAULT_ENCODING; return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding)); }; @@ -477,14 +477,14 @@ function dhGetPrivateKey(encoding) { } -DiffieHellman.prototype.setPublicKey = function(key, encoding) { +DiffieHellman.prototype.setPublicKey = function setPublicKey(key, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; this._handle.setPublicKey(toBuf(key, encoding)); return this; }; -DiffieHellman.prototype.setPrivateKey = function(key, encoding) { +DiffieHellman.prototype.setPrivateKey = function setPrivateKey(key, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; this._handle.setPrivateKey(toBuf(key, encoding)); return this; @@ -602,19 +602,21 @@ function Certificate() { } -Certificate.prototype.verifySpkac = function(object) { +Certificate.prototype.verifySpkac = function verifySpkac(object) { return binding.certVerifySpkac(object); }; -Certificate.prototype.exportPublicKey = function(object, encoding) { - return binding.certExportPublicKey(toBuf(object, encoding)); -}; +Certificate.prototype.exportPublicKey = + function exportPublicKey(object, encoding) { + return binding.certExportPublicKey(toBuf(object, encoding)); + }; -Certificate.prototype.exportChallenge = function(object, encoding) { - return binding.certExportChallenge(toBuf(object, encoding)); -}; +Certificate.prototype.exportChallenge = + function exportChallenge(object, encoding) { + return binding.certExportChallenge(toBuf(object, encoding)); + }; exports.setEngine = function setEngine(id, flags) { diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index de215dc2dce62b..310dc9dd029375 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -317,20 +317,14 @@ } function tryGetCwd(path) { - var threw = true; - var cwd; try { - cwd = process.cwd(); - threw = false; - } finally { - if (threw) { - // getcwd(3) can fail if the current working directory has been deleted. - // Fall back to the directory name of the (absolute) executable path. - // It's not really correct but what are the alternatives? - return path.dirname(process.execPath); - } + return process.cwd(); + } catch (ex) { + // getcwd(3) can fail if the current working directory has been deleted. + // Fall back to the directory name of the (absolute) executable path. + // It's not really correct but what are the alternatives? + return path.dirname(process.execPath); } - return cwd; } function evalScript(name) { diff --git a/lib/internal/process.js b/lib/internal/process.js index c8a58504fcf307..76098bb4d8a5b6 100644 --- a/lib/internal/process.js +++ b/lib/internal/process.js @@ -1,5 +1,7 @@ 'use strict'; +const util = require('util'); + var _lazyConstants = null; function lazyConstants() { @@ -185,10 +187,8 @@ function setupKillAndExit() { } } - if (err) { - const errnoException = require('util')._errnoException; - throw errnoException(err, 'kill'); - } + if (err) + throw util._errnoException(err, 'kill'); return true; }; @@ -220,8 +220,7 @@ function setupSignalHandlers() { const err = wrap.start(signum); if (err) { wrap.close(); - const errnoException = require('util')._errnoException; - throw errnoException(err, 'uv_signal_start'); + throw util._errnoException(err, 'uv_signal_start'); } signalWraps[type] = wrap; @@ -261,9 +260,8 @@ function setupChannel() { function setupRawDebug() { - const format = require('util').format; const rawDebug = process._rawDebug; process._rawDebug = function() { - rawDebug(format.apply(null, arguments)); + rawDebug(util.format.apply(null, arguments)); }; } diff --git a/lib/net.js b/lib/net.js index 5e653c61d2106c..094f118cefaa96 100644 --- a/lib/net.js +++ b/lib/net.js @@ -912,8 +912,9 @@ Socket.prototype.connect = function(options, cb) { this._sockname = null; } - var pipe = !!options.path; - debug('pipe', pipe, options.path); + const path = options.path; + var pipe = !!path; + debug('pipe', pipe, path); if (!this._handle) { this._handle = pipe ? new Pipe() : new TCP(); @@ -930,7 +931,10 @@ Socket.prototype.connect = function(options, cb) { this.writable = true; if (pipe) { - connect(this, options.path); + if (typeof path !== 'string') { + throw new TypeError('"path" option must be a string: ' + path); + } + connect(this, path); } else { lookupAndConnect(this, options); } @@ -1338,7 +1342,7 @@ Server.prototype.listen = function() { self.once('listening', lastArg); } - var port = toNumber(arguments[0]); + var port = typeof arguments[0] === 'undefined' ? 0 : toNumber(arguments[0]); // The third optional argument is the backlog size. // When the ip is omitted it can be the second argument. diff --git a/lib/readline.js b/lib/readline.js index c167db6eb10f08..ca99fe15c0a593 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -8,7 +8,6 @@ const kHistorySize = 30; const kMincrlfDelay = 100; -const kMaxcrlfDelay = 2000; const util = require('util'); const debug = util.debuglog('readline'); @@ -83,8 +82,8 @@ function Interface(input, output, completer, terminal) { this.input = input; this.historySize = historySize; this.removeHistoryDuplicates = !!removeHistoryDuplicates; - this.crlfDelay = Math.max(kMincrlfDelay, - Math.min(kMaxcrlfDelay, crlfDelay >>> 0)); + this.crlfDelay = crlfDelay ? + Math.max(kMincrlfDelay, crlfDelay) : kMincrlfDelay; // Check arity, 2 - for async, 1 for sync if (typeof completer === 'function') { diff --git a/lib/repl.js b/lib/repl.js index eb539cca0ef456..127fd80bf82f65 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -61,7 +61,7 @@ try { } // hack for repl require to work properly with node_modules folders -module.paths = require('module')._nodeModulePaths(module.filename); +module.paths = Module._nodeModulePaths(module.filename); // If obj.hasOwnProperty has been overridden, then calling // obj.hasOwnProperty(prop) will break. @@ -519,10 +519,11 @@ function REPLServer(prompt, // Check to see if a REPL keyword was used. If it returns true, // display next prompt and return. - if (cmd && cmd.charAt(0) === '.' && isNaN(parseFloat(cmd))) { - var matches = cmd.match(/^\.([^\s]+)\s*(.*)$/); - var keyword = matches && matches[1]; - var rest = matches && matches[2]; + if (cmd && cmd.charAt(0) === '.' && cmd.charAt(1) !== '.' && + isNaN(parseFloat(cmd))) { + const matches = cmd.match(/^\.([^\s]+)\s*(.*)$/); + const keyword = matches && matches[1]; + const rest = matches && matches[2]; if (self.parseREPLKeyword(keyword, rest) === true) { return; } else if (!self.bufferedCommand) { @@ -869,7 +870,7 @@ function complete(line, callback) { filter = match[1]; var dir, files, f, name, base, ext, abs, subfiles, s; group = []; - var paths = module.paths.concat(require('module').globalPaths); + var paths = module.paths.concat(Module.globalPaths); for (i = 0; i < paths.length; i++) { dir = path.resolve(paths[i], subdir); try { diff --git a/src/node.cc b/src/node.cc index 984c228205378d..33d97a0fcc8664 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1230,7 +1230,7 @@ void SetupPromises(const FunctionCallbackInfo& args) { env->process_object()->Delete( env->context(), - FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupPromises")).FromJust(); + FIXED_ONE_BYTE_STRING(isolate, "_setupPromises")).FromJust(); } diff --git a/src/node_file.cc b/src/node_file.cc index 90c88e5cb33e8b..af3ebdb1214816 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -571,6 +571,9 @@ static void InternalModuleReadFile(const FunctionCallbackInfo& args) { CHECK(args[0]->IsString()); node::Utf8Value path(env->isolate(), args[0]); + if (strlen(*path) != path.length()) + return; // Contains a nul byte. + uv_fs_t open_req; const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr); uv_fs_req_cleanup(&open_req); diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index bc9b5d953e8ebf..45d54ab548f862 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -472,6 +472,7 @@ class Parser : public AsyncWrap { static void Consume(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder()); + CHECK(args[0]->IsExternal()); Local stream_obj = args[0].As(); StreamBase* stream = static_cast(stream_obj->Value()); CHECK_NE(stream, nullptr); @@ -502,6 +503,7 @@ class Parser : public AsyncWrap { stream->set_alloc_cb(parser->prev_alloc_cb_); stream->set_read_cb(parser->prev_read_cb_); + stream->Unconsume(); } parser->prev_alloc_cb_.clear(); diff --git a/src/node_revert.h b/src/node_revert.h index b4c3633e947a6e..e76c08f58f3950 100644 --- a/src/node_revert.h +++ b/src/node_revert.h @@ -8,7 +8,7 @@ /** * Note that it is expected for this list to vary across specific LTS and * Stable versions! Only CVE's whose fixes require *breaking* changes within - * a given LTS or Stable may be added to this list, and only with CTC + * a given LTS or Stable may be added to this list, and only with TSC * consensus. * * For *master* this list should always be empty! diff --git a/src/node_version.h b/src/node_version.h index 903b0b55c4ff48..b03e541b4d0537 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -8,7 +8,7 @@ #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Boron" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/stream_base.h b/src/stream_base.h index 35929750bfbc54..56cd4129d8a373 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -234,6 +234,11 @@ class StreamBase : public StreamResource { consumed_ = true; } + inline void Unconsume() { + CHECK_EQ(consumed_, true); + consumed_ = false; + } + template inline Outer* Cast() { return static_cast(Cast()); } diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index d294b641ffa444..7709e24a6b4d93 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -222,13 +222,18 @@ void StreamWrap::OnReadImpl(ssize_t nread, } -void StreamWrap::OnReadCommon(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf, - uv_handle_type pending) { +void StreamWrap::OnRead(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { StreamWrap* wrap = static_cast(handle->data); HandleScope scope(wrap->env()->isolate()); Context::Scope context_scope(wrap->env()->context()); + uv_handle_type type = UV_UNKNOWN_HANDLE; + + if (wrap->is_named_pipe_ipc() && + uv_pipe_pending_count(reinterpret_cast(handle)) > 0) { + type = uv_pipe_pending_type(reinterpret_cast(handle)); + } // We should not be getting this callback if someone as already called // uv_close() on the handle. @@ -242,22 +247,7 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, } } - static_cast(wrap)->OnRead(nread, buf, pending); -} - - -void StreamWrap::OnRead(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - StreamWrap* wrap = static_cast(handle->data); - uv_handle_type type = UV_UNKNOWN_HANDLE; - - if (wrap->is_named_pipe_ipc() && - uv_pipe_pending_count(reinterpret_cast(handle)) > 0) { - type = uv_pipe_pending_type(reinterpret_cast(handle)); - } - - OnReadCommon(handle, nread, buf, type); + static_cast(wrap)->OnRead(nread, buf, type); } diff --git a/src/stream_wrap.h b/src/stream_wrap.h index e930670202d2d8..3b2ce8ee3beb00 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -84,10 +84,6 @@ class StreamWrap : public HandleWrap, public StreamBase { static void OnRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf); - static void OnReadCommon(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf, - uv_handle_type pending); static void AfterWrite(uv_write_t* req, int status); static void AfterShutdown(uv_shutdown_t* req, int status); diff --git a/test/.eslintrc.yaml b/test/.eslintrc.yaml index 4fea04d632f2d4..6d2c0ec90d22b0 100644 --- a/test/.eslintrc.yaml +++ b/test/.eslintrc.yaml @@ -3,12 +3,12 @@ rules: # ECMAScript 6 # http://eslint.org/docs/rules/#ecmascript-6 - no-var: 2 - prefer-const: 2 + no-var: error + prefer-const: error # Custom rules in tools/eslint-rules prefer-common-mustnotcall: 2 ## common module is mandatory in tests - required-modules: [2, common] - prefer-assert-methods: 2 + required-modules: [error, common] + prefer-assert-methods: error diff --git a/test/abort/test-http-parser-consume.js b/test/abort/test-http-parser-consume.js new file mode 100644 index 00000000000000..4a05a299a8e956 --- /dev/null +++ b/test/abort/test-http-parser-consume.js @@ -0,0 +1,28 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); +const spawn = require('child_process').spawn; + +if (process.argv[2] === 'child') { + const server = http.createServer(common.mustCall((req, res) => { + res.end('hello'); + })); + + server.listen(0, common.mustCall((s) => { + const rr = http.get( + { port: server.address().port }, + common.mustCall((d) => { + // This bad input (0) should abort the parser and the process + rr.parser.consume(0); + server.close(); + })); + })); +} else { + const child = spawn(process.execPath, [__filename, 'child'], + { stdio: 'inherit' }); + child.on('exit', common.mustCall((code, signal) => { + assert(common.nodeProcessAborted(code, signal), + 'process should have aborted, but did not'); + })); +} diff --git a/test/addons/async-hello-world/binding.cc b/test/addons/async-hello-world/binding.cc index da2bd417cd9a6f..42291c49011fb3 100644 --- a/test/addons/async-hello-world/binding.cc +++ b/test/addons/async-hello-world/binding.cc @@ -28,6 +28,7 @@ void DoAsync(uv_work_t* r) { req->output = req->input * 2; } +template void AfterAsync(uv_work_t* r) { async_req* req = reinterpret_cast(r->data); v8::Isolate* isolate = req->isolate; @@ -40,9 +41,18 @@ void AfterAsync(uv_work_t* r) { v8::TryCatch try_catch(isolate); + v8::Local global = isolate->GetCurrentContext()->Global(); v8::Local callback = v8::Local::New(isolate, req->callback); - callback->Call(isolate->GetCurrentContext()->Global(), 2, argv); + + if (use_makecallback) { + v8::Local ret = + node::MakeCallback(isolate, global, callback, 2, argv); + // This should be changed to an empty handle. + assert(!ret.IsEmpty()); + } else { + callback->Call(global, 2, argv); + } // cleanup req->callback.Reset(); @@ -53,6 +63,7 @@ void AfterAsync(uv_work_t* r) { } } +template void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); @@ -69,11 +80,12 @@ void Method(const v8::FunctionCallbackInfo& args) { uv_queue_work(uv_default_loop(), &req->req, DoAsync, - (uv_after_work_cb)AfterAsync); + (uv_after_work_cb)AfterAsync); } void init(v8::Local exports, v8::Local module) { - NODE_SET_METHOD(module, "exports", Method); + NODE_SET_METHOD(exports, "runCall", Method); + NODE_SET_METHOD(exports, "runMakeCallback", Method); } NODE_MODULE(binding, init) diff --git a/test/addons/async-hello-world/test-makecallback-uncaught.js b/test/addons/async-hello-world/test-makecallback-uncaught.js new file mode 100644 index 00000000000000..c207f535bee6eb --- /dev/null +++ b/test/addons/async-hello-world/test-makecallback-uncaught.js @@ -0,0 +1,9 @@ +'use strict'; +const common = require('../../common'); +const { runMakeCallback } = require(`./build/${common.buildType}/binding`); + +process.on('uncaughtException', common.mustCall()); + +runMakeCallback(5, common.mustCall(() => { + throw new Error('foo'); +})); diff --git a/test/addons/async-hello-world/test-makecallback.js b/test/addons/async-hello-world/test-makecallback.js new file mode 100644 index 00000000000000..0edf052e8c34fc --- /dev/null +++ b/test/addons/async-hello-world/test-makecallback.js @@ -0,0 +1,10 @@ +'use strict'; +const common = require('../../common'); +const assert = require('assert'); +const { runMakeCallback } = require(`./build/${common.buildType}/binding`); + +runMakeCallback(5, common.mustCall(function(err, val) { + assert.strictEqual(err, null); + assert.strictEqual(val, 10); + process.nextTick(common.mustCall()); +})); diff --git a/test/addons/async-hello-world/test.js b/test/addons/async-hello-world/test.js index fbd0d7eeb7ef13..f24071087c0629 100644 --- a/test/addons/async-hello-world/test.js +++ b/test/addons/async-hello-world/test.js @@ -1,9 +1,9 @@ 'use strict'; const common = require('../../common'); const assert = require('assert'); -const binding = require(`./build/${common.buildType}/binding`); +const { runCall } = require(`./build/${common.buildType}/binding`); -binding(5, common.mustCall(function(err, val) { +runCall(5, common.mustCall(function(err, val) { assert.strictEqual(err, null); assert.strictEqual(val, 10); process.nextTick(common.mustCall()); diff --git a/test/cctest/node_test_fixture.h b/test/cctest/node_test_fixture.h index 59988ba6cb2a3e..e32e7e6dc6b3ba 100644 --- a/test/cctest/node_test_fixture.h +++ b/test/cctest/node_test_fixture.h @@ -8,13 +8,6 @@ #include "v8.h" #include "libplatform/libplatform.h" -using node::Environment; -using node::IsolateData; -using node::CreateIsolateData; -using node::CreateEnvironment; -using node::AtExit; -using node::RunAtExit; - class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: virtual void* Allocate(size_t length) { diff --git a/test/common/README.md b/test/common/README.md index ca8613796f3f49..c84acaba390500 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -280,6 +280,42 @@ The realpath of the 'tmp' directory. Name of the temp directory used by tests. +## Countdown Module + +The `Countdown` module provides a simple countdown mechanism for tests that +require a particular action to be taken after a given number of completed +tasks (for instance, shutting down an HTTP server after a specific number of +requests). + + +```js +const Countdown = require('../common/countdown'); + +function doSomething() { + console.log('.'); +} + +const countdown = new Countdown(2, doSomething); +countdown.dec(); +countdown.dec(); +``` + +### new Countdown(limit, callback) + +* `limit` {number} +* `callback` {function} + +Creates a new `Countdown` instance. + +### Countdown.prototype.dec() + +Decrements the `Countdown` counter. + +### Coutndown.prototype.remaining + +Specifies the remaining number of times `Countdown.prototype.dec()` must be +called before the callback is invoked. + ## WPT Module The wpt.js module is a port of parts of diff --git a/test/common/countdown.js b/test/common/countdown.js new file mode 100644 index 00000000000000..6a22be0a07eb0b --- /dev/null +++ b/test/common/countdown.js @@ -0,0 +1,27 @@ +/* eslint-disable required-modules */ +'use strict'; + +const assert = require('assert'); +const kLimit = Symbol('limit'); +const kCallback = Symbol('callback'); + +class Countdown { + constructor(limit, cb) { + assert.strictEqual(typeof limit, 'number'); + assert.strictEqual(typeof cb, 'function'); + this[kLimit] = limit; + this[kCallback] = cb; + } + + dec() { + assert(this[kLimit] > 0, 'Countdown expired'); + if (--this[kLimit] === 0) + this[kCallback](); + } + + get remaining() { + return this[kLimit]; + } +} + +module.exports = Countdown; diff --git a/test/common/index.js b/test/common/index.js index 9932a6daf2bda6..df223e051935a8 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -4,7 +4,7 @@ const path = require('path'); const fs = require('fs'); const assert = require('assert'); const os = require('os'); -const child_process = require('child_process'); +const { exec, execSync, spawn, spawnSync } = require('child_process'); const stream = require('stream'); const util = require('util'); const Timer = process.binding('timer_wrap').Timer; @@ -121,7 +121,7 @@ Object.defineProperty(exports, 'inFreeBSDJail', { if (inFreeBSDJail !== null) return inFreeBSDJail; if (exports.isFreeBSD && - child_process.execSync('sysctl -n security.jail.jailed').toString() === + execSync('sysctl -n security.jail.jailed').toString() === '1\n') { inFreeBSDJail = true; } else { @@ -168,7 +168,7 @@ Object.defineProperty(exports, 'opensslCli', {get: function() { if (exports.isWindows) opensslCli += '.exe'; - const opensslCmd = child_process.spawnSync(opensslCli, ['version']); + const opensslCmd = spawnSync(opensslCli, ['version']); if (opensslCmd.status !== 0 || opensslCmd.error !== undefined) { // openssl command cannot be executed opensslCli = false; @@ -219,7 +219,7 @@ exports.childShouldThrowAndAbort = function() { } testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `; testCmd += `"${process.argv[1]}" child`; - const child = child_process.exec(testCmd); + const child = exec(testCmd); child.on('exit', function onExit(exitCode, signal) { const errMsg = 'Test should have aborted ' + `but instead exited with exit code ${exitCode}` + @@ -239,8 +239,6 @@ exports.ddCommand = function(filename, kilobytes) { exports.spawnCat = function(options) { - const spawn = require('child_process').spawn; - if (exports.isWindows) { return spawn('more', [], options); } else { @@ -250,8 +248,6 @@ exports.spawnCat = function(options) { exports.spawnSyncCat = function(options) { - const spawnSync = require('child_process').spawnSync; - if (exports.isWindows) { return spawnSync('more', [], options); } else { @@ -261,8 +257,6 @@ exports.spawnSyncCat = function(options) { exports.spawnPwd = function(options) { - const spawn = require('child_process').spawn; - if (exports.isWindows) { return spawn('cmd.exe', ['/c', 'cd'], options); } else { @@ -272,8 +266,6 @@ exports.spawnPwd = function(options) { exports.spawnSyncPwd = function(options) { - const spawnSync = require('child_process').spawnSync; - if (exports.isWindows) { return spawnSync('cmd.exe', ['/c', 'cd'], options); } else { diff --git a/test/fixtures/a1.js b/test/fixtures/a1.js deleted file mode 100644 index 990a78534a68c9..00000000000000 --- a/test/fixtures/a1.js +++ /dev/null @@ -1,25 +0,0 @@ -var c = require('./b/c'); - -console.error('load fixtures/a.js'); - -var string = 'A'; - -exports.SomeClass = c.SomeClass; - -exports.A = function() { - return string; -}; - -exports.C = function() { - return c.C(); -}; - -exports.D = function() { - return c.D(); -}; - -exports.number = 42; - -process.on('exit', function() { - string = 'A done'; -}); diff --git a/test/inspector/inspector-helper.js b/test/inspector/inspector-helper.js index 53b9ebdca75b54..17842ffd98961a 100644 --- a/test/inspector/inspector-helper.js +++ b/test/inspector/inspector-helper.js @@ -48,6 +48,7 @@ function send(socket, message, id, callback) { } function parseWSFrame(buffer, handler) { + // Protocol described in https://tools.ietf.org/html/rfc6455#section-5 if (buffer.length < 2) return 0; assert.strictEqual(0x81, buffer[0]); @@ -59,7 +60,8 @@ function parseWSFrame(buffer, handler) { dataLen = buffer.readUInt16BE(2); bodyOffset = 4; } else if (dataLen === 127) { - dataLen = buffer.readUInt32BE(2); + assert(buffer[2] === 0 && buffer[3] === 0, 'Inspector message too big'); + dataLen = buffer.readUIntBE(4, 6); bodyOffset = 10; } if (buffer.length < bodyOffset + dataLen) diff --git a/test/inspector/inspector.status b/test/inspector/inspector.status index ed6a782b9031a7..070d817b2c3ab2 100644 --- a/test/inspector/inspector.status +++ b/test/inspector/inspector.status @@ -5,5 +5,6 @@ prefix inspector # sample-test : PASS,FLAKY [true] # This section applies to all platforms +test-inspector-port-zero-cluster : PASS,FLAKY [$system==win32] diff --git a/test/known_issues/test-vm-strict-mode.js b/test/known_issues/test-vm-strict-mode.js new file mode 100644 index 00000000000000..9528944732930c --- /dev/null +++ b/test/known_issues/test-vm-strict-mode.js @@ -0,0 +1,17 @@ +'use strict'; +// https://github.com/nodejs/node/issues/12300 + +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const ctx = vm.createContext({ x: 42 }); + +// The following line wrongly throws an +// error because GlobalPropertySetterCallback() +// does not check if the property exists +// on the sandbox. It should just set x to 1 +// instead of throwing an error. +vm.runInContext('"use strict"; x = 1', ctx); + +assert.strictEqual(ctx.x, 1); diff --git a/test/parallel/test-assert-fail.js b/test/parallel/test-assert-fail.js new file mode 100644 index 00000000000000..0423b35ec4d901 --- /dev/null +++ b/test/parallel/test-assert-fail.js @@ -0,0 +1,10 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); + +// The stackFrameFunction should exclude the foo frame +assert.throws( + function foo() { assert.fail('first', 'second', 'message', '!==', foo); }, + (err) => !/foo/m.test(err.stack) +); diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js index f5ecb274a86a32..7eed19cc539466 100644 --- a/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/parallel/test-assert-typedarray-deepequal.js @@ -2,7 +2,6 @@ require('../common'); const assert = require('assert'); -const a = require('assert'); function makeBlock(f) { const args = Array.prototype.slice.call(arguments, 1); @@ -51,7 +50,8 @@ equalArrayPairs.forEach((arrayPair) => { notEqualArrayPairs.forEach((arrayPair) => { assert.throws( - makeBlock(a.deepEqual, arrayPair[0], arrayPair[1]), - a.AssertionError + // eslint-disable-next-line no-restricted-properties + makeBlock(assert.deepEqual, arrayPair[0], arrayPair[1]), + assert.AssertionError ); }); diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 30ab10a1283b82..aa51eb7e523e2e 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -1,7 +1,7 @@ 'use strict'; require('../common'); const assert = require('assert'); -const a = require('assert'); +const a = assert; function makeBlock(f) { const args = Array.prototype.slice.call(arguments, 1); @@ -345,11 +345,11 @@ function thrower(errorConstructor) { assert.throws(makeBlock(thrower, a.AssertionError), a.AssertionError, 'message'); assert.throws(makeBlock(thrower, a.AssertionError), a.AssertionError); -// eslint-disable-next-line assert-throws-arguments +// eslint-disable-next-line no-restricted-syntax assert.throws(makeBlock(thrower, a.AssertionError)); // if not passing an error, catch all. -// eslint-disable-next-line assert-throws-arguments +// eslint-disable-next-line no-restricted-syntax assert.throws(makeBlock(thrower, TypeError)); // when passing a type, only catch errors of the appropriate type @@ -524,7 +524,7 @@ testAssertionMessage({a: NaN, b: Infinity, c: -Infinity}, // #2893 try { - // eslint-disable-next-line assert-throws-arguments + // eslint-disable-next-line no-restricted-syntax assert.throws(function() { assert.ifError(null); }); diff --git a/test/parallel/test-child-process-env.js b/test/parallel/test-child-process-env.js index 9430e79593e0fd..f25a6f8bb4f50a 100644 --- a/test/parallel/test-child-process-env.js +++ b/test/parallel/test-child-process-env.js @@ -13,9 +13,12 @@ Object.setPrototypeOf(env, { let child; if (common.isWindows) { - child = spawn('cmd.exe', ['/c', 'set'], {env: env}); + child = spawn('cmd.exe', ['/c', 'set'], + Object.assign({}, process.env, { env: env })); } else { - child = spawn('/usr/bin/env', [], {env: env}); + child = spawn('/usr/bin/env', [], { env: env }); + child = spawn('/usr/bin/env', [], + Object.assign({}, process.env, { env: env })); } diff --git a/test/parallel/test-child-process-exec-env.js b/test/parallel/test-child-process-exec-env.js index 15156bbd311eb3..c3e5eb8ea7daee 100644 --- a/test/parallel/test-child-process-exec-env.js +++ b/test/parallel/test-child-process-exec-env.js @@ -23,7 +23,9 @@ function after(err, stdout, stderr) { if (!common.isWindows) { child = exec('/usr/bin/env', { env: { 'HELLO': 'WORLD' } }, after); } else { - child = exec('set', { env: { 'HELLO': 'WORLD' } }, after); + child = exec('set', + { env: Object.assign({}, process.env, { 'HELLO': 'WORLD' }) }, + after); } child.stdout.setEncoding('utf8'); diff --git a/test/parallel/test-child-process-exec-maxBuffer.js b/test/parallel/test-child-process-exec-maxBuffer.js index 714e029d728b1e..2b6b9473d64367 100644 --- a/test/parallel/test-child-process-exec-maxBuffer.js +++ b/test/parallel/test-child-process-exec-maxBuffer.js @@ -25,7 +25,7 @@ const unicode = '中文测试'; // length = 4, byte length = 12 } { - const cmd = `"${process.execPath}" -e "console.('${unicode}');"`; + const cmd = `"${process.execPath}" -e "console.error('${unicode}');"`; cp.exec(cmd, {maxBuffer: 10}, checkFactory('stderr')); } diff --git a/test/parallel/test-child-process-fork-and-spawn.js b/test/parallel/test-child-process-fork-and-spawn.js index 5807147a1c947d..b3e7e29f7d9bd0 100644 --- a/test/parallel/test-child-process-fork-and-spawn.js +++ b/test/parallel/test-child-process-fork-and-spawn.js @@ -1,8 +1,7 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const spawn = require('child_process').spawn; -const fork = require('child_process').fork; +const { fork, spawn } = require('child_process'); // Fork, then spawn. The spawned process should not hang. switch (process.argv[2] || '') { diff --git a/test/parallel/test-child-process-send-returns-boolean.js b/test/parallel/test-child-process-send-returns-boolean.js index 379f76a67390b9..d986b633d4140b 100644 --- a/test/parallel/test-child-process-send-returns-boolean.js +++ b/test/parallel/test-child-process-send-returns-boolean.js @@ -3,8 +3,7 @@ const common = require('../common'); const assert = require('assert'); const path = require('path'); const net = require('net'); -const fork = require('child_process').fork; -const spawn = require('child_process').spawn; +const { fork, spawn } = require('child_process'); const emptyFile = path.join(common.fixturesDir, 'empty.js'); diff --git a/test/parallel/test-common-countdown.js b/test/parallel/test-common-countdown.js new file mode 100644 index 00000000000000..ec0543f36fec74 --- /dev/null +++ b/test/parallel/test-common-countdown.js @@ -0,0 +1,15 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const Countdown = require('../common/countdown'); + +let done = ''; + +const countdown = new Countdown(2, common.mustCall(() => done = true)); +assert.strictEqual(countdown.remaining, 2); +countdown.dec(); +assert.strictEqual(countdown.remaining, 1); +countdown.dec(); +assert.strictEqual(countdown.remaining, 0); +assert.strictEqual(done, true); diff --git a/test/parallel/test-crypto-domain.js b/test/parallel/test-crypto-domain.js index eda01b95b562e4..072cf80f7f9c05 100644 --- a/test/parallel/test-crypto-domain.js +++ b/test/parallel/test-crypto-domain.js @@ -4,8 +4,8 @@ if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); -const domain = require('domain'); const crypto = require('crypto'); +const domain = require('domain'); function test(fn) { const ex = new Error('BAM'); diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index e3f49e61672bb7..7f3ac9e26baefb 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -23,15 +23,6 @@ function sharedOpenSSL() { return process.config.variables.node_shared_openssl; } -function addToEnv(newVar, value) { - const envCopy = {}; - for (const e in process.env) { - envCopy[e] = process.env[e]; - } - envCopy[newVar] = value; - return envCopy; -} - function testHelper(stream, args, expectedOutput, cmd, env) { const fullArgs = args.concat(['-e', `console.log(${cmd})`]); const child = spawnSync(process.execPath, fullArgs, { @@ -69,7 +60,7 @@ testHelper( [], FIPS_DISABLED, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', '')); + Object.assign({}, process.env, { 'OPENSSL_CONF': '' })); // --enable-fips should turn FIPS mode on testHelper( @@ -114,7 +105,7 @@ if (!sharedOpenSSL()) { [], compiledWithFips() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', CNF_FIPS_ON)); + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); // --openssl-config option should override OPENSSL_CONF testHelper( @@ -122,7 +113,7 @@ if (!sharedOpenSSL()) { [`--openssl-config=${CNF_FIPS_ON}`], compiledWithFips() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', CNF_FIPS_OFF)); + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); } testHelper( @@ -130,7 +121,7 @@ testHelper( [`--openssl-config=${CNF_FIPS_OFF}`], FIPS_DISABLED, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', CNF_FIPS_ON)); + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); // --enable-fips should take precedence over OpenSSL config file testHelper( @@ -146,7 +137,7 @@ testHelper( ['--enable-fips'], compiledWithFips() ? FIPS_ENABLED : OPTION_ERROR_STRING, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', CNF_FIPS_OFF)); + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); // --force-fips should take precedence over OpenSSL config file testHelper( @@ -162,7 +153,7 @@ testHelper( ['--force-fips'], compiledWithFips() ? FIPS_ENABLED : OPTION_ERROR_STRING, 'require("crypto").fips', - addToEnv('OPENSSL_CONF', CNF_FIPS_OFF)); + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); // setFipsCrypto should be able to turn FIPS mode on testHelper( diff --git a/test/parallel/test-crypto-hash.js b/test/parallel/test-crypto-hash.js index 1d36753738e95f..1ac00216fd67b3 100644 --- a/test/parallel/test-crypto-hash.js +++ b/test/parallel/test-crypto-hash.js @@ -80,11 +80,11 @@ const fileStream = fs.createReadStream(fn); fileStream.on('data', function(data) { sha1Hash.update(data); }); -fileStream.on('close', function() { +fileStream.on('close', common.mustCall(function() { assert.strictEqual(sha1Hash.digest('hex'), '22723e553129a336ad96e10f6aecdf0f45e4149e', 'Test SHA1 of sample.png'); -}); +})); // Issue #2227: unknown digest method should throw an error. assert.throws(function() { diff --git a/test/parallel/test-domain-exit-dispose.js b/test/parallel/test-domain-exit-dispose.js index a9c69ac3396712..686cdb890defb2 100644 --- a/test/parallel/test-domain-exit-dispose.js +++ b/test/parallel/test-domain-exit-dispose.js @@ -1,5 +1,4 @@ 'use strict'; -require('../common'); const common = require('../common'); const assert = require('assert'); const domain = require('domain'); diff --git a/test/parallel/test-fs-chmod.js b/test/parallel/test-fs-chmod.js index cbe9ef54bac6b3..7946cd751d9202 100644 --- a/test/parallel/test-fs-chmod.js +++ b/test/parallel/test-fs-chmod.js @@ -50,14 +50,17 @@ if (common.isWindows) { mode_sync = 0o644; } -const file1 = path.join(common.fixturesDir, 'a.js'); -const file2 = path.join(common.fixturesDir, 'a1.js'); +common.refreshTmpDir(); + +const file1 = path.join(common.tmpDir, 'a.js'); +const file2 = path.join(common.tmpDir, 'a1.js'); + +// Create file1. +fs.closeSync(fs.openSync(file1, 'w')); fs.chmod(file1, mode_async.toString(8), common.mustCall((err) => { assert.ifError(err); - console.log(fs.statSync(file1).mode); - if (common.isWindows) { assert.ok((fs.statSync(file1).mode & 0o777) & mode_async); } else { @@ -72,14 +75,12 @@ fs.chmod(file1, mode_async.toString(8), common.mustCall((err) => { } })); -fs.open(file2, 'a', common.mustCall((err, fd) => { +fs.open(file2, 'w', common.mustCall((err, fd) => { assert.ifError(err); fs.fchmod(fd, mode_async.toString(8), common.mustCall((err) => { assert.ifError(err); - console.log(fs.fstatSync(fd).mode); - if (common.isWindows) { assert.ok((fs.fstatSync(fd).mode & 0o777) & mode_async); } else { @@ -101,13 +102,11 @@ fs.open(file2, 'a', common.mustCall((err, fd) => { if (fs.lchmod) { const link = path.join(common.tmpDir, 'symbolic-link'); - common.refreshTmpDir(); fs.symlinkSync(file2, link); fs.lchmod(link, mode_async, common.mustCall((err) => { assert.ifError(err); - console.log(fs.lstatSync(link).mode); assert.strictEqual(mode_async, fs.lstatSync(link).mode & 0o777); fs.lchmodSync(link, mode_sync); diff --git a/test/parallel/test-fs-readfile-error.js b/test/parallel/test-fs-readfile-error.js index b3997f7a7d619a..53b9cf7d588cfe 100644 --- a/test/parallel/test-fs-readfile-error.js +++ b/test/parallel/test-fs-readfile-error.js @@ -12,7 +12,7 @@ const path = require('path'); function test(env, cb) { const filename = path.join(common.fixturesDir, 'test-fs-readfile-error.js'); const execPath = `"${process.execPath}" "${filename}"`; - const options = { env: Object.assign(process.env, env) }; + const options = { env: Object.assign({}, process.env, env) }; exec(execPath, options, common.mustCall((err, stdout, stderr) => { assert(err); assert.strictEqual(stdout, ''); diff --git a/test/parallel/test-fs-readfile-unlink.js b/test/parallel/test-fs-readfile-unlink.js index 5b1cbd14f9c4a4..203ea681e5a079 100644 --- a/test/parallel/test-fs-readfile-unlink.js +++ b/test/parallel/test-fs-readfile-unlink.js @@ -3,16 +3,11 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); const path = require('path'); -const dirName = path.resolve(common.fixturesDir, 'test-readfile-unlink'); -const fileName = path.resolve(dirName, 'test.bin'); +const fileName = path.resolve(common.tmpDir, 'test.bin'); + const buf = Buffer.alloc(512 * 1024, 42); -try { - fs.mkdirSync(dirName); -} catch (e) { - // Ignore if the directory already exists. - if (e.code !== 'EEXIST') throw e; -} +common.refreshTmpDir(); fs.writeFileSync(fileName, buf); @@ -21,6 +16,7 @@ fs.readFile(fileName, function(err, data) { assert.strictEqual(data.length, buf.length); assert.strictEqual(buf[0], 42); + // Unlink should not throw. This is part of the test. It used to throw on + // Windows due to a bug. fs.unlinkSync(fileName); - fs.rmdirSync(dirName); }); diff --git a/test/parallel/test-http-abort-client.js b/test/parallel/test-http-abort-client.js index c44681cf9a9884..b50b72f4bb91af 100644 --- a/test/parallel/test-http-abort-client.js +++ b/test/parallel/test-http-abort-client.js @@ -2,42 +2,27 @@ const common = require('../common'); const http = require('http'); -const server = http.Server(function(req, res) { - console.log('Server accepted request.'); +let serverRes; +const server = http.Server((req, res) => { + serverRes = res; res.writeHead(200); res.write('Part of my res.'); res.destroy(); }); -server.listen(0, common.mustCall(function() { +server.listen(0, common.mustCall(() => { http.get({ - port: this.address().port, + port: server.address().port, headers: { connection: 'keep-alive' } - }, common.mustCall(function(res) { + }, common.mustCall((res) => { server.close(); + serverRes.destroy(); - console.log(`Got res: ${res.statusCode}`); - console.dir(res.headers); - - res.on('data', function(chunk) { - console.log(`Read ${chunk.length} bytes`); - console.log(' chunk=%j', chunk.toString()); - }); - - res.on('end', function() { - console.log('Response ended.'); - }); - - res.on('aborted', function() { - console.log('Response aborted.'); - }); - - res.socket.on('close', function() { - console.log('socket closed, but not res'); - }); - - // it would be nice if this worked: + res.resume(); + res.on('end', common.mustCall()); + res.on('aborted', common.mustCall()); res.on('close', common.mustCall()); + res.socket.on('close', common.mustCall()); })); })); diff --git a/test/parallel/test-http-abort-queued.js b/test/parallel/test-http-abort-queued.js index 5f7259f7db968c..28fb2a78311201 100644 --- a/test/parallel/test-http-abort-queued.js +++ b/test/parallel/test-http-abort-queued.js @@ -1,11 +1,11 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); let complete; -const server = http.createServer(function(req, res) { +const server = http.createServer((req, res) => { // We should not see the queued /thatotherone request within the server // as it should be aborted before it is sent. assert.strictEqual(req.url, '/'); @@ -19,10 +19,8 @@ const server = http.createServer(function(req, res) { }); -server.listen(0, function() { - console.log('listen', server.address().port); - - const agent = new http.Agent({maxSockets: 1}); +server.listen(0, () => { + const agent = new http.Agent({ maxSockets: 1 }); assert.strictEqual(Object.keys(agent.sockets).length, 0); const options = { @@ -34,7 +32,7 @@ server.listen(0, function() { }; const req1 = http.request(options); - req1.on('response', function(res1) { + req1.on('response', (res1) => { assert.strictEqual(Object.keys(agent.sockets).length, 1); assert.strictEqual(Object.keys(agent.requests).length, 0); @@ -48,7 +46,9 @@ server.listen(0, function() { assert.strictEqual(Object.keys(agent.sockets).length, 1); assert.strictEqual(Object.keys(agent.requests).length, 1); - req2.on('error', function(err) { + // TODO(jasnell): This event does not appear to currently be triggered. + // is this handler actually required? + req2.on('error', (err) => { // This is expected in response to our explicit abort call assert.strictEqual(err.code, 'ECONNRESET'); }); @@ -59,25 +59,16 @@ server.listen(0, function() { assert.strictEqual(Object.keys(agent.sockets).length, 1); assert.strictEqual(Object.keys(agent.requests).length, 1); - console.log(`Got res: ${res1.statusCode}`); - console.dir(res1.headers); - - res1.on('data', function(chunk) { - console.log(`Read ${chunk.length} bytes`); - console.log(' chunk=%j', chunk.toString()); - complete(); - }); + res1.on('data', (chunk) => complete()); - res1.on('end', function() { - console.log('Response ended.'); - - setTimeout(function() { + res1.on('end', common.mustCall(() => { + setTimeout(common.mustCall(() => { assert.strictEqual(Object.keys(agent.sockets).length, 0); assert.strictEqual(Object.keys(agent.requests).length, 0); server.close(); - }, 100); - }); + }), 100); + })); }); req1.end(); diff --git a/test/parallel/test-http-after-connect.js b/test/parallel/test-http-after-connect.js index 8be887c58082da..dfabbc092b6149 100644 --- a/test/parallel/test-http-after-connect.js +++ b/test/parallel/test-http-after-connect.js @@ -2,61 +2,51 @@ const common = require('../common'); const assert = require('assert'); const http = require('http'); +const Countdown = require('../common/countdown'); -let clientResponses = 0; - -const server = http.createServer(common.mustCall(function(req, res) { - console.error('Server got GET request'); +const server = http.createServer(common.mustCall((req, res) => { req.resume(); res.writeHead(200); res.write(''); - setTimeout(function() { - res.end(req.url); - }, 50); + setTimeout(() => res.end(req.url), 50); }, 2)); -server.on('connect', common.mustCall(function(req, socket) { - console.error('Server got CONNECT request'); + +const countdown = new Countdown(2, common.mustCall(() => server.close())); + +server.on('connect', common.mustCall((req, socket) => { socket.write('HTTP/1.1 200 Connection established\r\n\r\n'); socket.resume(); - socket.on('end', function() { - socket.end(); - }); + socket.on('end', () => socket.end()); })); -server.listen(0, function() { + +server.listen(0, common.mustCall(() => { const req = http.request({ - port: this.address().port, + port: server.address().port, method: 'CONNECT', path: 'google.com:80' }); - req.on('connect', common.mustCall(function(res, socket) { - console.error('Client got CONNECT response'); + req.on('connect', common.mustCall((res, socket) => { socket.end(); - socket.on('end', function() { + socket.on('end', common.mustCall(() => { doRequest(0); doRequest(1); - }); + })); socket.resume(); })); req.end(); -}); +})); function doRequest(i) { http.get({ port: server.address().port, path: `/request${i}` - }, common.mustCall(function(res) { - console.error('Client got GET response'); + }, common.mustCall((res) => { let data = ''; res.setEncoding('utf8'); - res.on('data', function(chunk) { - data += chunk; - }); - res.on('end', function() { + res.on('data', (chunk) => data += chunk); + res.on('end', common.mustCall(() => { assert.strictEqual(data, `/request${i}`); - ++clientResponses; - if (clientResponses === 2) { - server.close(); - } - }); + countdown.dec(); + })); })); } diff --git a/test/parallel/test-http-agent-destroyed-socket.js b/test/parallel/test-http-agent-destroyed-socket.js index 4bb14c2d7e01ce..6dcebd42988589 100644 --- a/test/parallel/test-http-agent-destroyed-socket.js +++ b/test/parallel/test-http-agent-destroyed-socket.js @@ -1,36 +1,31 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); +const Countdown = require('../common/countdown'); -const server = http.createServer(function(req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); +const server = http.createServer(common.mustCall((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello World\n'); -}).listen(0, function() { - const agent = new http.Agent({maxSockets: 1}); +}, 2)).listen(0, common.mustCall(() => { + const agent = new http.Agent({ maxSockets: 1 }); - agent.on('free', function(socket, host, port) { - console.log('freeing socket. destroyed? ', socket.destroyed); - }); + agent.on('free', common.mustCall(3)); const requestOptions = { agent: agent, host: 'localhost', - port: this.address().port, + port: server.address().port, path: '/' }; - const request1 = http.get(requestOptions, function(response) { + const request1 = http.get(requestOptions, common.mustCall((response) => { // assert request2 is queued in the agent const key = agent.getName(requestOptions); assert.strictEqual(agent.requests[key].length, 1); - console.log('got response1'); - request1.socket.on('close', function() { - console.log('request1 socket closed'); - }); - response.pipe(process.stdout); - response.on('end', function() { - console.log('response1 done'); + request1.socket.on('close', common.mustCall()); + response.resume(); + response.on('end', common.mustCall(() => { ///////////////////////////////// // // THE IMPORTANT PART @@ -44,43 +39,29 @@ const server = http.createServer(function(req, res) { // is triggered. request1.socket.destroy(); - response.once('close', function() { + // TODO(jasnell): This close event does not appear to be triggered. + // is it necessary? + response.once('close', () => { // assert request2 was removed from the queue assert(!agent.requests[key]); - console.log("waiting for request2.onSocket's nextTick"); - process.nextTick(function() { + process.nextTick(() => { // assert that the same socket was not assigned to request2, // since it was destroyed. assert.notStrictEqual(request1.socket, request2.socket); assert(!request2.socket.destroyed, 'the socket is destroyed'); }); }); - }); - }); + })); + })); - let request2 = http.get(requestOptions, function(response) { + const request2 = http.get(requestOptions, common.mustCall((response) => { assert(!request2.socket.destroyed); assert(request1.socket.destroyed); // assert not reusing the same socket, since it was destroyed. assert.notStrictEqual(request1.socket, request2.socket); - console.log('got response2'); - let gotClose = false; - let gotResponseEnd = false; - request2.socket.on('close', function() { - console.log('request2 socket closed'); - gotClose = true; - done(); - }); - response.pipe(process.stdout); - response.on('end', function() { - console.log('response2 done'); - gotResponseEnd = true; - done(); - }); - - function done() { - if (gotResponseEnd && gotClose) - server.close(); - } - }); -}); + const countdown = new Countdown(2, common.mustCall(() => server.close())); + request2.socket.on('close', common.mustCall(() => countdown.dec())); + response.on('end', common.mustCall(() => countdown.dec())); + response.resume(); + })); +})); diff --git a/test/parallel/test-http-agent-error-on-idle.js b/test/parallel/test-http-agent-error-on-idle.js index 2f270c0d30ca0b..fce5e8f0324f5c 100644 --- a/test/parallel/test-http-agent-error-on-idle.js +++ b/test/parallel/test-http-agent-error-on-idle.js @@ -1,32 +1,31 @@ 'use strict'; -require('../common'); + +const common = require('../common'); const assert = require('assert'); const http = require('http'); const Agent = http.Agent; -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end('hello world'); -}); +}, 2)); -server.listen(0, function() { - const agent = new Agent({ - keepAlive: true, - }); +server.listen(0, () => { + const agent = new Agent({ keepAlive: true }); const requestParams = { host: 'localhost', - port: this.address().port, + port: server.address().port, agent: agent, path: '/' }; const socketKey = agent.getName(requestParams); - get(function(res) { + http.get(requestParams, common.mustCall((res) => { assert.strictEqual(res.statusCode, 200); res.resume(); - res.on('end', function() { - process.nextTick(function() { + res.on('end', common.mustCall(() => { + process.nextTick(common.mustCall(() => { const freeSockets = agent.freeSockets[socketKey]; assert.strictEqual(freeSockets.length, 1, `expect a free socket on ${socketKey}`); @@ -35,14 +34,10 @@ server.listen(0, function() { const freeSocket = freeSockets[0]; freeSocket.emit('error', new Error('ECONNRESET: test')); - get(done); - }); - }); - }); - - function get(callback) { - return http.get(requestParams, callback); - } + http.get(requestParams, done); + })); + })); + })); function done() { assert.strictEqual(Object.keys(agent.freeSockets).length, 0, @@ -50,6 +45,5 @@ server.listen(0, function() { agent.destroy(); server.close(); - process.exit(0); } }); diff --git a/test/parallel/test-http-agent-false.js b/test/parallel/test-http-agent-false.js index 5c9907bb706d32..6d5b1b38bf0a9b 100644 --- a/test/parallel/test-http-agent-false.js +++ b/test/parallel/test-http-agent-false.js @@ -1,6 +1,5 @@ 'use strict'; -require('../common'); -const assert = require('assert'); +const common = require('../common'); const http = require('http'); // sending `agent: false` when `port: null` is also passed in (i.e. the result @@ -14,20 +13,13 @@ const opts = { agent: false }; -let good = false; -process.on('exit', function() { - assert(good, 'expected either an "error" or "response" event'); -}); - // we just want an "error" (no local HTTP server on port 80) or "response" // to happen (user happens ot have HTTP server running on port 80). // As long as the process doesn't crash from a C++ assertion then we're good. const req = http.request(opts); -req.on('response', function(res) { - good = true; -}); -req.on('error', function(err) { - // an "error" event is ok, don't crash the process - good = true; -}); + +// Will be called by either the response event or error event, not both +const oneResponse = common.mustCall(); +req.on('response', oneResponse); +req.on('error', oneResponse); req.end(); diff --git a/test/parallel/test-http-agent-keepalive.js b/test/parallel/test-http-agent-keepalive.js index 9ea3fd7677aebe..7f9626d4669ef9 100644 --- a/test/parallel/test-http-agent-keepalive.js +++ b/test/parallel/test-http-agent-keepalive.js @@ -13,19 +13,17 @@ const agent = new Agent({ maxFreeSockets: 5 }); -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { if (req.url === '/error') { res.destroy(); return; } else if (req.url === '/remote_close') { // cache the socket, close it after a short delay const socket = res.connection; - setImmediate(function() { - socket.end(); - }); + setImmediate(common.mustCall(() => socket.end())); } res.end('hello world'); -}); +}, 4)); function get(path, callback) { return http.get({ @@ -44,82 +42,75 @@ function checkDataAndSockets(body) { function second() { // request second, use the same socket - get('/second', function(res) { + get('/second', common.mustCall((res) => { assert.strictEqual(res.statusCode, 200); res.on('data', checkDataAndSockets); - res.on('end', function() { + res.on('end', common.mustCall(() => { assert.strictEqual(agent.sockets[name].length, 1); assert.strictEqual(agent.freeSockets[name], undefined); - process.nextTick(function() { + process.nextTick(common.mustCall(() => { assert.strictEqual(agent.sockets[name], undefined); assert.strictEqual(agent.freeSockets[name].length, 1); remoteClose(); - }); - }); - }); + })); + })); + })); } function remoteClose() { // mock remote server close the socket - get('/remote_close', function(res) { + get('/remote_close', common.mustCall((res) => { assert.deepStrictEqual(res.statusCode, 200); res.on('data', checkDataAndSockets); - res.on('end', function() { + res.on('end', common.mustCall(() => { assert.strictEqual(agent.sockets[name].length, 1); assert.strictEqual(agent.freeSockets[name], undefined); - process.nextTick(function() { + process.nextTick(common.mustCall(() => { assert.strictEqual(agent.sockets[name], undefined); assert.strictEqual(agent.freeSockets[name].length, 1); // waitting remote server close the socket - setTimeout(function() { + setTimeout(common.mustCall(() => { assert.strictEqual(agent.sockets[name], undefined); assert.strictEqual(agent.freeSockets[name], undefined, 'freeSockets is not empty'); remoteError(); - }, common.platformTimeout(200)); - }); - }); - }); + }), common.platformTimeout(200)); + })); + })); + })); } function remoteError() { // remove server will destroy ths socket - const req = get('/error', function(res) { - throw new Error('should not call this function'); - }); - req.on('error', function(err) { - assert.ok(err); + const req = get('/error', common.mustNotCall()); + req.on('error', common.mustCall((err) => { + assert(err); assert.strictEqual(err.message, 'socket hang up'); assert.strictEqual(agent.sockets[name].length, 1); assert.strictEqual(agent.freeSockets[name], undefined); // Wait socket 'close' event emit - setTimeout(function() { + setTimeout(common.mustCall(() => { assert.strictEqual(agent.sockets[name], undefined); assert.strictEqual(agent.freeSockets[name], undefined); - done(); - }, common.platformTimeout(1)); - }); -} - -function done() { - console.log('http keepalive agent test success.'); - process.exit(0); + server.close(); + }), common.platformTimeout(1)); + })); } -server.listen(0, function() { +server.listen(0, common.mustCall(() => { name = `localhost:${server.address().port}:`; // request first, and keep alive - get('/first', function(res) { + get('/first', common.mustCall((res) => { assert.strictEqual(res.statusCode, 200); res.on('data', checkDataAndSockets); - res.on('end', function() { + res.on('end', common.mustCall(() => { assert.strictEqual(agent.sockets[name].length, 1); assert.strictEqual(agent.freeSockets[name], undefined); - process.nextTick(function() { + process.nextTick(common.mustCall(() => { assert.strictEqual(agent.sockets[name], undefined); assert.strictEqual(agent.freeSockets[name].length, 1); second(); - }); - }); - }); -}); + })); + })); + })); +})); diff --git a/test/parallel/test-http-agent-maxsockets-regress-4050.js b/test/parallel/test-http-agent-maxsockets-regress-4050.js index fd3a8c33f3e39a..57a90e4b05c79f 100644 --- a/test/parallel/test-http-agent-maxsockets-regress-4050.js +++ b/test/parallel/test-http-agent-maxsockets-regress-4050.js @@ -1,7 +1,8 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); +const Countdown = require('../common/countdown'); const MAX_SOCKETS = 2; @@ -12,9 +13,11 @@ const agent = new http.Agent({ maxFreeSockets: 2 }); -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end('hello world'); -}); +}, 6)); + +const countdown = new Countdown(6, common.mustCall(() => server.close())); function get(path, callback) { return http.get({ @@ -25,19 +28,14 @@ function get(path, callback) { }, callback); } -server.listen(0, function() { - let finished = 0; - const num_requests = 6; - for (let i = 0; i < num_requests; i++) { - const request = get('/1', function() { - }); - request.on('response', function() { +server.listen(0, common.mustCall(() => { + for (let i = 0; i < 6; i++) { + const request = get('/1', common.mustCall()); + request.on('response', common.mustCall(() => { request.abort(); const sockets = agent.sockets[Object.keys(agent.sockets)[0]]; assert(sockets.length <= MAX_SOCKETS); - if (++finished === num_requests) { - server.close(); - } - }); + countdown.dec(); + })); } -}); +})); diff --git a/test/parallel/test-http-agent-maxsockets.js b/test/parallel/test-http-agent-maxsockets.js index 513906160048d9..66fffba250513f 100644 --- a/test/parallel/test-http-agent-maxsockets.js +++ b/test/parallel/test-http-agent-maxsockets.js @@ -1,7 +1,8 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); +const Countdown = require('../common/countdown'); const agent = new http.Agent({ keepAlive: true, @@ -10,9 +11,9 @@ const agent = new http.Agent({ maxFreeSockets: 2 }); -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end('hello world'); -}); +}, 2)); function get(path, callback) { return http.get({ @@ -23,32 +24,25 @@ function get(path, callback) { }, callback); } -let count = 0; -function done() { - if (++count !== 2) { - return; - } +const countdown = new Countdown(2, common.mustCall(() => { const freepool = agent.freeSockets[Object.keys(agent.freeSockets)[0]]; assert.strictEqual(freepool.length, 2, `expect keep 2 free sockets, but got ${freepool.length}`); agent.destroy(); server.close(); +})); + +function dec() { + process.nextTick(() => countdown.dec()); } -server.listen(0, function() { - get('/1', function(res) { - assert.strictEqual(res.statusCode, 200); - res.resume(); - res.on('end', function() { - process.nextTick(done); - }); - }); +function onGet(res) { + assert.strictEqual(res.statusCode, 200); + res.resume(); + res.on('end', common.mustCall(dec)); +} - get('/2', function(res) { - assert.strictEqual(res.statusCode, 200); - res.resume(); - res.on('end', function() { - process.nextTick(done); - }); - }); -}); +server.listen(0, common.mustCall(() => { + get('/1', common.mustCall(onGet)); + get('/2', common.mustCall(onGet)); +})); diff --git a/test/parallel/test-http-agent-no-protocol.js b/test/parallel/test-http-agent-no-protocol.js index a11489b6c5bc2b..dd95b6c33769c0 100644 --- a/test/parallel/test-http-agent-no-protocol.js +++ b/test/parallel/test-http-agent-no-protocol.js @@ -3,17 +3,17 @@ const common = require('../common'); const http = require('http'); const url = require('url'); -const server = http.createServer(common.mustCall(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end(); -})).listen(0, '127.0.0.1', common.mustCall(function() { - const opts = url.parse(`http://127.0.0.1:${this.address().port}/`); +})).listen(0, '127.0.0.1', common.mustCall(() => { + const opts = url.parse(`http://127.0.0.1:${server.address().port}/`); // remove the `protocol` field… the `http` module should fall back // to "http:", as defined by the global, default `http.Agent` instance. opts.agent = new http.Agent(); opts.agent.protocol = null; - http.get(opts, common.mustCall(function(res) { + http.get(opts, common.mustCall((res) => { res.resume(); server.close(); })); diff --git a/test/parallel/test-http-agent-null.js b/test/parallel/test-http-agent-null.js index 9071b88b98997a..475cddc4902eaf 100644 --- a/test/parallel/test-http-agent-null.js +++ b/test/parallel/test-http-agent-null.js @@ -2,14 +2,14 @@ const common = require('../common'); const http = require('http'); -const server = http.createServer(common.mustCall(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end(); -})).listen(0, common.mustCall(function() { +})).listen(0, common.mustCall(() => { const options = { agent: null, - port: this.address().port + port: server.address().port }; - http.get(options, common.mustCall(function(res) { + http.get(options, common.mustCall((res) => { res.resume(); server.close(); })); diff --git a/test/parallel/test-http-automatic-headers.js b/test/parallel/test-http-automatic-headers.js index 37a5c43901c33d..5a6a8e524c76ee 100644 --- a/test/parallel/test-http-automatic-headers.js +++ b/test/parallel/test-http-automatic-headers.js @@ -1,23 +1,23 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.setHeader('X-Date', 'foo'); res.setHeader('X-Connection', 'bar'); res.setHeader('X-Content-Length', 'baz'); res.end(); -}); +})); server.listen(0); -server.on('listening', function() { - const agent = new http.Agent({ port: this.address().port, maxSockets: 1 }); +server.on('listening', common.mustCall(() => { + const agent = new http.Agent({ port: server.address().port, maxSockets: 1 }); http.get({ - port: this.address().port, + port: server.address().port, path: '/hello', agent: agent - }, function(res) { + }, common.mustCall((res) => { assert.strictEqual(res.statusCode, 200); assert.strictEqual(res.headers['x-date'], 'foo'); assert.strictEqual(res.headers['x-connection'], 'bar'); @@ -27,5 +27,5 @@ server.on('listening', function() { assert.strictEqual(res.headers['content-length'], '0'); server.close(); agent.destroy(); - }); -}); + })); +})); diff --git a/test/parallel/test-http-blank-header.js b/test/parallel/test-http-blank-header.js index edd8923fa8e2f7..cc52e35e05a38d 100644 --- a/test/parallel/test-http-blank-header.js +++ b/test/parallel/test-http-blank-header.js @@ -4,34 +4,29 @@ const assert = require('assert'); const http = require('http'); const net = require('net'); -const server = http.createServer(common.mustCall(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { assert.strictEqual('GET', req.method); assert.strictEqual('/blah', req.url); assert.deepStrictEqual({ - host: 'mapdevel.trolologames.ru:443', - origin: 'http://mapdevel.trolologames.ru', + host: 'example.org:443', + origin: 'http://example.org', cookie: '' }, req.headers); })); -server.listen(0, function() { - const c = net.createConnection(this.address().port); +server.listen(0, common.mustCall(() => { + const c = net.createConnection(server.address().port); - c.on('connect', function() { + c.on('connect', common.mustCall(() => { c.write('GET /blah HTTP/1.1\r\n' + - 'Host: mapdevel.trolologames.ru:443\r\n' + + 'Host: example.org:443\r\n' + 'Cookie:\r\n' + - 'Origin: http://mapdevel.trolologames.ru\r\n' + + 'Origin: http://example.org\r\n' + '\r\n\r\nhello world' ); - }); + })); - c.on('end', function() { - c.end(); - }); - - c.on('close', function() { - server.close(); - }); -}); + c.on('end', common.mustCall(() => c.end())); + c.on('close', common.mustCall(() => server.close())); +})); diff --git a/test/parallel/test-http-buffer-sanity.js b/test/parallel/test-http-buffer-sanity.js index 717ca23ce8bc16..0fadd6c0c07819 100644 --- a/test/parallel/test-http-buffer-sanity.js +++ b/test/parallel/test-http-buffer-sanity.js @@ -11,16 +11,12 @@ for (let i = 0; i < buffer.length; i++) { buffer[i] = i % 256; } - -const web = http.Server(function(req, res) { - web.close(); - - console.log(req.headers); +const server = http.Server(function(req, res) { + server.close(); let i = 0; - req.on('data', function(d) { - process.stdout.write(','); + req.on('data', (d) => { measuredSize += d.length; for (let j = 0; j < d.length; j++) { assert.strictEqual(buffer[i], d[j]); @@ -28,39 +24,27 @@ const web = http.Server(function(req, res) { } }); - - req.on('end', function() { + req.on('end', common.mustCall(() => { + assert.strictEqual(bufferSize, measuredSize); res.writeHead(200); res.write('thanks'); res.end(); - console.log('response with \'thanks\''); - }); - - req.connection.on('error', function(e) { - console.log(`http server-side error: ${e.message}`); - process.exit(1); - }); + })); }); -web.listen(0, common.mustCall(function() { - console.log('Making request'); - +server.listen(0, common.mustCall(() => { const req = http.request({ - port: this.address().port, - method: 'GET', + port: server.address().port, + method: 'POST', path: '/', headers: { 'content-length': buffer.length } - }, common.mustCall(function(res) { - console.log('Got response'); + }, common.mustCall((res) => { res.setEncoding('utf8'); - res.on('data', common.mustCall(function(string) { - assert.strictEqual('thanks', string); + let data = ''; + res.on('data', (chunk) => data += chunk); + res.on('end', common.mustCall(() => { + assert.strictEqual('thanks', data); })); })); req.end(buffer); })); - - -process.on('exit', function() { - assert.strictEqual(bufferSize, measuredSize); -}); diff --git a/test/parallel/test-http-chunked.js b/test/parallel/test-http-chunked.js index b70a704bb7fce4..4fa4f2004a2967 100644 --- a/test/parallel/test-http-chunked.js +++ b/test/parallel/test-http-chunked.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); @@ -13,31 +13,23 @@ const UTF8_STRING = '南越国是前203年至前111年存在于岭南地区的 '采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,' + '有效的改善了岭南地区落后的政治、经济现状。'; -const server = http.createServer(function(req, res) { - res.writeHead(200, {'Content-Type': 'text/plain; charset=utf8'}); +const server = http.createServer(common.mustCall((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf8' }); res.end(UTF8_STRING, 'utf8'); -}); -server.listen(0, function() { +})); +server.listen(0, common.mustCall(() => { let data = ''; - const get = http.get({ + http.get({ path: '/', host: 'localhost', - port: this.address().port - }, function(x) { + port: server.address().port + }, common.mustCall((x) => { x.setEncoding('utf8'); - x.on('data', function(c) { data += c; }); - x.on('error', function(e) { - throw e; - }); - x.on('end', function() { + x.on('data', (c) => data += c); + x.on('end', common.mustCall(() => { assert.strictEqual('string', typeof data); - console.log('here is the response:'); assert.strictEqual(UTF8_STRING, data); - console.log(data); server.close(); - }); - }); - get.on('error', function(e) { throw e; }); - get.end(); - -}); + })); + })).end(); +})); diff --git a/test/parallel/test-http-client-abort.js b/test/parallel/test-http-client-abort.js index 68b76d1548de27..a4aa41c328f849 100644 --- a/test/parallel/test-http-client-abort.js +++ b/test/parallel/test-http-client-abort.js @@ -1,55 +1,33 @@ 'use strict'; -require('../common'); -const assert = require('assert'); +const common = require('../common'); const http = require('http'); +const Countdown = require('../common/countdown'); -let clientAborts = 0; +const N = 8; + +const countdown = new Countdown(N, common.mustCall(() => server.close())); -const server = http.Server(function(req, res) { - console.log('Got connection'); +const server = http.Server(common.mustCall((req, res) => { res.writeHead(200); res.write('Working on it...'); + req.on('aborted', common.mustCall(() => countdown.dec())); +}, N)); - // I would expect an error event from req or res that the client aborted - // before completing the HTTP request / response cycle, or maybe a new - // event like "aborted" or something. - req.on('aborted', function() { - clientAborts++; - console.log(`Got abort ${clientAborts}`); - if (clientAborts === N) { - console.log('All aborts detected, you win.'); - server.close(); - } - }); -}); +server.listen(0, common.mustCall(() => { -let responses = 0; -const N = 8; -const requests = []; + const requests = []; + const reqCountdown = new Countdown(N, common.mustCall(() => { + requests.forEach((req) => req.abort()); + })); -server.listen(0, function() { - console.log('Server listening.'); + const options = { port: server.address().port }; for (let i = 0; i < N; i++) { - console.log(`Making client ${i}`); - const options = { port: this.address().port, path: `/?id=${i}` }; - const req = http.get(options, function(res) { - console.log(`Client response code ${res.statusCode}`); - - res.resume(); - if (++responses === N) { - console.log('All clients connected, destroying.'); - requests.forEach(function(outReq) { - console.log('abort'); - outReq.abort(); - }); - } - }); - - requests.push(req); + options.path = `/?id=${i}`; + requests.push( + http.get(options, common.mustCall((res) => { + res.resume(); + reqCountdown.dec(); + }))); } -}); - -process.on('exit', function() { - assert.strictEqual(N, clientAborts); -}); +})); diff --git a/test/parallel/test-http-client-abort2.js b/test/parallel/test-http-client-abort2.js index 7c7be9b530e2d2..174174d849b90a 100644 --- a/test/parallel/test-http-client-abort2.js +++ b/test/parallel/test-http-client-abort2.js @@ -1,16 +1,17 @@ 'use strict'; -require('../common'); +const common = require('../common'); const http = require('http'); -const server = http.createServer(function(req, res) { +const server = http.createServer(common.mustCall((req, res) => { res.end('Hello'); -}); +})); -server.listen(0, function() { - const req = http.get({port: this.address().port}, function(res) { - res.on('data', function(data) { +server.listen(0, common.mustCall(() => { + const options = { port: server.address().port }; + const req = http.get(options, common.mustCall((res) => { + res.on('data', (data) => { req.abort(); server.close(); }); - }); -}); + })); +})); diff --git a/test/parallel/test-http-client-agent.js b/test/parallel/test-http-client-agent.js index 6d30a2236ef485..a24d886c041984 100644 --- a/test/parallel/test-http-client-agent.js +++ b/test/parallel/test-http-client-agent.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); @@ -7,23 +7,22 @@ let name; const max = 3; let count = 0; -const server = http.Server(function(req, res) { +const server = http.Server(common.mustCall((req, res) => { if (req.url === '/0') { - setTimeout(function() { + setTimeout(common.mustCall(() => { res.writeHead(200); res.end('Hello, World!'); - }, 100); + }), 100); } else { res.writeHead(200); res.end('Hello, World!'); } -}); -server.listen(0, function() { - name = http.globalAgent.getName({ port: this.address().port }); - for (let i = 0; i < max; ++i) { +}, max)); +server.listen(0, common.mustCall(() => { + name = http.globalAgent.getName({ port: server.address().port }); + for (let i = 0; i < max; ++i) request(i); - } -}); +})); function request(i) { const req = http.get({ @@ -31,7 +30,7 @@ function request(i) { path: `/${i}` }, function(res) { const socket = req.socket; - socket.on('close', function() { + socket.on('close', common.mustCall(() => { ++count; if (count < max) { assert.strictEqual(http.globalAgent.sockets[name].includes(socket), @@ -41,11 +40,7 @@ function request(i) { assert(!http.globalAgent.requests.hasOwnProperty(name)); server.close(); } - }); + })); res.resume(); }); } - -process.on('exit', function() { - assert.strictEqual(count, max); -}); diff --git a/test/parallel/test-http-client-default-headers-exist.js b/test/parallel/test-http-client-default-headers-exist.js index 410f83449fc1b6..4efe1c95802fb6 100644 --- a/test/parallel/test-http-client-default-headers-exist.js +++ b/test/parallel/test-http-client-default-headers-exist.js @@ -1,7 +1,8 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); +const Countdown = require('../common/countdown'); const expectedHeaders = { 'DELETE': ['host', 'connection'], @@ -14,17 +15,18 @@ const expectedHeaders = { const expectedMethods = Object.keys(expectedHeaders); -let requestCount = 0; +const countdown = + new Countdown(expectedMethods.length, + common.mustCall(() => server.close())); -const server = http.createServer(function(req, res) { - requestCount++; +const server = http.createServer(common.mustCall((req, res) => { res.end(); assert(expectedHeaders.hasOwnProperty(req.method), `${req.method} was an unexpected method`); const requestHeaders = Object.keys(req.headers); - requestHeaders.forEach(function(header) { + requestHeaders.forEach((header) => { assert.strictEqual( expectedHeaders[req.method].includes(header.toLowerCase()), true, @@ -38,15 +40,14 @@ const server = http.createServer(function(req, res) { `some headers were missing for method: ${req.method}` ); - if (expectedMethods.length === requestCount) - server.close(); -}); + countdown.dec(); +}, expectedMethods.length)); -server.listen(0, function() { - expectedMethods.forEach(function(method) { +server.listen(0, common.mustCall(() => { + expectedMethods.forEach((method) => { http.request({ method: method, port: server.address().port }).end(); }); -}); +})); diff --git a/test/parallel/test-http-client-encoding.js b/test/parallel/test-http-client-encoding.js index d2aa8fdcbbac46..57d02802c8438c 100644 --- a/test/parallel/test-http-client-encoding.js +++ b/test/parallel/test-http-client-encoding.js @@ -1,18 +1,18 @@ 'use strict'; -require('../common'); - +const common = require('../common'); +const assert = require('assert'); const http = require('http'); -http.createServer(function(req, res) { - res.end('ok\n'); - this.close(); -}).listen(0, test); - -function test() { +const server = http.createServer((req, res) => { + res.end('ok'); + server.close(); +}).listen(0, common.mustCall(() => { http.request({ - port: this.address().port, + port: server.address().port, encoding: 'utf8' - }, function(res) { - res.pipe(process.stdout); - }).end(); -} + }, common.mustCall((res) => { + let data = ''; + res.on('data', (chunk) => data += chunk); + res.on('end', common.mustCall(() => assert.strictEqual(data, 'ok'))); + })).end(); +})); diff --git a/test/parallel/test-http-client-parse-error.js b/test/parallel/test-http-client-parse-error.js index 77cd2cb193a680..fc022b337770e0 100644 --- a/test/parallel/test-http-client-parse-error.js +++ b/test/parallel/test-http-client-parse-error.js @@ -1,39 +1,30 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); - const http = require('http'); const net = require('net'); +const Countdown = require('../common/countdown'); + +const countdown = new Countdown(2, common.mustCall(() => server.close())); -let connects = 0; -let parseErrors = 0; +const payloads = [ + 'HTTP/1.1 302 Object Moved\r\nContent-Length: 0\r\n\r\nhi world', + 'bad http = should trigger parse error' +]; // Create a TCP server -net.createServer(function(c) { - console.log('connection'); - if (++connects === 1) { - c.end('HTTP/1.1 302 Object Moved\r\nContent-Length: 0\r\n\r\nhi world'); - } else { - c.end('bad http - should trigger parse error\r\n'); - this.close(); - } -}).listen(0, '127.0.0.1', function() { +const server = + net.createServer(common.mustCall((c) => c.end(payloads.shift()), 2)); + +server.listen(0, common.mustCall(() => { for (let i = 0; i < 2; i++) { - http.request({ - host: '127.0.0.1', - port: this.address().port, - method: 'GET', + http.get({ + port: server.address().port, path: '/' - }).on('error', function(e) { - console.log('got error from client'); + }).on('error', common.mustCall((e) => { assert.ok(e.message.includes('Parse Error')); assert.strictEqual(e.code, 'HPE_INVALID_CONSTANT'); - parseErrors++; - }).end(); + countdown.dec(); + })); } -}); - -process.on('exit', function() { - assert.strictEqual(connects, 2); - assert.strictEqual(parseErrors, 2); -}); +})); diff --git a/test/parallel/test-http-invalidheaderfield2.js b/test/parallel/test-http-invalidheaderfield2.js index 2267c8565cb634..40415d9c368891 100644 --- a/test/parallel/test-http-invalidheaderfield2.js +++ b/test/parallel/test-http-invalidheaderfield2.js @@ -2,8 +2,7 @@ require('../common'); const assert = require('assert'); const inspect = require('util').inspect; -const checkIsHttpToken = require('_http_common')._checkIsHttpToken; -const checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; +const { _checkIsHttpToken, _checkInvalidHeaderChar } = require('_http_common'); // Good header field names [ @@ -29,8 +28,8 @@ const checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; '3.14159265359' ].forEach(function(str) { assert.strictEqual( - checkIsHttpToken(str), true, - `checkIsHttpToken(${inspect(str)}) unexpectedly failed`); + _checkIsHttpToken(str), true, + `_checkIsHttpToken(${inspect(str)}) unexpectedly failed`); }); // Bad header field names [ @@ -55,8 +54,8 @@ const checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; 'This,That' ].forEach(function(str) { assert.strictEqual( - checkIsHttpToken(str), false, - `checkIsHttpToken(${inspect(str)}) unexpectedly succeeded`); + _checkIsHttpToken(str), false, + `_checkIsHttpToken(${inspect(str)}) unexpectedly succeeded`); }); @@ -68,8 +67,8 @@ const checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; '!@#$%^&*()-_=+\\;\':"[]{}<>,./?|~`' ].forEach(function(str) { assert.strictEqual( - checkInvalidHeaderChar(str), false, - `checkInvalidHeaderChar(${inspect(str)}) unexpectedly failed`); + _checkInvalidHeaderChar(str), false, + `_checkInvalidHeaderChar(${inspect(str)}) unexpectedly failed`); }); // Bad header field values @@ -84,6 +83,6 @@ const checkInvalidHeaderChar = require('_http_common')._checkInvalidHeaderChar; 'Ding!\x07' ].forEach(function(str) { assert.strictEqual( - checkInvalidHeaderChar(str), true, - `checkInvalidHeaderChar(${inspect(str)}) unexpectedly succeeded`); + _checkInvalidHeaderChar(str), true, + `_checkInvalidHeaderChar(${inspect(str)}) unexpectedly succeeded`); }); diff --git a/test/parallel/test-http-methods.js b/test/parallel/test-http-methods.js index fb49add6a2ad24..a0105d908265df 100644 --- a/test/parallel/test-http-methods.js +++ b/test/parallel/test-http-methods.js @@ -2,11 +2,44 @@ require('../common'); const assert = require('assert'); const http = require('http'); -const util = require('util'); -assert(Array.isArray(http.METHODS)); -assert(http.METHODS.length > 0); -assert(http.METHODS.includes('GET')); -assert(http.METHODS.includes('HEAD')); -assert(http.METHODS.includes('POST')); -assert.deepStrictEqual(util._extend([], http.METHODS), http.METHODS.sort()); +// This test ensures all http methods from HTTP parser are exposed +// to http library + +const methods = [ + 'DELETE', + 'GET', + 'HEAD', + 'POST', + 'PUT', + 'CONNECT', + 'OPTIONS', + 'TRACE', + 'COPY', + 'LOCK', + 'MKCOL', + 'MOVE', + 'PROPFIND', + 'PROPPATCH', + 'SEARCH', + 'UNLOCK', + 'BIND', + 'REBIND', + 'UNBIND', + 'ACL', + 'REPORT', + 'MKACTIVITY', + 'CHECKOUT', + 'MERGE', + 'M-SEARCH', + 'NOTIFY', + 'SUBSCRIBE', + 'UNSUBSCRIBE', + 'PATCH', + 'PURGE', + 'MKCALENDAR', + 'LINK', + 'UNLINK' +]; + +assert.deepStrictEqual(http.METHODS, methods.sort()); diff --git a/test/parallel/test-http-parser.js b/test/parallel/test-http-parser.js index 92ff0c9dbde436..7b2d08a82b8608 100644 --- a/test/parallel/test-http-parser.js +++ b/test/parallel/test-http-parser.js @@ -32,7 +32,7 @@ function newParser(type) { parser.url += url; }; - parser[kOnHeadersComplete] = function(info) { + parser[kOnHeadersComplete] = function() { }; parser[kOnBody] = function(b, start, len) { @@ -76,8 +76,7 @@ function expectBody(expected) { const request = Buffer.from(`GET /hello HTTP/1.1${CRLF}${CRLF}`); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(versionMajor, 1); assert.strictEqual(versionMinor, 1); assert.strictEqual(method, methods.indexOf('GET')); @@ -93,7 +92,7 @@ function expectBody(expected) { // thrown from parser.execute() // - parser[kOnHeadersComplete] = function(info) { + parser[kOnHeadersComplete] = function() { throw new Error('hello world'); }; @@ -117,8 +116,7 @@ function expectBody(expected) { 'pong'); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url, statusCode, statusMessage) => { assert.strictEqual(method, undefined); assert.strictEqual(versionMajor, 1); assert.strictEqual(versionMinor, 1); @@ -146,8 +144,7 @@ function expectBody(expected) { `HTTP/1.0 200 Connection established${CRLF}${CRLF}`); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url, statusCode, statusMessage) => { assert.strictEqual(versionMajor, 1); assert.strictEqual(versionMinor, 0); assert.strictEqual(method, undefined); @@ -179,15 +176,14 @@ function expectBody(expected) { let seen_body = false; - const onHeaders = (headers, url) => { + const onHeaders = (headers) => { assert.ok(seen_body); // trailers should come after the body assert.deepStrictEqual(headers, ['Vary', '*', 'Content-Type', 'text/plain']); }; const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/it'); assert.strictEqual(versionMajor, 1); @@ -221,8 +217,7 @@ function expectBody(expected) { CRLF); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method) => { assert.strictEqual(method, methods.indexOf('GET')); assert.strictEqual(versionMajor, 1); assert.strictEqual(versionMinor, 0); @@ -250,8 +245,7 @@ function expectBody(expected) { CRLF); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('GET')); assert.strictEqual(url || parser.url, '/foo/bar/baz?quux=42#1337'); assert.strictEqual(versionMajor, 1); @@ -284,8 +278,7 @@ function expectBody(expected) { 'foo=42&bar=1337'); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/it'); assert.strictEqual(versionMajor, 1); @@ -322,8 +315,7 @@ function expectBody(expected) { '0' + CRLF); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/it'); assert.strictEqual(versionMajor, 1); @@ -360,8 +352,7 @@ function expectBody(expected) { '123456' + CRLF); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/it'); assert.strictEqual(versionMajor, 1); @@ -418,8 +409,7 @@ function expectBody(expected) { function test(a, b) { const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/helpme'); assert.strictEqual(versionMajor, 1); @@ -475,8 +465,7 @@ function expectBody(expected) { '0' + CRLF); const onHeadersComplete = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url || parser.url, '/it'); assert.strictEqual(versionMajor, 1); @@ -527,8 +516,7 @@ function expectBody(expected) { 'pong'); const onHeadersComplete1 = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('PUT')); assert.strictEqual(url, '/this'); assert.strictEqual(versionMajor, 1); @@ -539,8 +527,7 @@ function expectBody(expected) { }; const onHeadersComplete2 = (versionMajor, versionMinor, headers, - method, url, statusCode, statusMessage, - upgrade, shouldKeepAlive) => { + method, url) => { assert.strictEqual(method, methods.indexOf('POST')); assert.strictEqual(url, '/that'); assert.strictEqual(versionMajor, 1); diff --git a/test/parallel/test-http-server-stale-close.js b/test/parallel/test-http-server-stale-close.js index 3728453c039447..188fbdbe528cff 100644 --- a/test/parallel/test-http-server-stale-close.js +++ b/test/parallel/test-http-server-stale-close.js @@ -1,7 +1,6 @@ 'use strict'; require('../common'); const http = require('http'); -const util = require('util'); const fork = require('child_process').fork; if (process.env.NODE_TEST_FORK_PORT) { @@ -24,7 +23,9 @@ if (process.env.NODE_TEST_FORK_PORT) { }); server.listen(0, function() { fork(__filename, { - env: util._extend(process.env, {NODE_TEST_FORK_PORT: this.address().port}) + env: Object.assign({}, process.env, { + NODE_TEST_FORK_PORT: this.address().port + }) }); }); } diff --git a/test/parallel/test-http-upgrade-reconsume-stream.js b/test/parallel/test-http-upgrade-reconsume-stream.js new file mode 100644 index 00000000000000..e712ea647b3ad9 --- /dev/null +++ b/test/parallel/test-http-upgrade-reconsume-stream.js @@ -0,0 +1,29 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const tls = require('tls'); +const http = require('http'); + +// Tests that, after the HTTP parser stopped owning a socket that emits an +// 'upgrade' event, another C++ stream can start owning it (e.g. a TLSSocket). + +const server = http.createServer(common.mustNotCall()); + +server.on('upgrade', common.mustCall((request, socket, head) => { + // This should not crash. + new tls.TLSSocket(socket); + server.close(); + socket.destroy(); +})); + +server.listen(0, common.mustCall(() => { + http.get({ + port: server.address().port, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket' + } + }).on('error', () => {}); +})); diff --git a/test/parallel/test-listen-fd-detached.js b/test/parallel/test-listen-fd-detached.js index 86d866afd13483..c9b840e2d8f04a 100644 --- a/test/parallel/test-listen-fd-detached.js +++ b/test/parallel/test-listen-fd-detached.js @@ -64,7 +64,6 @@ function parent() { }).listen(0, function() { console.error('server listening on %d', this.address().port); - const spawn = require('child_process').spawn; const child = spawn(process.execPath, [__filename, 'child'], { stdio: [ 'ignore', 'ignore', 'ignore', server._handle ], detached: true diff --git a/test/parallel/test-module-loading-error.js b/test/parallel/test-module-loading-error.js index cf6ce7e4bdeee8..80918d5fdb0eb3 100644 --- a/test/parallel/test-module-loading-error.js +++ b/test/parallel/test-module-loading-error.js @@ -8,7 +8,9 @@ const error_desc = { win32: ['%1 is not a valid Win32 application'], linux: ['file too short', 'Exec format error'], sunos: ['unknown file type', 'not an ELF file'], - darwin: ['file too short'] + darwin: ['file too short'], + aix: ['Cannot load module', + 'Cannot run a file that does not have a valid format.'] }; const dlerror_msg = error_desc[process.platform]; diff --git a/test/parallel/test-net-better-error-messages-path.js b/test/parallel/test-net-better-error-messages-path.js index f4d00c7aebf055..5f6203a5c2fe45 100644 --- a/test/parallel/test-net-better-error-messages-path.js +++ b/test/parallel/test-net-better-error-messages-path.js @@ -2,12 +2,21 @@ const common = require('../common'); const net = require('net'); const assert = require('assert'); -const fp = '/tmp/fadagagsdfgsdf'; -const c = net.connect(fp); -c.on('connect', common.mustNotCall()); +{ + const fp = '/tmp/fadagagsdfgsdf'; + const c = net.connect(fp); -c.on('error', common.mustCall(function(e) { - assert.strictEqual(e.code, 'ENOENT'); - assert.strictEqual(e.message, `connect ENOENT ${fp}`); -})); + c.on('connect', common.mustNotCall()); + c.on('error', common.mustCall(function(e) { + assert.strictEqual(e.code, 'ENOENT'); + assert.strictEqual(e.message, `connect ENOENT ${fp}`); + })); +} + +{ + assert.throws( + () => net.createConnection({ path: {} }), + /"path" option must be a string: \[object Object]/ + ); +} diff --git a/test/parallel/test-net-listen-port-option.js b/test/parallel/test-net-listen-port-option.js index c4851bd533dfbe..3f5f69da735108 100644 --- a/test/parallel/test-net-listen-port-option.js +++ b/test/parallel/test-net-listen-port-option.js @@ -26,3 +26,47 @@ net.Server().listen({ port: '' + common.PORT }, close); net.Server().listen({ port: port }, common.fail); }, /invalid listen argument/i); }); + +// Repeat the tests, passing port as an argument, which validates somewhat +// differently. + +net.Server().listen(undefined, close); +net.Server().listen('0', close); + +// 'nan', skip, treated as a path, not a port +//'+Infinity', skip, treated as a path, not a port +//'-Infinity' skip, treated as a path, not a port + +// 4.x treats these as 0, but 6.x treats them as invalid numbers. +[ + -1, + 123.456, + 0x10000, + 1 / 0, + -1 / 0, +].forEach(function(port) { + assert.throws(function() { + net.Server().listen(port, common.fail); + }, /"port" argument must be >= 0 and < 65536/i); +}); + +// null is treated as 0 +net.Server().listen(null, close); + +// false/true are converted to 0/1, arguably a bug, but fixing would be +// semver-major. Note that true fails when port 1 low can't be listened on by +// unprivileged processes (Linux) but the listen does succeed on some Windows +// versions. +net.Server().listen(false, close); + +(function() { + const done = common.mustCall(function(err) { + if (err) + return assert.strictEqual(err.code, 'EACCES'); + + assert.strictEqual(this.address().port, 1); + this.close(); + }); + + net.Server().listen(true).on('error', done).on('listening', done); +})(); diff --git a/test/parallel/test-net-pause-resume-connecting.js b/test/parallel/test-net-pause-resume-connecting.js index 1ae51d51fb25f2..602a449359f456 100644 --- a/test/parallel/test-net-pause-resume-connecting.js +++ b/test/parallel/test-net-pause-resume-connecting.js @@ -19,27 +19,27 @@ const server = net.createServer(function(conn) { server.listen(0, function() { // Client 1 - conn = require('net').createConnection(this.address().port, 'localhost'); + conn = net.createConnection(this.address().port, 'localhost'); conn.resume(); conn.on('data', onDataOk); // Client 2 - conn = require('net').createConnection(this.address().port, 'localhost'); + conn = net.createConnection(this.address().port, 'localhost'); conn.pause(); conn.resume(); conn.on('data', onDataOk); // Client 3 - conn = require('net').createConnection(this.address().port, 'localhost'); + conn = net.createConnection(this.address().port, 'localhost'); conn.pause(); conn.on('data', common.mustNotCall()); scheduleTearDown(conn); // Client 4 - conn = require('net').createConnection(this.address().port, 'localhost'); + conn = net.createConnection(this.address().port, 'localhost'); conn.resume(); conn.pause(); conn.resume(); @@ -47,7 +47,7 @@ server.listen(0, function() { // Client 5 - conn = require('net').createConnection(this.address().port, 'localhost'); + conn = net.createConnection(this.address().port, 'localhost'); conn.resume(); conn.resume(); conn.pause(); diff --git a/test/parallel/test-npm-install.js b/test/parallel/test-npm-install.js index 315f7885e840d6..8c7443c21f82ee 100644 --- a/test/parallel/test-npm-install.js +++ b/test/parallel/test-npm-install.js @@ -2,7 +2,7 @@ const common = require('../common'); const path = require('path'); -const spawn = require('child_process').spawn; +const exec = require('child_process').exec; const assert = require('assert'); const fs = require('fs'); @@ -22,11 +22,6 @@ const npmPath = path.join( 'npm-cli.js' ); -const args = [ - npmPath, - 'install' -]; - const pkgContent = JSON.stringify({ dependencies: { 'package-name': `${common.fixturesDir}/packages/main` @@ -37,23 +32,29 @@ const pkgPath = path.join(installDir, 'package.json'); fs.writeFileSync(pkgPath, pkgContent); -const env = Object.create(process.env); -env['PATH'] = path.dirname(process.execPath); -env['NPM_CONFIG_PREFIX'] = path.join(npmSandbox, 'npm-prefix'); -env['NPM_CONFIG_TMP'] = path.join(npmSandbox, 'npm-tmp'); -env['HOME'] = path.join(npmSandbox, 'home'); +const env = Object.assign({}, process.env, { + PATH: path.dirname(process.execPath), + NPM_CONFIG_PREFIX: path.join(npmSandbox, 'npm-prefix'), + NPM_CONFIG_TMP: path.join(npmSandbox, 'npm-tmp'), + HOME: path.join(npmSandbox, 'home'), +}); -const proc = spawn(process.execPath, args, { +exec(`${process.execPath} ${npmPath} install`, { cwd: installDir, env: env -}); +}, common.mustCall(handleExit)); + +function handleExit(error, stdout, stderr) { + const code = error ? error.code : 0; + const signalCode = error ? error.signal : null; + + if (code !== 0) { + process.stderr.write(stderr); + } -function handleExit(code, signalCode) { assert.strictEqual(code, 0, `npm install got error code ${code}`); assert.strictEqual(signalCode, null, `unexpected signal: ${signalCode}`); assert.doesNotThrow(function() { fs.accessSync(`${installDir}/node_modules/package-name`); }); } - -proc.on('exit', common.mustCall(handleExit)); diff --git a/test/parallel/test-os.js b/test/parallel/test-os.js index db5a137eb54ef4..f3c0082f553c1d 100644 --- a/test/parallel/test-os.js +++ b/test/parallel/test-os.js @@ -104,7 +104,8 @@ console.error(interfaces); switch (platform) { case 'linux': { - const filter = (e) => e.address === '127.0.0.1'; + const filter = + (e) => e.address === '127.0.0.1' && e.netmask === '255.0.0.0'; const actual = interfaces.lo.filter(filter); const expected = [{ address: '127.0.0.1', netmask: '255.0.0.0', mac: '00:00:00:00:00:00', family: 'IPv4', diff --git a/test/parallel/test-process-exit-code.js b/test/parallel/test-process-exit-code.js index a956ee19310f26..c26a72fcc596d7 100644 --- a/test/parallel/test-process-exit-code.js +++ b/test/parallel/test-process-exit-code.js @@ -62,22 +62,23 @@ function child5() { } function parent() { + const { spawn } = require('child_process'); + const node = process.execPath; + const f = __filename; + const option = { stdio: [ 0, 1, 'ignore' ] }; + + const test = (arg, exit) => { + spawn(node, [f, arg], option).on('exit', (code) => { + assert.strictEqual( + code, exit, + `wrong exit for ${arg}\nexpected:${exit} but got:${code}`); + console.log('ok - %s exited with %d', arg, exit); + }); + }; + test('child1', 42); test('child2', 42); test('child3', 0); test('child4', 1); test('child5', 99); } - -function test(arg, exit) { - const spawn = require('child_process').spawn; - const node = process.execPath; - const f = __filename; - const option = { stdio: [ 0, 1, 'ignore' ] }; - spawn(node, [f, arg], option).on('exit', function(code) { - assert.strictEqual( - code, exit, - `wrong exit for ${arg}\nexpected:${exit} but got:${code}`); - console.log('ok - %s exited with %d', arg, exit); - }); -} diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index d101a4582dfadb..a042514a9eea21 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -4,8 +4,7 @@ const assert = require('assert'); const readline = require('readline'); const EventEmitter = require('events').EventEmitter; const inherits = require('util').inherits; -const Writable = require('stream').Writable; -const Readable = require('stream').Readable; +const { Writable, Readable } = require('stream'); function FakeInput() { EventEmitter.call(this); @@ -41,192 +40,248 @@ function isWarned(emitter) { } { - // Maximum crlfDelay is 2000ms + // set crlfDelay to float 100.5ms const fi = new FakeInput(); const rli = new readline.Interface({ input: fi, output: fi, - crlfDelay: 1 << 30 + crlfDelay: 100.5 }); - assert.strictEqual(rli.crlfDelay, 2000); + assert.strictEqual(rli.crlfDelay, 100.5); rli.close(); } -[ true, false ].forEach(function(terminal) { - let fi; - let rli; - let called; +{ + const fi = new FakeInput(); + const rli = new readline.Interface({ + input: fi, + output: fi, + crlfDelay: 5000 + }); + assert.strictEqual(rli.crlfDelay, 5000); + rli.close(); +} +[ true, false ].forEach(function(terminal) { // disable history - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal, - historySize: 0 }); - assert.strictEqual(rli.historySize, 0); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal, historySize: 0 } + ); + assert.strictEqual(rli.historySize, 0); - fi.emit('data', 'asdf\n'); - assert.deepStrictEqual(rli.history, terminal ? [] : undefined); - rli.close(); + fi.emit('data', 'asdf\n'); + assert.deepStrictEqual(rli.history, terminal ? [] : undefined); + rli.close(); + } // default history size 30 - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal}); - assert.strictEqual(rli.historySize, 30); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + assert.strictEqual(rli.historySize, 30); - fi.emit('data', 'asdf\n'); - assert.deepStrictEqual(rli.history, terminal ? ['asdf'] : undefined); - rli.close(); + fi.emit('data', 'asdf\n'); + assert.deepStrictEqual(rli.history, terminal ? ['asdf'] : undefined); + rli.close(); + } // sending a full line - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - called = false; - rli.on('line', function(line) { - called = true; - assert.strictEqual(line, 'asdf'); - }); - fi.emit('data', 'asdf\n'); - assert.ok(called); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + let called = false; + rli.on('line', function(line) { + called = true; + assert.strictEqual(line, 'asdf'); + }); + fi.emit('data', 'asdf\n'); + assert.ok(called); + } // sending a blank line - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - called = false; - rli.on('line', function(line) { - called = true; - assert.strictEqual(line, ''); - }); - fi.emit('data', '\n'); - assert.ok(called); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + let called = false; + rli.on('line', function(line) { + called = true; + assert.strictEqual(line, ''); + }); + fi.emit('data', '\n'); + assert.ok(called); + } // sending a single character with no newline - fi = new FakeInput(); - rli = new readline.Interface(fi, {}); - called = false; - rli.on('line', function(line) { - called = true; - }); - fi.emit('data', 'a'); - assert.ok(!called); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface(fi, {}); + let called = false; + rli.on('line', function(line) { + called = true; + }); + fi.emit('data', 'a'); + assert.ok(!called); + rli.close(); + } // sending a single character with no newline and then a newline - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - called = false; - rli.on('line', function(line) { - called = true; - assert.strictEqual(line, 'a'); - }); - fi.emit('data', 'a'); - assert.ok(!called); - fi.emit('data', '\n'); - assert.ok(called); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + let called = false; + rli.on('line', function(line) { + called = true; + assert.strictEqual(line, 'a'); + }); + fi.emit('data', 'a'); + assert.ok(!called); + fi.emit('data', '\n'); + assert.ok(called); + rli.close(); + } // sending multiple newlines at once - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - let expectedLines = ['foo', 'bar', 'baz']; - let callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', `${expectedLines.join('\n')}\n`); - assert.strictEqual(callCount, expectedLines.length); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar', 'baz']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', `${expectedLines.join('\n')}\n`); + assert.strictEqual(callCount, expectedLines.length); + rli.close(); + } // sending multiple newlines at once that does not end with a new line - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo', 'bar', 'baz', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', expectedLines.join('\n')); - assert.strictEqual(callCount, expectedLines.length - 1); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar', 'baz', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', expectedLines.join('\n')); + assert.strictEqual(callCount, expectedLines.length - 1); + rli.close(); + } // sending multiple newlines at once that does not end with a new(empty) // line and a `end` event - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo', 'bar', 'baz', '']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - rli.on('close', function() { - callCount++; - }); - fi.emit('data', expectedLines.join('\n')); - fi.emit('end'); - assert.strictEqual(callCount, expectedLines.length); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar', 'baz', '']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + rli.on('close', function() { + callCount++; + }); + fi.emit('data', expectedLines.join('\n')); + fi.emit('end'); + assert.strictEqual(callCount, expectedLines.length); + rli.close(); + } // sending multiple newlines at once that does not end with a new line // and a `end` event(last line is) // \r\n should emit one line event, not two - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo', 'bar', 'baz', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', expectedLines.join('\r\n')); - assert.strictEqual(callCount, expectedLines.length - 1); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar', 'baz', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', expectedLines.join('\r\n')); + assert.strictEqual(callCount, expectedLines.length - 1); + rli.close(); + } // \r\n should emit one line event when split across multiple writes. - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo', 'bar', 'baz', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - expectedLines.forEach(function(line) { - fi.emit('data', `${line}\r`); - fi.emit('data', '\n'); - }); - assert.strictEqual(callCount, expectedLines.length); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar', 'baz', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + expectedLines.forEach(function(line) { + fi.emit('data', `${line}\r`); + fi.emit('data', '\n'); + }); + assert.strictEqual(callCount, expectedLines.length); + rli.close(); + } // \r should behave like \n when alone - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: true }); - expectedLines = ['foo', 'bar', 'baz', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', expectedLines.join('\r')); - assert.strictEqual(callCount, expectedLines.length - 1); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: true } + ); + const expectedLines = ['foo', 'bar', 'baz', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', expectedLines.join('\r')); + assert.strictEqual(callCount, expectedLines.length - 1); + rli.close(); + } // \r at start of input should output blank line - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: true }); - expectedLines = ['', 'foo' ]; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', '\rfoo\r'); - assert.strictEqual(callCount, expectedLines.length); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: true } + ); + const expectedLines = ['', 'foo' ]; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', '\rfoo\r'); + assert.strictEqual(callCount, expectedLines.length); + rli.close(); + } // Emit two line events when the delay - // between \r and \n exceeds crlfDelay + // between \r and \n exceeds crlfDelay { const fi = new FakeInput(); const delay = 200; @@ -248,191 +303,270 @@ function isWarned(emitter) { }), delay * 2); } + // Emit one line events when the delay between \r and \n is + // over the default crlfDelay but within the setting value + { + const fi = new FakeInput(); + const delay = 125; + const crlfDelay = common.platformTimeout(1000); + const rli = new readline.Interface({ + input: fi, + output: fi, + terminal: terminal, + crlfDelay + }); + let callCount = 0; + rli.on('line', function(line) { + callCount++; + }); + fi.emit('data', '\r'); + setTimeout(common.mustCall(() => { + fi.emit('data', '\n'); + assert.strictEqual(callCount, 1); + rli.close(); + }), delay); + } + + // set crlfDelay to `Infinity` is allowed + { + const fi = new FakeInput(); + const delay = 200; + const crlfDelay = Infinity; + const rli = new readline.Interface({ + input: fi, + output: fi, + terminal: terminal, + crlfDelay + }); + let callCount = 0; + rli.on('line', function(line) { + callCount++; + }); + fi.emit('data', '\r'); + setTimeout(common.mustCall(() => { + fi.emit('data', '\n'); + assert.strictEqual(callCount, 1); + rli.close(); + }), delay); + } + // \t when there is no completer function should behave like an ordinary - // character - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: true }); - called = false; - rli.on('line', function(line) { - assert.strictEqual(line, '\t'); - assert.strictEqual(called, false); - called = true; - }); - fi.emit('data', '\t'); - fi.emit('data', '\n'); - assert.ok(called); - rli.close(); + // character + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: true } + ); + let called = false; + rli.on('line', function(line) { + assert.strictEqual(line, '\t'); + assert.strictEqual(called, false); + called = true; + }); + fi.emit('data', '\t'); + fi.emit('data', '\n'); + assert.ok(called); + rli.close(); + } // \t does not become part of the input when there is a completer function - fi = new FakeInput(); - const completer = (line) => [[], line]; - rli = new readline.Interface({ - input: fi, - output: fi, - terminal: true, - completer: completer - }); - called = false; - rli.on('line', function(line) { - assert.strictEqual(line, 'foo'); - assert.strictEqual(called, false); - called = true; - }); - for (const character of '\tfo\to\t') { - fi.emit('data', character); + { + const fi = new FakeInput(); + const completer = (line) => [[], line]; + const rli = new readline.Interface({ + input: fi, + output: fi, + terminal: true, + completer: completer + }); + let called = false; + rli.on('line', function(line) { + assert.strictEqual(line, 'foo'); + assert.strictEqual(called, false); + called = true; + }); + for (const character of '\tfo\to\t') { + fi.emit('data', character); + } + fi.emit('data', '\n'); + assert.ok(called); + rli.close(); } - fi.emit('data', '\n'); - assert.ok(called); - rli.close(); // constructor throws if completer is not a function or undefined - fi = new FakeInput(); - assert.throws(function() { - readline.createInterface({ - input: fi, - completer: 'string is not valid' - }); - }, function(err) { - if (err instanceof TypeError) { - if (/Argument "completer" must be a function/.test(err)) { - return true; + { + const fi = new FakeInput(); + assert.throws(function() { + readline.createInterface({ + input: fi, + completer: 'string is not valid' + }); + }, function(err) { + if (err instanceof TypeError) { + if (/Argument "completer" must be a function/.test(err)) { + return true; + } } - } - return false; - }); + return false; + }); + } // duplicate lines are removed from history when // `options.removeHistoryDuplicates` is `true` - fi = new FakeInput(); - rli = new readline.Interface({ - input: fi, - output: fi, - terminal: true, - removeHistoryDuplicates: true - }); - expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', `${expectedLines.join('\n')}\n`); - assert.strictEqual(callCount, expectedLines.length); - fi.emit('keypress', '.', { name: 'up' }); // 'bat' - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'bar' - assert.notStrictEqual(rli.line, expectedLines[--callCount]); - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'baz' - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'foo' - assert.notStrictEqual(rli.line, expectedLines[--callCount]); - assert.strictEqual(rli.line, expectedLines[--callCount]); - assert.strictEqual(callCount, 0); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface({ + input: fi, + output: fi, + terminal: true, + removeHistoryDuplicates: true + }); + const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', `${expectedLines.join('\n')}\n`); + assert.strictEqual(callCount, expectedLines.length); + fi.emit('keypress', '.', { name: 'up' }); // 'bat' + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'bar' + assert.notStrictEqual(rli.line, expectedLines[--callCount]); + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'baz' + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'foo' + assert.notStrictEqual(rli.line, expectedLines[--callCount]); + assert.strictEqual(rli.line, expectedLines[--callCount]); + assert.strictEqual(callCount, 0); + rli.close(); + } // duplicate lines are not removed from history when // `options.removeHistoryDuplicates` is `false` - fi = new FakeInput(); - rli = new readline.Interface({ - input: fi, - output: fi, - terminal: true, - removeHistoryDuplicates: false - }); - expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; - callCount = 0; - rli.on('line', function(line) { - assert.strictEqual(line, expectedLines[callCount]); - callCount++; - }); - fi.emit('data', `${expectedLines.join('\n')}\n`); - assert.strictEqual(callCount, expectedLines.length); - fi.emit('keypress', '.', { name: 'up' }); // 'bat' - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'bar' - assert.notStrictEqual(rli.line, expectedLines[--callCount]); - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'baz' - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'bar' - assert.strictEqual(rli.line, expectedLines[--callCount]); - fi.emit('keypress', '.', { name: 'up' }); // 'foo' - assert.strictEqual(rli.line, expectedLines[--callCount]); - assert.strictEqual(callCount, 0); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface({ + input: fi, + output: fi, + terminal: true, + removeHistoryDuplicates: false + }); + const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; + let callCount = 0; + rli.on('line', function(line) { + assert.strictEqual(line, expectedLines[callCount]); + callCount++; + }); + fi.emit('data', `${expectedLines.join('\n')}\n`); + assert.strictEqual(callCount, expectedLines.length); + fi.emit('keypress', '.', { name: 'up' }); // 'bat' + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'bar' + assert.notStrictEqual(rli.line, expectedLines[--callCount]); + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'baz' + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'bar' + assert.strictEqual(rli.line, expectedLines[--callCount]); + fi.emit('keypress', '.', { name: 'up' }); // 'foo' + assert.strictEqual(rli.line, expectedLines[--callCount]); + assert.strictEqual(callCount, 0); + rli.close(); + } // sending a multi-byte utf8 char over multiple writes - const buf = Buffer.from('☮', 'utf8'); - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - callCount = 0; - rli.on('line', function(line) { - callCount++; - assert.strictEqual(line, buf.toString('utf8')); - }); - [].forEach.call(buf, function(i) { - fi.emit('data', Buffer.from([i])); - }); - assert.strictEqual(callCount, 0); - fi.emit('data', '\n'); - assert.strictEqual(callCount, 1); - rli.close(); + { + const buf = Buffer.from('☮', 'utf8'); + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + let callCount = 0; + rli.on('line', function(line) { + callCount++; + assert.strictEqual(line, buf.toString('utf8')); + }); + [].forEach.call(buf, function(i) { + fi.emit('data', Buffer.from([i])); + }); + assert.strictEqual(callCount, 0); + fi.emit('data', '\n'); + assert.strictEqual(callCount, 1); + rli.close(); + } // Regression test for repl freeze, #1968: // check that nothing fails if 'keypress' event throws. - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: true }); - const keys = []; - fi.on('keypress', function(key) { - keys.push(key); - if (key === 'X') { - throw new Error('bad thing happened'); - } - }); - try { - fi.emit('data', 'fooX'); - } catch (e) { } - fi.emit('data', 'bar'); - assert.strictEqual(keys.join(''), 'fooXbar'); - rli.close(); + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: true } + ); + const keys = []; + fi.on('keypress', function(key) { + keys.push(key); + if (key === 'X') { + throw new Error('bad thing happened'); + } + }); + try { + fi.emit('data', 'fooX'); + } catch (e) { } + fi.emit('data', 'bar'); + assert.strictEqual(keys.join(''), 'fooXbar'); + rli.close(); + } // calling readline without `new` - fi = new FakeInput(); - rli = readline.Interface({ input: fi, output: fi, terminal: terminal }); - called = false; - rli.on('line', function(line) { - called = true; - assert.strictEqual(line, 'asdf'); - }); - fi.emit('data', 'asdf\n'); - assert.ok(called); - rli.close(); + { + const fi = new FakeInput(); + const rli = readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + let called = false; + rli.on('line', function(line) { + called = true; + assert.strictEqual(line, 'asdf'); + }); + fi.emit('data', 'asdf\n'); + assert.ok(called); + rli.close(); + } if (terminal) { // question - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo']; - rli.question(expectedLines[0], function() { + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo']; + rli.question(expectedLines[0], function() { + rli.close(); + }); + const cursorPos = rli._getCursorPos(); + assert.strictEqual(cursorPos.rows, 0); + assert.strictEqual(cursorPos.cols, expectedLines[0].length); rli.close(); - }); - let cursorPos = rli._getCursorPos(); - assert.strictEqual(cursorPos.rows, 0); - assert.strictEqual(cursorPos.cols, expectedLines[0].length); - rli.close(); + } // sending a multi-line question - fi = new FakeInput(); - rli = new readline.Interface({ input: fi, output: fi, terminal: terminal }); - expectedLines = ['foo', 'bar']; - rli.question(expectedLines.join('\n'), function() { + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: fi, terminal: terminal } + ); + const expectedLines = ['foo', 'bar']; + rli.question(expectedLines.join('\n'), function() { + rli.close(); + }); + const cursorPos = rli._getCursorPos(); + assert.strictEqual(cursorPos.rows, expectedLines.length - 1); + assert.strictEqual(cursorPos.cols, expectedLines.slice(-1)[0].length); rli.close(); - }); - cursorPos = rli._getCursorPos(); - assert.strictEqual(cursorPos.rows, expectedLines.length - 1); - assert.strictEqual(cursorPos.cols, expectedLines.slice(-1)[0].length); - rli.close(); + } } // isFullWidthCodePoint() should return false for non-numeric values @@ -482,7 +616,10 @@ function isWarned(emitter) { assert.strictEqual(readline.getStringWidth('\u001b[31m\u001b[39m'), 0); assert.strictEqual(readline.getStringWidth('> '), 2); - assert.deepStrictEqual(fi.listeners(terminal ? 'keypress' : 'data'), []); + { + const fi = new FakeInput(); + assert.deepStrictEqual(fi.listeners(terminal ? 'keypress' : 'data'), []); + } // check EventEmitter memory leak for (let i = 0; i < 12; i++) { @@ -495,36 +632,40 @@ function isWarned(emitter) { assert.strictEqual(isWarned(process.stdout._events), false); } - //can create a new readline Interface with a null output arugument - fi = new FakeInput(); - rli = new readline.Interface({input: fi, output: null, terminal: terminal }); + // can create a new readline Interface with a null output arugument + { + const fi = new FakeInput(); + const rli = new readline.Interface( + { input: fi, output: null, terminal: terminal } + ); - called = false; - rli.on('line', function(line) { - called = true; - assert.strictEqual(line, 'asdf'); - }); - fi.emit('data', 'asdf\n'); - assert.ok(called); + let called = false; + rli.on('line', function(line) { + called = true; + assert.strictEqual(line, 'asdf'); + }); + fi.emit('data', 'asdf\n'); + assert.ok(called); - assert.doesNotThrow(function() { - rli.setPrompt('ddd> '); - }); + assert.doesNotThrow(function() { + rli.setPrompt('ddd> '); + }); - assert.doesNotThrow(function() { - rli.prompt(); - }); + assert.doesNotThrow(function() { + rli.prompt(); + }); - assert.doesNotThrow(function() { - rli.write('really shouldnt be seeing this'); - }); + assert.doesNotThrow(function() { + rli.write('really shouldnt be seeing this'); + }); - assert.doesNotThrow(function() { - rli.question('What do you think of node.js? ', function(answer) { - console.log('Thank you for your valuable feedback:', answer); - rli.close(); + assert.doesNotThrow(function() { + rli.question('What do you think of node.js? ', function(answer) { + console.log('Thank you for your valuable feedback:', answer); + rli.close(); + }); }); - }); + } { const expected = terminal diff --git a/test/parallel/test-repl-envvars.js b/test/parallel/test-repl-envvars.js index 5f597e0abb78ca..c0b1f53b3c2efc 100644 --- a/test/parallel/test-repl-envvars.js +++ b/test/parallel/test-repl-envvars.js @@ -36,7 +36,7 @@ const tests = [ ]; function run(test) { - const env = test.env; + const env = Object.assign({}, process.env, test.env); const expected = test.expected; const opts = { terminal: true, diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index c471b185dd6531..3b705f7b6be97f 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -387,7 +387,13 @@ function error_test() { { client: client_unix, send: '(function() {\nif (false) {} /bar"/;\n}())', expect: `${prompt_multiline}${prompt_multiline}undefined\n${prompt_unix}` - } + }, + // Do not parse `...[]` as a REPL keyword + { client: client_unix, send: '...[]\n', + expect: `${prompt_multiline}` }, + // bring back the repl to prompt + { client: client_unix, send: '.break', + expect: `${prompt_unix}` } ]); } diff --git a/test/parallel/test-require-nul.js b/test/parallel/test-require-nul.js new file mode 100644 index 00000000000000..0c5cb7018d47fc --- /dev/null +++ b/test/parallel/test-require-nul.js @@ -0,0 +1,9 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); + +// Nul bytes should throw, not abort. +assert.throws(() => require('\u0000ab'), /Cannot find module '\u0000ab'/); +assert.throws(() => require('a\u0000b'), /Cannot find module 'a\u0000b'/); +assert.throws(() => require('ab\u0000'), /Cannot find module 'ab\u0000'/); diff --git a/test/parallel/test-require-symlink.js b/test/parallel/test-require-symlink.js index 85fcb2d2d16f9d..f5129e02739ca0 100644 --- a/test/parallel/test-require-symlink.js +++ b/test/parallel/test-require-symlink.js @@ -4,8 +4,7 @@ const common = require('../common'); const assert = require('assert'); const path = require('path'); const fs = require('fs'); -const exec = require('child_process').exec; -const spawn = require('child_process').spawn; +const { exec, spawn } = require('child_process'); common.refreshTmpDir(); diff --git a/test/parallel/test-stdin-script-child.js b/test/parallel/test-stdin-script-child.js index f215682fe4c345..af966baff7655d 100644 --- a/test/parallel/test-stdin-script-child.js +++ b/test/parallel/test-stdin-script-child.js @@ -4,7 +4,7 @@ const assert = require('assert'); const spawn = require('child_process').spawn; const child = spawn(process.execPath, [], { - env: Object.assign(process.env, { + env: Object.assign({}, process.env, { NODE_DEBUG: process.argv[2] }) }); diff --git a/test/parallel/test-stream-inheritance.js b/test/parallel/test-stream-inheritance.js index 77dc4804c1f986..aefb39af512646 100644 --- a/test/parallel/test-stream-inheritance.js +++ b/test/parallel/test-stream-inheritance.js @@ -33,8 +33,14 @@ assert.ok(!(undefined instanceof Writable)); // Simple inheritance check for `Writable` works fine in a subclass constructor. function CustomWritable() { - assert.ok(this instanceof Writable, 'inherits from Writable'); - assert.ok(this instanceof CustomWritable, 'inherits from CustomWritable'); + assert.ok( + this instanceof CustomWritable, + `${this} does not inherit from CustomWritable` + ); + assert.ok( + this instanceof Writable, + `${this} does not inherit from Writable` + ); } Object.setPrototypeOf(CustomWritable, Writable); @@ -42,4 +48,9 @@ Object.setPrototypeOf(CustomWritable.prototype, Writable.prototype); new CustomWritable(); -assert.throws(CustomWritable, /AssertionError: inherits from Writable/); +assert.throws(CustomWritable, /AssertionError: undefined does not inherit from CustomWritable/); + +class OtherCustomWritable extends Writable {} + +assert(!(new OtherCustomWritable() instanceof CustomWritable)); +assert(!(new CustomWritable() instanceof OtherCustomWritable)); diff --git a/test/parallel/test-timers-immediate.js b/test/parallel/test-timers-immediate.js index 9632022917f152..01e034fa580140 100644 --- a/test/parallel/test-timers-immediate.js +++ b/test/parallel/test-timers-immediate.js @@ -2,10 +2,6 @@ const common = require('../common'); const assert = require('assert'); -let immediateB; -let immediateC; -let immediateD; - let mainFinished = false; setImmediate(common.mustCall(function() { @@ -13,21 +9,16 @@ setImmediate(common.mustCall(function() { clearImmediate(immediateB); })); -immediateB = setImmediate(function() { +let immediateB = setImmediate(function() { common.fail('this immediate should not run'); }); -setImmediate(function(x, y, z) { - immediateC = [x, y, z]; -}, 1, 2, 3); - -setImmediate(function(x, y, z, a, b) { - immediateD = [x, y, z, a, b]; -}, 1, 2, 3, 4, 5); +setImmediate(common.mustCall((...args) => { + assert.deepStrictEqual(args, [1, 2, 3]); +}), 1, 2, 3); -process.on('exit', function() { - assert.deepStrictEqual(immediateC, [1, 2, 3], 'immediateC args should match'); - assert.deepStrictEqual(immediateD, [1, 2, 3, 4, 5], '5 args should match'); -}); +setImmediate(common.mustCall((...args) => { + assert.deepStrictEqual(args, [1, 2, 3, 4, 5]); +}), 1, 2, 3, 4, 5); mainFinished = true; diff --git a/test/parallel/test-timers-non-integer-delay.js b/test/parallel/test-timers-non-integer-delay.js index cd7fa5e661dc81..db50ec0a2cd8ac 100644 --- a/test/parallel/test-timers-non-integer-delay.js +++ b/test/parallel/test-timers-non-integer-delay.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); /* * This test makes sure that non-integer timer delays do not make the process @@ -18,13 +18,11 @@ require('../common'); */ const TIMEOUT_DELAY = 1.1; -const NB_TIMEOUTS_FIRED = 50; +let N = 50; -let nbTimeoutFired = 0; -const interval = setInterval(function() { - ++nbTimeoutFired; - if (nbTimeoutFired === NB_TIMEOUTS_FIRED) { +const interval = setInterval(common.mustCall(() => { + if (--N === 0) { clearInterval(interval); process.exit(0); } -}, TIMEOUT_DELAY); +}, N), TIMEOUT_DELAY); diff --git a/test/parallel/test-timers-socket-timeout-removes-other-socket-unref-timer.js b/test/parallel/test-timers-socket-timeout-removes-other-socket-unref-timer.js index f42144360b6941..4b8bc5fc6fda37 100644 --- a/test/parallel/test-timers-socket-timeout-removes-other-socket-unref-timer.js +++ b/test/parallel/test-timers-socket-timeout-removes-other-socket-unref-timer.js @@ -6,6 +6,7 @@ const common = require('../common'); const net = require('net'); +const Countdown = require('../common/countdown'); const clients = []; @@ -19,7 +20,7 @@ const server = net.createServer(function onClient(client) { * the list of unref timers when traversing it, and exposes the * original issue in joyent/node#8897. */ - clients[0].setTimeout(1, function onTimeout() { + clients[0].setTimeout(1, () => { clients[1].setTimeout(0); clients[0].end(); clients[1].end(); @@ -31,19 +32,16 @@ const server = net.createServer(function onClient(client) { } }); -server.listen(0, common.localhostIPv4, function() { - let nbClientsEnded = 0; +server.listen(0, common.localhostIPv4, common.mustCall(() => { + const countdown = new Countdown(2, common.mustCall(() => server.close())); - function addEndedClient(client) { - ++nbClientsEnded; - if (nbClientsEnded === 2) { - server.close(); - } + { + const client = net.connect({ port: server.address().port }); + client.on('end', () => countdown.dec()); } - const client1 = net.connect({ port: this.address().port }); - client1.on('end', addEndedClient); - - const client2 = net.connect({ port: this.address().port }); - client2.on('end', addEndedClient); -}); + { + const client = net.connect({ port: server.address().port }); + client.on('end', () => countdown.dec()); + } +})); diff --git a/test/parallel/test-timers-unref-leak.js b/test/parallel/test-timers-unref-leak.js index 8eef00dd4ffe92..afecf7f15ce1b5 100644 --- a/test/parallel/test-timers-unref-leak.js +++ b/test/parallel/test-timers-unref-leak.js @@ -1,27 +1,14 @@ 'use strict'; -require('../common'); -const assert = require('assert'); +const common = require('../common'); -let called = 0; -let closed = 0; - -const timeout = setTimeout(function() { - called++; -}, 10); +const timeout = setTimeout(common.mustCall(), 10); timeout.unref(); // Wrap `close` method to check if the handle was closed const close = timeout._handle.close; -timeout._handle.close = function() { - closed++; +timeout._handle.close = common.mustCall(function() { return close.apply(this, arguments); -}; +}); // Just to keep process alive and let previous timer's handle die -setTimeout(function() { -}, 50); - -process.on('exit', function() { - assert.strictEqual(called, 1); - assert.strictEqual(closed, 1); -}); +setTimeout(() => {}, 50); diff --git a/test/parallel/test-timers-unref.js b/test/parallel/test-timers-unref.js index aaa43720f6661c..e4bca54b7d7b03 100644 --- a/test/parallel/test-timers-unref.js +++ b/test/parallel/test-timers-unref.js @@ -1,59 +1,54 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); -let interval_fired = false; -let timeout_fired = false; let unref_interval = false; let unref_timer = false; -let unref_callbacks = 0; let checks = 0; const LONG_TIME = 10 * 1000; const SHORT_TIME = 100; -assert.doesNotThrow(function() { +assert.doesNotThrow(() => { setTimeout(() => {}, 10).unref().ref().unref(); }, 'ref and unref are chainable'); -assert.doesNotThrow(function() { +assert.doesNotThrow(() => { setInterval(() => {}, 10).unref().ref().unref(); }, 'ref and unref are chainable'); -setInterval(function() { - interval_fired = true; -}, LONG_TIME).unref(); +setInterval(common.mustNotCall('Interval should not fire'), LONG_TIME).unref(); +setTimeout(common.mustNotCall('Timer should not fire'), LONG_TIME).unref(); -setTimeout(function() { - timeout_fired = true; -}, LONG_TIME).unref(); - -const interval = setInterval(function() { +const interval = setInterval(common.mustCall(() => { unref_interval = true; clearInterval(interval); -}, SHORT_TIME); +}), SHORT_TIME); interval.unref(); -setTimeout(function() { +setTimeout(common.mustCall(() => { unref_timer = true; -}, SHORT_TIME).unref(); +}), SHORT_TIME).unref(); -const check_unref = setInterval(function() { +const check_unref = setInterval(() => { if (checks > 5 || (unref_interval && unref_timer)) clearInterval(check_unref); checks += 1; }, 100); -setTimeout(function() { - unref_callbacks++; - this.unref(); -}, SHORT_TIME); +{ + const timeout = + setTimeout(common.mustCall(() => { + timeout.unref(); + }), SHORT_TIME); +} -// Should not timeout the test -setInterval(function() { - this.unref(); -}, SHORT_TIME); +{ + // Should not timeout the test + const timeout = + setInterval(() => timeout.unref(), SHORT_TIME); +} // Should not assert on args.Holder()->InternalFieldCount() > 0. See #4261. { @@ -61,16 +56,3 @@ setInterval(function() { process.nextTick(t.unref.bind({})); process.nextTick(t.unref.bind(t)); } - -process.on('exit', function() { - assert.strictEqual(interval_fired, false, - 'Interval should not fire'); - assert.strictEqual(timeout_fired, false, - 'Timeout should not fire'); - assert.strictEqual(unref_timer, true, - 'An unrefd timeout should still fire'); - assert.strictEqual(unref_interval, true, - 'An unrefd interval should still fire'); - assert.strictEqual(unref_callbacks, 1, - 'Callback should only run once'); -}); diff --git a/test/parallel/test-timers-unrefd-interval-still-fires.js b/test/parallel/test-timers-unrefd-interval-still-fires.js index bf16013f004965..a9e9af84304217 100644 --- a/test/parallel/test-timers-unrefd-interval-still-fires.js +++ b/test/parallel/test-timers-unrefd-interval-still-fires.js @@ -5,23 +5,20 @@ const common = require('../common'); const TEST_DURATION = common.platformTimeout(1000); -const N = 3; -let nbIntervalFired = 0; +let N = 3; -const keepOpen = setTimeout(() => { - console.error('[FAIL] Interval fired %d/%d times.', nbIntervalFired, N); - throw new Error('Test timed out. keepOpen was not canceled.'); -}, TEST_DURATION); +const keepOpen = + setTimeout( + common.mustNotCall('Test timed out. keepOpen was not canceled.'), + TEST_DURATION); -const timer = setInterval(() => { - ++nbIntervalFired; - if (nbIntervalFired === N) { +const timer = setInterval(common.mustCall(() => { + if (--N === 0) { clearInterval(timer); - timer._onTimeout = () => { - throw new Error('Unrefd interval fired after being cleared.'); - }; + timer._onTimeout = + common.mustNotCall('Unrefd interal fired after being cleared'); clearTimeout(keepOpen); } -}, 1); +}, N), 1); timer.unref(); diff --git a/test/parallel/test-timers-unrefed-in-beforeexit.js b/test/parallel/test-timers-unrefed-in-beforeexit.js index 530d97674d8bf7..a38b55bf45d599 100644 --- a/test/parallel/test-timers-unrefed-in-beforeexit.js +++ b/test/parallel/test-timers-unrefed-in-beforeexit.js @@ -1,20 +1,7 @@ 'use strict'; -require('../common'); -const assert = require('assert'); +const common = require('../common'); -let once = 0; - -process.on('beforeExit', () => { - if (once > 1) - throw new RangeError('beforeExit should only have been called once!'); - - setTimeout(() => {}, 1).unref(); - once++; -}); - -process.on('exit', (code) => { - if (code !== 0) return; - - assert.strictEqual(once, 1); -}); +process.on('beforeExit', common.mustCall(() => { + setTimeout(common.mustNotCall(), 1).unref(); +})); diff --git a/test/parallel/test-timers-zero-timeout.js b/test/parallel/test-timers-zero-timeout.js index 9728685c43277b..c835b4abcf0b2e 100644 --- a/test/parallel/test-timers-zero-timeout.js +++ b/test/parallel/test-timers-zero-timeout.js @@ -15,18 +15,14 @@ const assert = require('assert'); } { - let ncalled = 0; + let ncalled = 3; - const iv = setInterval(f, 0, 'foo', 'bar', 'baz'); - - function f(a, b, c) { + const f = common.mustCall((a, b, c) => { assert.strictEqual(a, 'foo'); assert.strictEqual(b, 'bar'); assert.strictEqual(c, 'baz'); - if (++ncalled === 3) clearTimeout(iv); - } + if (--ncalled === 0) clearTimeout(iv); + }, ncalled); - process.on('exit', function() { - assert.strictEqual(ncalled, 3); - }); + const iv = setInterval(f, 0, 'foo', 'bar', 'baz'); } diff --git a/test/parallel/test-tls-client-default-ciphers.js b/test/parallel/test-tls-client-default-ciphers.js index 91a0a86b1b7c53..5de7f8cf8a8ba2 100644 --- a/test/parallel/test-tls-client-default-ciphers.js +++ b/test/parallel/test-tls-client-default-ciphers.js @@ -16,11 +16,8 @@ function test1() { throw new Done(); }; - try { - tls.connect(common.PORT); - } catch (e) { - assert(e instanceof Done); - } + assert.throws(tls.connect, Done); + assert.strictEqual(ciphers, tls.DEFAULT_CIPHERS); } test1(); diff --git a/test/parallel/test-tls-connect.js b/test/parallel/test-tls-connect.js index b410f86180e00b..1419bd3a5ea427 100644 --- a/test/parallel/test-tls-connect.js +++ b/test/parallel/test-tls-connect.js @@ -1,13 +1,13 @@ 'use strict'; const common = require('../common'); -const assert = require('assert'); if (!common.hasCrypto) common.skip('missing crypto'); -const tls = require('tls'); +const assert = require('assert'); const fs = require('fs'); const path = require('path'); +const tls = require('tls'); // https://github.com/joyent/node/issues/1218 // uncatchable exception on TLS connection error @@ -18,7 +18,10 @@ const path = require('path'); const options = {cert: cert, key: key, port: common.PORT}; const conn = tls.connect(options, common.fail); - conn.on('error', common.mustCall()); + conn.on( + 'error', + common.mustCall((e) => { assert.strictEqual(e.code, 'ECONNREFUSED'); }) + ); } // SSL_accept/SSL_connect error handling @@ -35,5 +38,8 @@ const path = require('path'); assert.ok(false); // callback should never be executed }); - conn.on('error', common.mustCall()); + conn.on( + 'error', + common.mustCall((e) => { assert.strictEqual(e.code, 'ECONNREFUSED'); }) + ); } diff --git a/test/parallel/test-tls-ecdh-disable.js b/test/parallel/test-tls-ecdh-disable.js index a44ce2cedbe6b1..9921ccd1a11f75 100644 --- a/test/parallel/test-tls-ecdh-disable.js +++ b/test/parallel/test-tls-ecdh-disable.js @@ -14,7 +14,7 @@ const fs = require('fs'); const options = { key: fs.readFileSync(`${common.fixturesDir}/keys/agent2-key.pem`), cert: fs.readFileSync(`${common.fixturesDir}/keys/agent2-cert.pem`), - ciphers: 'ECDHE-RSA-RC4-SHA', + ciphers: 'ECDHE-RSA-AES128-SHA', ecdhCurve: false }; diff --git a/test/parallel/test-tls-session-cache.js b/test/parallel/test-tls-session-cache.js index 326e760f495e82..a1e6a615ae662f 100644 --- a/test/parallel/test-tls-session-cache.js +++ b/test/parallel/test-tls-session-cache.js @@ -1,11 +1,20 @@ 'use strict'; const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + if (!common.opensslCli) common.skip('node compiled without OpenSSL CLI.'); -if (!common.hasCrypto) - common.skip('missing crypto'); +const assert = require('assert'); +const tls = require('tls'); +const fs = require('fs'); +const { join } = require('path'); +const { spawn } = require('child_process'); + +const keyFile = join(common.fixturesDir, 'agent.key'); +const certFile = join(common.fixturesDir, 'agent.crt'); doTest({ tickets: false }, function() { doTest({ tickets: true }, function() { @@ -14,14 +23,6 @@ doTest({ tickets: false }, function() { }); function doTest(testOptions, callback) { - const assert = require('assert'); - const tls = require('tls'); - const fs = require('fs'); - const join = require('path').join; - const spawn = require('child_process').spawn; - - const keyFile = join(common.fixturesDir, 'agent.key'); - const certFile = join(common.fixturesDir, 'agent.crt'); const key = fs.readFileSync(keyFile); const cert = fs.readFileSync(certFile); const options = { diff --git a/test/parallel/test-tls-set-ciphers.js b/test/parallel/test-tls-set-ciphers.js index d53029e4cc9511..e6e14bcf87a507 100644 --- a/test/parallel/test-tls-set-ciphers.js +++ b/test/parallel/test-tls-set-ciphers.js @@ -15,7 +15,7 @@ const fs = require('fs'); const options = { key: fs.readFileSync(`${common.fixturesDir}/keys/agent2-key.pem`), cert: fs.readFileSync(`${common.fixturesDir}/keys/agent2-cert.pem`), - ciphers: 'DES-CBC3-SHA' + ciphers: 'AES256-SHA' }; const reply = 'I AM THE WALRUS'; // something recognizable diff --git a/test/parallel/test-tls-translate-peer-certificate.js b/test/parallel/test-tls-translate-peer-certificate.js new file mode 100644 index 00000000000000..537c00a009697a --- /dev/null +++ b/test/parallel/test-tls-translate-peer-certificate.js @@ -0,0 +1,55 @@ +'use strict'; +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const { strictEqual, deepStrictEqual } = require('assert'); +const { translatePeerCertificate } = require('_tls_common'); + +const certString = 'A=1\nB=2\nC=3'; +const certObject = { A: '1', B: '2', C: '3' }; + +strictEqual(translatePeerCertificate(null), null); +strictEqual(translatePeerCertificate(undefined), null); + +strictEqual(translatePeerCertificate(0), null); +strictEqual(translatePeerCertificate(1), 1); + +deepStrictEqual(translatePeerCertificate({}), {}); + +deepStrictEqual(translatePeerCertificate({ issuer: '' }), + { issuer: {} }); +deepStrictEqual(translatePeerCertificate({ issuer: null }), + { issuer: null }); +deepStrictEqual(translatePeerCertificate({ issuer: certString }), + { issuer: certObject }); + +deepStrictEqual(translatePeerCertificate({ subject: '' }), + { subject: {} }); +deepStrictEqual(translatePeerCertificate({ subject: null }), + { subject: null }); +deepStrictEqual(translatePeerCertificate({ subject: certString }), + { subject: certObject }); + +deepStrictEqual(translatePeerCertificate({ issuerCertificate: '' }), + { issuerCertificate: null }); +deepStrictEqual(translatePeerCertificate({ issuerCertificate: null }), + { issuerCertificate: null }); +deepStrictEqual( + translatePeerCertificate({ issuerCertificate: { subject: certString } }), + { issuerCertificate: { subject: certObject } }); + +{ + const cert = {}; + cert.issuerCertificate = cert; + deepStrictEqual(translatePeerCertificate(cert), { issuerCertificate: cert }); +} + +deepStrictEqual(translatePeerCertificate({ infoAccess: '' }), + { infoAccess: {} }); +deepStrictEqual(translatePeerCertificate({ infoAccess: null }), + { infoAccess: null }); +deepStrictEqual( + translatePeerCertificate({ infoAccess: 'OCSP - URI:file:///etc/passwd' }), + { infoAccess: { 'OCSP - URI': ['file:///etc/passwd'] } }); diff --git a/test/parallel/test-vm-context-async-script.js b/test/parallel/test-vm-context-async-script.js index 1e9ed629fb114f..2b1e4593ecbc70 100644 --- a/test/parallel/test-vm-context-async-script.js +++ b/test/parallel/test-vm-context-async-script.js @@ -1,14 +1,14 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const vm = require('vm'); -const sandbox = { setTimeout: setTimeout }; +const sandbox = { setTimeout }; const ctx = vm.createContext(sandbox); vm.runInContext('setTimeout(function() { x = 3; }, 0);', ctx); -setTimeout(function() { +setTimeout(common.mustCall(() => { assert.strictEqual(sandbox.x, 3); assert.strictEqual(ctx.x, 3); -}, 1); +}), 1); diff --git a/test/parallel/test-vm-context.js b/test/parallel/test-vm-context.js index a3b46cb89fa160..33116f52bb08e7 100644 --- a/test/parallel/test-vm-context.js +++ b/test/parallel/test-vm-context.js @@ -6,29 +6,29 @@ const vm = require('vm'); const Script = vm.Script; let script = new Script('"passed";'); -console.error('run in a new empty context'); +// Run in a new empty context let context = vm.createContext(); let result = script.runInContext(context); assert.strictEqual('passed', result); -console.error('create a new pre-populated context'); -context = vm.createContext({'foo': 'bar', 'thing': 'lala'}); +// Create a new pre-populated context +context = vm.createContext({ 'foo': 'bar', 'thing': 'lala' }); assert.strictEqual('bar', context.foo); assert.strictEqual('lala', context.thing); -console.error('test updating context'); +// Test updating context script = new Script('foo = 3;'); result = script.runInContext(context); assert.strictEqual(3, context.foo); assert.strictEqual('lala', context.thing); // Issue GH-227: -assert.throws(function() { +assert.throws(() => { vm.runInNewContext('', null, 'some.js'); }, /^TypeError: sandbox must be an object$/); // Issue GH-1140: -console.error('test runInContext signature'); +// Test runInContext signature let gh1140Exception; try { vm.runInContext('throw new Error()', context, 'expected-filename.js'); @@ -56,8 +56,8 @@ const contextifiedSandboxErrorMsg = }); // Issue GH-693: -console.error('test RegExp as argument to assert.throws'); -script = vm.createScript('var assert = require(\'assert\'); assert.throws(' + +// Test RegExp as argument to assert.throws +script = vm.createScript('const assert = require(\'assert\'); assert.throws(' + 'function() { throw "hello world"; }, /hello/);', 'some.js'); script.runInNewContext({ require: require }); @@ -71,14 +71,14 @@ assert.strictEqual(script.runInContext(ctx), false); // Error on the first line of a module should // have the correct line and column number -assert.throws(function() { +assert.throws(() => { vm.runInContext('throw new Error()', context, { filename: 'expected-filename.js', lineOffset: 32, columnOffset: 123 }); -}, function(err) { - return /expected-filename.js:33:130/.test(err.stack); +}, (err) => { + return /expected-filename\.js:33:130/.test(err.stack); }, 'Expected appearance of proper offset in Error stack'); // https://github.com/nodejs/node/issues/6158 diff --git a/test/parallel/test-vm-create-and-run-in-context.js b/test/parallel/test-vm-create-and-run-in-context.js index 7fd3f1d70436ad..e4f1524969148b 100644 --- a/test/parallel/test-vm-create-and-run-in-context.js +++ b/test/parallel/test-vm-create-and-run-in-context.js @@ -5,24 +5,24 @@ const assert = require('assert'); const vm = require('vm'); -console.error('run in a new empty context'); +// Run in a new empty context let context = vm.createContext(); let result = vm.runInContext('"passed";', context); assert.strictEqual('passed', result); -console.error('create a new pre-populated context'); -context = vm.createContext({'foo': 'bar', 'thing': 'lala'}); +// Create a new pre-populated context +context = vm.createContext({ 'foo': 'bar', 'thing': 'lala' }); assert.strictEqual('bar', context.foo); assert.strictEqual('lala', context.thing); -console.error('test updating context'); +// Test updating context result = vm.runInContext('var foo = 3;', context); assert.strictEqual(3, context.foo); assert.strictEqual('lala', context.thing); // https://github.com/nodejs/node/issues/5768 -console.error('run in contextified sandbox without referencing the context'); -const sandbox = {x: 1}; +// Run in contextified sandbox without referencing the context +const sandbox = { x: 1 }; vm.createContext(sandbox); global.gc(); vm.runInContext('x = 2', sandbox); diff --git a/test/parallel/test-vm-function-declaration.js b/test/parallel/test-vm-function-declaration.js index ff594644c68de0..bb7ebe2aa6d1f6 100644 --- a/test/parallel/test-vm-function-declaration.js +++ b/test/parallel/test-vm-function-declaration.js @@ -21,5 +21,3 @@ assert.strictEqual(res.name, 'b', 'res should be named b'); assert.strictEqual(typeof o.a, 'function', 'a should be function'); assert.strictEqual(typeof o.b, 'function', 'b should be function'); assert.strictEqual(res, o.b, 'result should be global b function'); - -console.log('ok'); diff --git a/test/parallel/test-vm-new-script-new-context.js b/test/parallel/test-vm-new-script-new-context.js index 94d884c4d34df9..0280c24e5b8aec 100644 --- a/test/parallel/test-vm-new-script-new-context.js +++ b/test/parallel/test-vm-new-script-new-context.js @@ -15,14 +15,14 @@ const Script = require('vm').Script; { const script = new Script('throw new Error(\'test\');'); - assert.throws(function() { + assert.throws(() => { script.runInNewContext(); }, /^Error: test$/); } { const script = new Script('foo.bar = 5;'); - assert.throws(function() { + assert.throws(() => { script.runInNewContext(); }, /^ReferenceError: foo is not defined$/); } @@ -73,14 +73,14 @@ const Script = require('vm').Script; script.runInNewContext({ f: f }); assert.strictEqual(f.a, 2); - assert.throws(function() { + assert.throws(() => { script.runInNewContext(); }, /^ReferenceError: f is not defined$/); } { const script = new Script(''); - assert.throws(function() { + assert.throws(() => { script.runInNewContext.call('\'hello\';'); }, /^TypeError: this\.runInContext is not a function$/); } diff --git a/test/parallel/test-vm-new-script-this-context.js b/test/parallel/test-vm-new-script-this-context.js index 62aecfed28af4f..4dcfdda5f1d13a 100644 --- a/test/parallel/test-vm-new-script-this-context.js +++ b/test/parallel/test-vm-new-script-this-context.js @@ -5,14 +5,14 @@ const Script = require('vm').Script; common.globalCheck = false; -console.error('run a string'); +// Run a string let script = new Script('\'passed\';'); const result = script.runInThisContext(script); assert.strictEqual('passed', result); -console.error('thrown error'); +// Thrown error script = new Script('throw new Error(\'test\');'); -assert.throws(function() { +assert.throws(() => { script.runInThisContext(script); }, /^Error: test$/); @@ -22,7 +22,7 @@ script.runInThisContext(script); assert.strictEqual(2, global.hello); -console.error('pass values'); +// Pass values global.code = 'foo = 1;' + 'bar = 2;' + 'if (typeof baz !== "undefined") throw new Error("test fail");'; @@ -34,7 +34,7 @@ assert.strictEqual(0, global.obj.foo); assert.strictEqual(2, global.bar); assert.strictEqual(1, global.foo); -console.error('call a function'); +// Call a function global.f = function() { global.foo = 100; }; script = new Script('f()'); script.runInThisContext(script); diff --git a/test/parallel/test-vm-run-in-new-context.js b/test/parallel/test-vm-run-in-new-context.js index 3f8c632859db0f..95184f1e629f12 100644 --- a/test/parallel/test-vm-run-in-new-context.js +++ b/test/parallel/test-vm-run-in-new-context.js @@ -10,12 +10,12 @@ assert.strictEqual(typeof global.gc, 'function', common.globalCheck = false; -console.error('run a string'); +// Run a string const result = vm.runInNewContext('\'passed\';'); assert.strictEqual('passed', result); -console.error('thrown error'); -assert.throws(function() { +// Thrown error +assert.throws(() => { vm.runInNewContext('throw new Error(\'test\');'); }, /^Error: test$/); @@ -24,7 +24,7 @@ vm.runInNewContext('hello = 2'); assert.strictEqual(5, global.hello); -console.error('pass values in and out'); +// Pass values in and out global.code = 'foo = 1;' + 'bar = 2;' + 'if (baz !== 3) throw new Error(\'test fail\');'; @@ -37,17 +37,17 @@ assert.strictEqual(1, global.obj.foo); assert.strictEqual(2, global.obj.bar); assert.strictEqual(2, global.foo); -console.error('call a function by reference'); +// Call a function by reference function changeFoo() { global.foo = 100; } vm.runInNewContext('f()', { f: changeFoo }); assert.strictEqual(global.foo, 100); -console.error('modify an object by reference'); +// Modify an object by reference const f = { a: 1 }; vm.runInNewContext('f.a = 2', { f: f }); assert.strictEqual(f.a, 2); -console.error('use function in context without referencing context'); +// Use function in context without referencing context const fn = vm.runInNewContext('(function() { obj.p = {}; })', { obj: {} }); global.gc(); fn(); diff --git a/test/parallel/test-vm-syntax-error-message.js b/test/parallel/test-vm-syntax-error-message.js index c0a00d06aa54f8..5a16239f5653e9 100644 --- a/test/parallel/test-vm-syntax-error-message.js +++ b/test/parallel/test-vm-syntax-error-message.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const child_process = require('child_process'); @@ -11,16 +11,12 @@ const p = child_process.spawn(process.execPath, [ 'catch (e) { console.log(e.message); }' ]); -p.stderr.on('data', function(data) { - assert(false, 'Unexpected stderr data: ' + data); -}); +p.stderr.on('data', common.mustNotCall()); let output = ''; -p.stdout.on('data', function(data) { - output += data; -}); +p.stdout.on('data', (data) => output += data); -process.on('exit', function() { +p.stdout.on('end', common.mustCall(() => { assert.strictEqual(output.replace(/[\r\n]+/g, ''), 'boo'); -}); +})); diff --git a/test/parallel/test-vm-syntax-error-stderr.js b/test/parallel/test-vm-syntax-error-stderr.js index 9cba2178e3a0a3..e40edc907c6639 100644 --- a/test/parallel/test-vm-syntax-error-stderr.js +++ b/test/parallel/test-vm-syntax-error-stderr.js @@ -12,18 +12,14 @@ const p = child_process.spawn(process.execPath, [ wrong_script ]); -p.stdout.on('data', function(data) { - common.fail(`Unexpected stdout data: ${data}`); -}); +p.stdout.on('data', common.mustNotCall()); let output = ''; -p.stderr.on('data', function(data) { - output += data; -}); +p.stderr.on('data', (data) => output += data); -process.on('exit', function() { +p.stderr.on('end', common.mustCall(() => { assert(/BEGIN CERT/.test(output)); assert(/^\s+\^/m.test(output)); assert(/Invalid left-hand side expression in prefix operation/.test(output)); -}); +})); diff --git a/test/parallel/test-zlib-failed-init.js b/test/parallel/test-zlib-failed-init.js index afc2c82ddfca8e..0ca70ad92d50b9 100644 --- a/test/parallel/test-zlib-failed-init.js +++ b/test/parallel/test-zlib-failed-init.js @@ -1,10 +1,15 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); +if (process.config.variables.node_shared_zlib && + /^1\.2\.[0-8]$/.test(process.versions.zlib)) { + common.skip("older versions of shared zlib don't throw on create"); +} + // For raw deflate encoding, requests for 256-byte windows are rejected as // invalid by zlib. // (http://zlib.net/manual.html#Advanced) diff --git a/test/parallel/test-zlib-from-gzip.js b/test/parallel/test-zlib-from-gzip.js index 7bd377eb8698fd..bca810e1a75d5f 100644 --- a/test/parallel/test-zlib-from-gzip.js +++ b/test/parallel/test-zlib-from-gzip.js @@ -21,10 +21,10 @@ const inp = fs.createReadStream(fixture); const out = fs.createWriteStream(outputFile); inp.pipe(gunzip).pipe(out); -out.on('close', function() { +out.on('close', common.mustCall(() => { const actual = fs.readFileSync(outputFile); assert.strictEqual(actual.length, expect.length, 'length should match'); for (let i = 0, l = actual.length; i < l; i++) { assert.strictEqual(actual[i], expect[i], `byte[${i}]`); } -}); +})); diff --git a/test/parallel/test-zlib-from-string.js b/test/parallel/test-zlib-from-string.js index ab2f7d023d8bc8..cf24d2a804cc73 100644 --- a/test/parallel/test-zlib-from-string.js +++ b/test/parallel/test-zlib-from-string.js @@ -1,7 +1,7 @@ 'use strict'; // test compressing and uncompressing a string with zlib -require('../common'); +const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); @@ -33,32 +33,32 @@ const expectedBase64Gzip = 'H4sIAAAAAAAAA11RS05DMQy8yhzg6d2BPSAkJPZu4laWkjiN4' + 'mHo33kJO8xfkckmLjE5XMKBQ4gxIsfvCZ44doUThF2mcZq8q2' + 'sHnHNzRtagj5AQAA'; -zlib.deflate(inputString, function(err, buffer) { +zlib.deflate(inputString, common.mustCall((err, buffer) => { assert.strictEqual(buffer.toString('base64'), expectedBase64Deflate, 'deflate encoded string should match'); -}); +})); -zlib.gzip(inputString, function(err, buffer) { +zlib.gzip(inputString, common.mustCall((err, buffer) => { // Can't actually guarantee that we'll get exactly the same // deflated bytes when we compress a string, since the header // depends on stuff other than the input string itself. // However, decrypting it should definitely yield the same // result that we're expecting, and this should match what we get // from inflating the known valid deflate data. - zlib.gunzip(buffer, function(err, gunzipped) { + zlib.gunzip(buffer, common.mustCall((err, gunzipped) => { assert.strictEqual(gunzipped.toString(), inputString, 'Should get original string after gzip/gunzip'); - }); -}); + })); +})); let buffer = Buffer.from(expectedBase64Deflate, 'base64'); -zlib.unzip(buffer, function(err, buffer) { +zlib.unzip(buffer, common.mustCall((err, buffer) => { assert.strictEqual(buffer.toString(), inputString, 'decoded inflated string should match'); -}); +})); buffer = Buffer.from(expectedBase64Gzip, 'base64'); -zlib.unzip(buffer, function(err, buffer) { +zlib.unzip(buffer, common.mustCall((err, buffer) => { assert.strictEqual(buffer.toString(), inputString, 'decoded gunzipped string should match'); -}); +})); diff --git a/test/parallel/test-zlib-invalid-input.js b/test/parallel/test-zlib-invalid-input.js index 6e87ab8b4f8227..d1d157678bba25 100644 --- a/test/parallel/test-zlib-invalid-input.js +++ b/test/parallel/test-zlib-invalid-input.js @@ -1,14 +1,26 @@ 'use strict'; // test uncompressing invalid input -require('../common'); +const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); -const nonStringInputs = [1, true, {a: 1}, ['a']]; +const nonStringInputs = [ + 1, + true, + { a: 1 }, + ['a'] +]; -console.error('Doing the non-strings'); -nonStringInputs.forEach(function(input) { +// zlib.Unzip classes need to get valid data, or else they'll throw. +const unzips = [ + zlib.Unzip(), + zlib.Gunzip(), + zlib.Inflate(), + zlib.InflateRaw() +]; + +nonStringInputs.forEach(common.mustCall((input) => { // zlib.gunzip should not throw an error when called with bad input. assert.doesNotThrow(function() { zlib.gunzip(input, function(err, buffer) { @@ -16,30 +28,12 @@ nonStringInputs.forEach(function(input) { assert.ok(err); }); }); -}); +}, nonStringInputs.length)); -console.error('Doing the unzips'); -// zlib.Unzip classes need to get valid data, or else they'll throw. -const unzips = [ zlib.Unzip(), - zlib.Gunzip(), - zlib.Inflate(), - zlib.InflateRaw() ]; -const hadError = []; -unzips.forEach(function(uz, i) { - console.error(`Error for ${uz.constructor.name}`); - uz.on('error', function(er) { - console.error('Error event', er); - hadError[i] = true; - }); - - uz.on('end', function(er) { - throw new Error(`end event should not be emitted ${uz.constructor.name}`); - }); +unzips.forEach(common.mustCall((uz, i) => { + uz.on('error', common.mustCall()); + uz.on('end', common.mustNotCall); // this will trigger error event uz.write('this is not valid compressed data.'); -}); - -process.on('exit', function() { - assert.deepStrictEqual(hadError, [true, true, true, true], 'expect 4 errors'); -}); +}, unzips.length)); diff --git a/test/parallel/test-zlib-random-byte-pipes.js b/test/parallel/test-zlib-random-byte-pipes.js index 143ab526f70a49..5ec5908777c814 100644 --- a/test/parallel/test-zlib-random-byte-pipes.js +++ b/test/parallel/test-zlib-random-byte-pipes.js @@ -6,124 +6,119 @@ if (!common.hasCrypto) const assert = require('assert'); const crypto = require('crypto'); const stream = require('stream'); -const util = require('util'); const zlib = require('zlib'); const Stream = stream.Stream; // emit random bytes, and keep a shasum -function RandomReadStream(opt) { - Stream.call(this); +class RandomReadStream extends Stream { + constructor(opt) { + super(); - this.readable = true; - this._paused = false; - this._processing = false; - - this._hasher = crypto.createHash('sha1'); - opt = opt || {}; - - // base block size. - opt.block = opt.block || 256 * 1024; + this.readable = true; + this._paused = false; + this._processing = false; - // total number of bytes to emit - opt.total = opt.total || 256 * 1024 * 1024; - this._remaining = opt.total; + this._hasher = crypto.createHash('sha1'); + opt = opt || {}; - // how variable to make the block sizes - opt.jitter = opt.jitter || 1024; + // base block size. + opt.block = opt.block || 256 * 1024; - this._opt = opt; + // total number of bytes to emit + opt.total = opt.total || 256 * 1024 * 1024; + this._remaining = opt.total; - this._process = this._process.bind(this); + // how variable to make the block sizes + opt.jitter = opt.jitter || 1024; - process.nextTick(this._process); -} + this._opt = opt; -util.inherits(RandomReadStream, Stream); + this._process = this._process.bind(this); -RandomReadStream.prototype.pause = function() { - this._paused = true; - this.emit('pause'); -}; + process.nextTick(this._process); + } -RandomReadStream.prototype.resume = function() { - // console.error("rrs resume"); - this._paused = false; - this.emit('resume'); - this._process(); -}; + pause() { + this._paused = true; + this.emit('pause'); + } -RandomReadStream.prototype._process = function() { - if (this._processing) return; - if (this._paused) return; + resume() { + // console.error("rrs resume"); + this._paused = false; + this.emit('resume'); + this._process(); + } - this._processing = true; + _process() { + if (this._processing) return; + if (this._paused) return; - if (!this._remaining) { - this._hash = this._hasher.digest('hex').toLowerCase().trim(); - this._processing = false; + this._processing = true; - this.emit('end'); - return; - } + if (!this._remaining) { + this._hash = this._hasher.digest('hex').toLowerCase().trim(); + this._processing = false; - // figure out how many bytes to output - // if finished, then just emit end. - let block = this._opt.block; - const jitter = this._opt.jitter; - if (jitter) { - block += Math.ceil(Math.random() * jitter - (jitter / 2)); - } - block = Math.min(block, this._remaining); - const buf = Buffer.allocUnsafe(block); - for (let i = 0; i < block; i++) { - buf[i] = Math.random() * 256; - } + this.emit('end'); + return; + } - this._hasher.update(buf); + // figure out how many bytes to output + // if finished, then just emit end. + let block = this._opt.block; + const jitter = this._opt.jitter; + if (jitter) { + block += Math.ceil(Math.random() * jitter - (jitter / 2)); + } + block = Math.min(block, this._remaining); + const buf = Buffer.allocUnsafe(block); + for (let i = 0; i < block; i++) { + buf[i] = Math.random() * 256; + } - this._remaining -= block; + this._hasher.update(buf); - console.error('block=%d\nremain=%d\n', block, this._remaining); - this._processing = false; + this._remaining -= block; - this.emit('data', buf); - process.nextTick(this._process); -}; + this._processing = false; + this.emit('data', buf); + process.nextTick(this._process); + } +} // a filter that just verifies a shasum -function HashStream() { - Stream.call(this); +class HashStream extends Stream { + constructor() { + super(); + this.readable = this.writable = true; + this._hasher = crypto.createHash('sha1'); + } - this.readable = this.writable = true; - this._hasher = crypto.createHash('sha1'); -} + write(c) { + // Simulate the way that an fs.ReadStream returns false + // on *every* write, only to resume a moment later. + this._hasher.update(c); + process.nextTick(() => this.resume()); + return false; + } + + resume() { + this.emit('resume'); + process.nextTick(() => this.emit('drain')); + } -util.inherits(HashStream, Stream); - -HashStream.prototype.write = function(c) { - // Simulate the way that an fs.ReadStream returns false - // on *every* write like a jerk, only to resume a - // moment later. - this._hasher.update(c); - process.nextTick(this.resume.bind(this)); - return false; -}; - -HashStream.prototype.resume = function() { - this.emit('resume'); - process.nextTick(this.emit.bind(this, 'drain')); -}; - -HashStream.prototype.end = function(c) { - if (c) { - this.write(c); + end(c) { + if (c) { + this.write(c); + } + this._hash = this._hasher.digest('hex').toLowerCase().trim(); + this.emit('data', this._hash); + this.emit('end'); } - this._hash = this._hasher.digest('hex').toLowerCase().trim(); - this.emit('data', this._hash); - this.emit('end'); -}; +} const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 }); @@ -133,23 +128,6 @@ const gunz = zlib.createGunzip(); inp.pipe(gzip).pipe(gunz).pipe(out); -inp.on('data', function(c) { - console.error('inp data', c.length); -}); - -gzip.on('data', function(c) { - console.error('gzip data', c.length); -}); - -gunz.on('data', function(c) { - console.error('gunz data', c.length); -}); - -out.on('data', function(c) { - console.error('out data', c.length); -}); - -out.on('data', common.mustCall(function(c) { - console.error('hash=%s', c); +out.on('data', common.mustCall((c) => { assert.strictEqual(c, inp._hash, 'hashes should match'); })); diff --git a/test/parallel/test-zlib-sync-no-event.js b/test/parallel/test-zlib-sync-no-event.js index 33c0018b6f9108..9defd3d31f4fb0 100644 --- a/test/parallel/test-zlib-sync-no-event.js +++ b/test/parallel/test-zlib-sync-no-event.js @@ -1,20 +1,18 @@ 'use strict'; -require('../common'); +const common = require('../common'); const zlib = require('zlib'); const assert = require('assert'); -const shouldNotBeCalled = () => { throw new Error('unexpected event'); }; - const message = 'Come on, Fhqwhgads.'; +const buffer = Buffer.from(message); const zipper = new zlib.Gzip(); -zipper.on('close', shouldNotBeCalled); +zipper.on('close', common.mustNotCall); -const buffer = Buffer.from(message); const zipped = zipper._processChunk(buffer, zlib.Z_FINISH); const unzipper = new zlib.Gunzip(); -unzipper.on('close', shouldNotBeCalled); +unzipper.on('close', common.mustNotCall); const unzipped = unzipper._processChunk(zipped, zlib.Z_FINISH); assert.notStrictEqual(zipped.toString(), message); diff --git a/test/parallel/test-zlib-write-after-flush.js b/test/parallel/test-zlib-write-after-flush.js index caacc976e51a46..5ab601f7f1d46c 100644 --- a/test/parallel/test-zlib-write-after-flush.js +++ b/test/parallel/test-zlib-write-after-flush.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); @@ -11,23 +11,14 @@ gzip.pipe(gunz); let output = ''; const input = 'A line of data\n'; gunz.setEncoding('utf8'); -gunz.on('data', function(c) { - output += c; -}); - -process.on('exit', function() { +gunz.on('data', (c) => output += c); +gunz.on('end', common.mustCall(() => { assert.strictEqual(output, input); - - // Make sure that the flush flag was set back to normal assert.strictEqual(gzip._flushFlag, zlib.Z_NO_FLUSH); - - console.log('ok'); -}); +})); // make sure that flush/write doesn't trigger an assert failure -gzip.flush(); write(); -function write() { - gzip.write(input); - gzip.end(); - gunz.read(0); -} +gzip.flush(); +gzip.write(input); +gzip.end(); +gunz.read(0); diff --git a/test/parallel/test-zlib.js b/test/parallel/test-zlib.js index 468b5f346f04ee..dbd437e500b10f 100644 --- a/test/parallel/test-zlib.js +++ b/test/parallel/test-zlib.js @@ -4,7 +4,6 @@ const assert = require('assert'); const zlib = require('zlib'); const path = require('path'); const fs = require('fs'); -const util = require('util'); const stream = require('stream'); let zlibPairs = [ @@ -48,105 +47,104 @@ if (process.env.FAST) { } const tests = {}; -testFiles.forEach(function(file) { +testFiles.forEach(common.mustCall((file) => { tests[file] = fs.readFileSync(path.resolve(common.fixturesDir, file)); -}); +}, testFiles.length)); // stream that saves everything -function BufferStream() { - this.chunks = []; - this.length = 0; - this.writable = true; - this.readable = true; +class BufferStream extends stream.Stream { + constructor() { + super(); + this.chunks = []; + this.length = 0; + this.writable = true; + this.readable = true; + } + + write(c) { + this.chunks.push(c); + this.length += c.length; + return true; + } + + end(c) { + if (c) this.write(c); + // flatten + const buf = Buffer.allocUnsafe(this.length); + let i = 0; + this.chunks.forEach((c) => { + c.copy(buf, i); + i += c.length; + }); + this.emit('data', buf); + this.emit('end'); + return true; + } } -util.inherits(BufferStream, stream.Stream); - -BufferStream.prototype.write = function(c) { - this.chunks.push(c); - this.length += c.length; - return true; -}; - -BufferStream.prototype.end = function(c) { - if (c) this.write(c); - // flatten - const buf = Buffer.allocUnsafe(this.length); - let i = 0; - this.chunks.forEach(function(c) { - c.copy(buf, i); - i += c.length; - }); - this.emit('data', buf); - this.emit('end'); - return true; -}; - - -function SlowStream(trickle) { - this.trickle = trickle; - this.offset = 0; - this.readable = this.writable = true; +class SlowStream extends stream.Stream { + constructor(trickle) { + super(); + this.trickle = trickle; + this.offset = 0; + this.readable = this.writable = true; + } + + write() { + throw new Error('not implemented, just call ss.end(chunk)'); + } + + pause() { + this.paused = true; + this.emit('pause'); + } + + resume() { + const emit = () => { + if (this.paused) return; + if (this.offset >= this.length) { + this.ended = true; + return this.emit('end'); + } + const end = Math.min(this.offset + this.trickle, this.length); + const c = this.chunk.slice(this.offset, end); + this.offset += c.length; + this.emit('data', c); + process.nextTick(emit); + }; + + if (this.ended) return; + this.emit('resume'); + if (!this.chunk) return; + this.paused = false; + emit(); + } + + end(chunk) { + // walk over the chunk in blocks. + this.chunk = chunk; + this.length = chunk.length; + this.resume(); + return this.ended; + } } -util.inherits(SlowStream, stream.Stream); - -SlowStream.prototype.write = function() { - throw new Error('not implemented, just call ss.end(chunk)'); -}; - -SlowStream.prototype.pause = function() { - this.paused = true; - this.emit('pause'); -}; - -SlowStream.prototype.resume = function() { - const emit = () => { - if (this.paused) return; - if (this.offset >= this.length) { - this.ended = true; - return this.emit('end'); - } - const end = Math.min(this.offset + this.trickle, this.length); - const c = this.chunk.slice(this.offset, end); - this.offset += c.length; - this.emit('data', c); - process.nextTick(emit); - }; - - if (this.ended) return; - this.emit('resume'); - if (!this.chunk) return; - this.paused = false; - emit(); -}; - -SlowStream.prototype.end = function(chunk) { - // walk over the chunk in blocks. - this.chunk = chunk; - this.length = chunk.length; - this.resume(); - return this.ended; -}; - // for each of the files, make sure that compressing and // decompressing results in the same data, for every combination // of the options set above. -let failures = 0; -let total = 0; -let done = 0; -Object.keys(tests).forEach(function(file) { +const testKeys = Object.keys(tests); +testKeys.forEach(common.mustCall((file) => { const test = tests[file]; - chunkSize.forEach(function(chunkSize) { - trickle.forEach(function(trickle) { - windowBits.forEach(function(windowBits) { - level.forEach(function(level) { - memLevel.forEach(function(memLevel) { - strategy.forEach(function(strategy) { - zlibPairs.forEach(function(pair) { + chunkSize.forEach(common.mustCall((chunkSize) => { + trickle.forEach(common.mustCall((trickle) => { + windowBits.forEach(common.mustCall((windowBits) => { + level.forEach(common.mustCall((level) => { + memLevel.forEach(common.mustCall((memLevel) => { + strategy.forEach(common.mustCall((strategy) => { + zlibPairs.forEach(common.mustCall((pair) => { const Def = pair[0]; const Inf = pair[1]; const opts = { level: level, @@ -154,57 +152,32 @@ Object.keys(tests).forEach(function(file) { memLevel: memLevel, strategy: strategy }; - total++; - const def = new Def(opts); const inf = new Inf(opts); const ss = new SlowStream(trickle); const buf = new BufferStream(); // verify that the same exact buffer comes out the other end. - buf.on('data', function(c) { + buf.on('data', common.mustCall((c) => { const msg = `${file} ${chunkSize} ${ JSON.stringify(opts)} ${Def.name} -> ${Inf.name}`; - let ok = true; - const testNum = ++done; let i; for (i = 0; i < Math.max(c.length, test.length); i++) { if (c[i] !== test[i]) { - ok = false; - failures++; + assert.fail(null, null, msg); break; } } - if (ok) { - console.log(`ok ${testNum} ${msg}`); - } else { - console.log(`not ok ${testNum} msg`); - console.log(' ...'); - console.log(` testfile: ${file}`); - console.log(` type: ${Def.name} -> ${Inf.name}`); - console.log(` position: ${i}`); - console.log(` options: ${JSON.stringify(opts)}`); - console.log(` expect: ${test[i]}`); - console.log(` actual: ${c[i]}`); - console.log(` chunkSize: ${chunkSize}`); - console.log(' ---'); - } - }); + })); // the magic happens here. ss.pipe(def).pipe(inf).pipe(buf); ss.end(test); - }); - }); - }); - }); - }); - }); - }); -}); - -process.on('exit', function(code) { - console.log(`1..${done}`); - assert.strictEqual(done, total, `${total - done} tests left unfinished`); - assert.strictEqual(failures, 0, 'some test failures'); -}); + }, zlibPairs.length)); + }, strategy.length)); + }, memLevel.length)); + }, level.length)); + }, windowBits.length)); + }, trickle.length)); + }, chunkSize.length)); +}, testKeys.length)); diff --git a/test/pummel/test-process-cpuUsage.js b/test/pummel/test-process-cpuUsage.js index 20b2fadef9fae0..1d5aa861b64ad8 100644 --- a/test/pummel/test-process-cpuUsage.js +++ b/test/pummel/test-process-cpuUsage.js @@ -17,14 +17,14 @@ while (Date.now() - now < RUN_FOR_MS); // Get a diff reading from when we started. const diff = process.cpuUsage(start); -const MICROSECONDS_PER_SECOND = 1000 * 1000; +const MICROSECONDS_PER_MILLISECOND = 1000; // Diff usages should be >= 0, <= ~RUN_FOR_MS millis. // Let's be generous with the slop factor, defined above, in case other things // are happening on this CPU. The <= check may be invalid if the node process // is making use of multiple CPUs, in which case, just remove it. assert(diff.user >= 0); -assert(diff.user <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_SECOND); +assert(diff.user <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_MILLISECOND); assert(diff.system >= 0); -assert(diff.system <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_SECOND); +assert(diff.system <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_MILLISECOND); diff --git a/test/pummel/test-vm-memleak.js b/test/pummel/test-vm-memleak.js index 8503e2389b44a7..8bcd08b48606af 100644 --- a/test/pummel/test-vm-memleak.js +++ b/test/pummel/test-vm-memleak.js @@ -3,6 +3,7 @@ require('../common'); const assert = require('assert'); +const vm = require('vm'); const start = Date.now(); let maxMem = 0; @@ -14,7 +15,7 @@ assert(ok, 'Run this test with --max_old_space_size=32.'); const interval = setInterval(function() { try { - require('vm').runInNewContext('throw 1;'); + vm.runInNewContext('throw 1;'); } catch (e) { } @@ -31,7 +32,7 @@ const interval = setInterval(function() { function testContextLeak() { for (let i = 0; i < 1000; i++) - require('vm').createContext({}); + vm.createContext({}); } process.on('exit', function() { diff --git a/test/sequential/test-child-process-execsync.js b/test/sequential/test-child-process-execsync.js index 61e3bf60f75b13..cccd3b7e77d6f3 100644 --- a/test/sequential/test-child-process-execsync.js +++ b/test/sequential/test-child-process-execsync.js @@ -2,8 +2,7 @@ const common = require('../common'); const assert = require('assert'); -const execSync = require('child_process').execSync; -const execFileSync = require('child_process').execFileSync; +const { execFileSync, execSync } = require('child_process'); const TIMER = 200; const SLEEP = 2000; diff --git a/test/sequential/test-module-loading.js b/test/sequential/test-module-loading.js index 8fd681cc651be8..73f40890a422f9 100644 --- a/test/sequential/test-module-loading.js +++ b/test/sequential/test-module-loading.js @@ -110,7 +110,7 @@ try { assert.strictEqual('blah', e.message); } -assert.strictEqual(require('path').dirname(__filename), __dirname); +assert.strictEqual(path.dirname(__filename), __dirname); console.error('load custom file types with extensions'); require.extensions['.test'] = function(module, filename) { diff --git a/test/sequential/test-net-GH-5504.js b/test/sequential/test-net-GH-5504.js index bd0943f9e01566..46448342a2f257 100644 --- a/test/sequential/test-net-GH-5504.js +++ b/test/sequential/test-net-GH-5504.js @@ -49,7 +49,7 @@ function parent() { const node = process.execPath; const s = spawn(node, [__filename, 'server'], { - env: Object.assign(process.env, { + env: Object.assign({}, process.env, { NODE_DEBUG: 'net' }) }); diff --git a/test/sequential/test-timers-blocking-callback.js b/test/sequential/test-timers-blocking-callback.js index 73b0f13997716d..d500b813af0026 100644 --- a/test/sequential/test-timers-blocking-callback.js +++ b/test/sequential/test-timers-blocking-callback.js @@ -1,8 +1,9 @@ 'use strict'; /* - * This is a regression test for https://github.com/joyent/node/issues/15447 - * and https://github.com/joyent/node/issues/9333. + * This is a regression test for + * https://github.com/nodejs/node-v0.x-archive/issues/15447 and + * and https://github.com/nodejs/node-v0.x-archive/issues/9333. * * When a timer is added in another timer's callback, its underlying timer * handle was started with a timeout that was actually incorrect. @@ -28,9 +29,15 @@ const Timer = process.binding('timer_wrap').Timer; const TIMEOUT = 100; -let nbBlockingCallbackCalls = 0; -let latestDelay = 0; -let timeCallbackScheduled = 0; +let nbBlockingCallbackCalls; +let latestDelay; +let timeCallbackScheduled; + +// These tests are timing dependent so they may fail even when the bug is +// not present (if the host is sufficiently busy that the timers are delayed +// significantly). However, they fail 100% of the time when the bug *is* +// present, so to increase reliability, allow for a small number of retries. +let retries = 2; function initTest() { nbBlockingCallbackCalls = 0; @@ -38,7 +45,7 @@ function initTest() { timeCallbackScheduled = 0; } -function blockingCallback(callback) { +function blockingCallback(retry, callback) { ++nbBlockingCallbackCalls; if (nbBlockingCallbackCalls > 1) { @@ -47,8 +54,15 @@ function blockingCallback(callback) { // to fire, they shouldn't generally be more than 100% late in this case. // But they are guaranteed to be at least 100ms late given the bug in // https://github.com/nodejs/node-v0.x-archive/issues/15447 and - // https://github.com/nodejs/node-v0.x-archive/issues/9333.. - assert(latestDelay < TIMEOUT * 2); + // https://github.com/nodejs/node-v0.x-archive/issues/9333. + if (latestDelay >= TIMEOUT * 2) { + if (retries > 0) { + retries--; + return retry(callback); + } + assert.fail(null, null, + `timeout delayed by more than 100% (${latestDelay}ms)`); + } if (callback) return callback(); } else { @@ -56,25 +70,45 @@ function blockingCallback(callback) { common.busyLoop(TIMEOUT); timeCallbackScheduled = Timer.now(); - setTimeout(blockingCallback.bind(null, callback), TIMEOUT); + setTimeout(blockingCallback.bind(null, retry, callback), TIMEOUT); } } -const testAddingTimerToEmptyTimersList = common.mustCall(function(callback) { +function testAddingTimerToEmptyTimersList(callback) { initTest(); // Call setTimeout just once to make sure the timers list is // empty when blockingCallback is called. - setTimeout(blockingCallback.bind(null, callback), TIMEOUT); -}); + setTimeout( + blockingCallback.bind(null, testAddingTimerToEmptyTimersList, callback), + TIMEOUT + ); +} + +function testAddingTimerToNonEmptyTimersList() { + // If both timers fail and attempt a retry, only actually do anything for one + // of them. + let retryOK = true; + const retry = () => { + if (retryOK) + testAddingTimerToNonEmptyTimersList(); + retryOK = false; + }; -const testAddingTimerToNonEmptyTimersList = common.mustCall(function() { initTest(); // Call setTimeout twice with the same timeout to make // sure the timers list is not empty when blockingCallback is called. - setTimeout(blockingCallback, TIMEOUT); - setTimeout(blockingCallback, TIMEOUT); -}); + setTimeout( + blockingCallback.bind(null, retry), + TIMEOUT + ); + setTimeout( + blockingCallback.bind(null, retry), + TIMEOUT + ); +} // Run the test for the empty timers list case, and then for the non-empty -// timers list one -testAddingTimerToEmptyTimersList(testAddingTimerToNonEmptyTimersList); +// timers list one. +testAddingTimerToEmptyTimersList( + common.mustCall(testAddingTimerToNonEmptyTimersList) +); diff --git a/test/sequential/test-util-debug.js b/test/sequential/test-util-debug.js index 96f754c71adab9..b74579097e36e1 100644 --- a/test/sequential/test-util-debug.js +++ b/test/sequential/test-util-debug.js @@ -26,7 +26,7 @@ function test(environ, shouldWrite) { const spawn = require('child_process').spawn; const child = spawn(process.execPath, [__filename, 'child'], { - env: Object.assign(process.env, { NODE_DEBUG: environ }) + env: Object.assign({}, process.env, { NODE_DEBUG: environ }) }); expectErr = expectErr.split('%PID%').join(child.pid); diff --git a/tools/cpplint.py b/tools/cpplint.py index b5a05f0af39ba7..305220060c5cdb 100644 --- a/tools/cpplint.py +++ b/tools/cpplint.py @@ -1074,7 +1074,8 @@ def RepositoryName(self): """ fullname = self.FullName() # XXX(bnoordhuis) Expects that cpplint.py lives in the tools/ directory. - toplevel = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + toplevel = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..')).replace('\\', '/') prefix = os.path.commonprefix([fullname, toplevel]) return fullname[len(prefix) + 1:] diff --git a/tools/doc/addon-verify.js b/tools/doc/addon-verify.js index f681b0a90eb2a6..14953be66a6ce3 100644 --- a/tools/doc/addon-verify.js +++ b/tools/doc/addon-verify.js @@ -11,29 +11,29 @@ const verifyDir = path.resolve(rootDir, 'test', 'addons'); const contents = fs.readFileSync(doc).toString(); const tokens = marked.lexer(contents); -let files = null; let id = 0; -// Just to make sure that all examples will be processed -tokens.push({ type: 'heading' }); - -for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; +let currentHeader; +const addons = {}; +tokens.forEach((token) => { if (token.type === 'heading' && token.text) { - const blockName = token.text; - if (files && Object.keys(files).length !== 0) { - verifyFiles(files, - blockName, - console.log.bind(null, 'wrote'), - function(err) { if (err) throw err; }); - } - files = {}; - } else if (token.type === 'code') { + currentHeader = token.text; + addons[currentHeader] = { + files: {} + }; + } + if (token.type === 'code') { var match = token.text.match(/^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/); - if (match === null) - continue; - files[match[1]] = token.text; + if (match !== null) { + addons[currentHeader].files[match[1]] = token.text; + } } +}); +for (var header in addons) { + verifyFiles(addons[header].files, + header, + console.log.bind(null, 'wrote'), + function(err) { if (err) throw err; }); } function once(fn) { diff --git a/tools/doc/html.js b/tools/doc/html.js index 7f22769e633dd3..c4ed0b0eda7bbe 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -10,6 +10,7 @@ const typeParser = require('./type-parser.js'); module.exports = toHTML; const STABILITY_TEXT_REG_EXP = /(.*:)\s*(\d)([\s\S]*)/; +const DOC_CREATED_REG_EXP = //; // customized heading without id attribute var renderer = new marked.Renderer(); @@ -31,6 +32,7 @@ var gtocPath = path.resolve(path.join( )); var gtocLoading = null; var gtocData = null; +var docCreated = null; /** * opts: input, filename, template, nodeVersion. @@ -39,6 +41,8 @@ function toHTML(opts, cb) { var template = opts.template; var nodeVersion = opts.nodeVersion || process.version; + docCreated = opts.input.match(DOC_CREATED_REG_EXP); + if (gtocData) { return onGtocLoaded(); } @@ -136,6 +140,8 @@ function render(opts, cb) { ); } + template = template.replace(/__ALTDOCS__/, altDocs(filename)); + // content has to be the last thing we do with // the lexed tokens, because it's destructive. const content = marked.parser(lexed); @@ -167,6 +173,56 @@ function replaceInText(text) { return linkJsTypeDocs(linkManPages(text)); } +function altDocs(filename) { + if (!docCreated) { + console.error(`Failed to add alternative version links to ${filename}`); + return ''; + } + + function lte(v) { + const ns = v.num.split('.'); + if (docCreated[1] > +ns[0]) + return false; + if (docCreated[1] < +ns[0]) + return true; + return docCreated[2] <= +ns[1]; + } + + const versions = [ + { num: '8.x' }, + { num: '7.x' }, + { num: '6.x', lts: true }, + { num: '5.x' }, + { num: '4.x', lts: true }, + { num: '0.12.x' }, + { num: '0.10.x' } + ]; + + const host = 'https://nodejs.org'; + const href = (v) => `${host}/docs/latest-v${v.num}/api/${filename}.html`; + + function li(v, i) { + let html = `
  • ${v.num}`; + + if (v.lts) + html += ' LTS'; + + return html + '
  • '; + } + + const lis = versions.filter(lte).map(li).join('\n'); + + if (!lis.length) + return ''; + + return ` +
  • + View another version +
      ${lis}
    +
  • + `; +} + // handle general body-text replacements // for example, link man page references to the actual page function parseText(lexed) { @@ -349,7 +405,7 @@ function parseAPIHeader(text) { text = text.replace( STABILITY_TEXT_REG_EXP, - `
    $1 $2$3
    ` + `` ); return text; } diff --git a/tools/eslint-rules/assert-throws-arguments.js b/tools/eslint-rules/assert-throws-arguments.js deleted file mode 100644 index 3b51188c0c89bc..00000000000000 --- a/tools/eslint-rules/assert-throws-arguments.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @fileoverview Check that assert.throws is never called with a string as - * second argument. - * @author Michaël Zasso - */ -'use strict'; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -function checkThrowsArguments(context, node) { - if (node.callee.type === 'MemberExpression' && - node.callee.object.name === 'assert' && - node.callee.property.name === 'throws') { - const args = node.arguments; - if (args.length > 3) { - context.report({ - message: 'Too many arguments', - node: node - }); - } else if (args.length > 1) { - const error = args[1]; - if (error.type === 'Literal' && typeof error.value === 'string' || - error.type === 'TemplateLiteral') { - context.report({ - message: 'Unexpected string as second argument', - node: error - }); - } - } else { - if (context.options[0].requireTwo) { - context.report({ - message: 'Expected at least two arguments', - node: node - }); - } - } - } -} - -module.exports = { - meta: { - schema: [ - { - type: 'object', - properties: { - requireTwo: { - type: 'boolean' - } - } - } - ] - }, - create: function(context) { - return { - CallExpression: (node) => checkThrowsArguments(context, node) - }; - } -}; diff --git a/tools/jslint.js b/tools/jslint.js index 245a5c570b7a90..a8f4d498ed5ab1 100644 --- a/tools/jslint.js +++ b/tools/jslint.js @@ -120,7 +120,7 @@ if (cluster.isMaster) { if (showProgress) { // Start the progress display update timer when the first worker is ready - cluster.once('online', function(worker) { + cluster.once('online', function() { startTime = process.hrtime(); setInterval(printProgress, 1000).unref(); printProgress(); diff --git a/tools/release.sh b/tools/release.sh index 988a2c19b6d39d..fcb5ef124261a1 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -13,7 +13,28 @@ webuser=dist promotablecmd=dist-promotable promotecmd=dist-promote signcmd=dist-sign - +customsshkey="" # let ssh and scp use default key +signversion="" + +while getopts ":i:s:" option; do + case "${option}" in + i) + customsshkey="-i ${OPTARG}" + ;; + s) + signversion="${OPTARG}" + ;; + \?) + echo "Invalid option -$OPTARG." + exit 1 + ;; + :) + echo "Option -$OPTARG takes a parameter." + exit 1 + ;; + esac +done +shift $((OPTIND-1)) ################################################################################ ## Select a GPG key to use @@ -81,7 +102,7 @@ function sign { exit 1 fi - shapath=$(ssh ${webuser}@${webhost} $signcmd nodejs $version) + shapath=$(ssh ${customsshkey} ${webuser}@${webhost} $signcmd nodejs $version) if ! [[ ${shapath} =~ ^/.+/SHASUMS256.txt$ ]]; then echo 'Error: No SHASUMS file returned by sign!' @@ -96,7 +117,7 @@ function sign { mkdir -p $tmpdir - scp ${webuser}@${webhost}:${shapath} ${tmpdir}/${shafile} + scp ${customsshkey} ${webuser}@${webhost}:${shapath} ${tmpdir}/${shafile} gpg --default-key $gpgkey --clearsign --digest-algo SHA256 ${tmpdir}/${shafile} gpg --default-key $gpgkey --detach-sign --digest-algo SHA256 ${tmpdir}/${shafile} @@ -119,7 +140,7 @@ function sign { fi if [ "X${yorn}" == "Xy" ]; then - scp ${tmpdir}/${shafile} ${tmpdir}/${shafile}.asc ${tmpdir}/${shafile}.sig ${webuser}@${webhost}:${shadir}/ + scp ${customsshkey} ${tmpdir}/${shafile} ${tmpdir}/${shafile}.asc ${tmpdir}/${shafile}.sig ${webuser}@${webhost}:${shadir}/ break fi done @@ -128,17 +149,11 @@ function sign { } -if [ "X${1}" == "X-s" ]; then - if [ "X${2}" == "X" ]; then - echo "Please supply a version string to sign" - exit 1 - fi - - sign $2 - exit 0 +if [ -n "${signversion}" ]; then + sign ${signversion} + exit 0 fi - # else: do a normal release & promote ################################################################################ @@ -146,7 +161,7 @@ fi echo -e "\n# Checking for releases ..." -promotable=$(ssh ${webuser}@${webhost} $promotablecmd nodejs) +promotable=$(ssh ${customsshkey} ${webuser}@${webhost} $promotablecmd nodejs) if [ "X${promotable}" == "X" ]; then echo "No releases to promote!" @@ -179,7 +194,7 @@ for version in $versions; do echo -e "\n# Promoting ${version}..." - ssh ${webuser}@${webhost} $promotecmd nodejs $version + ssh ${customsshkey} ${webuser}@${webhost} $promotecmd nodejs $version sign $version diff --git a/tools/update-eslint.sh b/tools/update-eslint.sh index 0c9d3758dca973..ec0e4858cfba25 100755 --- a/tools/update-eslint.sh +++ b/tools/update-eslint.sh @@ -11,6 +11,7 @@ cd "$( dirname "${BASH_SOURCE[0]}" )" rm -rf eslint mkdir eslint-tmp cd eslint-tmp +npm init --yes npm install --global-style --no-binlinks --production eslint@latest cd node_modules/eslint diff --git a/vcbuild.bat b/vcbuild.bat index 1b933b05686c1b..8fbb8d365f76e4 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -27,6 +27,7 @@ set msi= set upload= set licensertf= set jslint= +set cpplint= set buildnodeweak= set noetw= set noetw_msi_arg= @@ -57,7 +58,7 @@ if /i "%1"=="nosnapshot" set nosnapshot=1&goto arg-ok if /i "%1"=="noetw" set noetw=1&goto arg-ok if /i "%1"=="noperfctr" set noperfctr=1&goto arg-ok if /i "%1"=="licensertf" set licensertf=1&goto arg-ok -if /i "%1"=="test" set test_args=%test_args% doctool known_issues message parallel sequential addons -J&set jslint=1&set build_addons=1&goto arg-ok +if /i "%1"=="test" set test_args=%test_args% doctool known_issues message parallel sequential addons -J&set cpplint=1&set jslint=1&set build_addons=1&goto arg-ok if /i "%1"=="test-ci" set test_args=%test_args% %test_ci_args% -p tap --logfile test.tap doctool inspector known_issues message sequential parallel addons&set cctest_args=%cctest_args% --gtest_output=tap:cctest.tap&set build_addons=1&goto arg-ok if /i "%1"=="test-addons" set test_args=%test_args% addons&set build_addons=1&goto arg-ok if /i "%1"=="test-simple" set test_args=%test_args% sequential parallel -J&goto arg-ok @@ -67,10 +68,13 @@ if /i "%1"=="test-inspector" set test_args=%test_args% inspector&goto arg-ok if /i "%1"=="test-tick-processor" set test_args=%test_args% tick-processor&goto arg-ok if /i "%1"=="test-internet" set test_args=%test_args% internet&goto arg-ok if /i "%1"=="test-pummel" set test_args=%test_args% pummel&goto arg-ok -if /i "%1"=="test-all" set test_args=%test_args% sequential parallel message gc inspector internet pummel&set buildnodeweak=1&set jslint=1&goto arg-ok +if /i "%1"=="test-all" set test_args=%test_args% sequential parallel message gc inspector internet pummel&set buildnodeweak=1&set cpplint=1&set jslint=1&goto arg-ok if /i "%1"=="test-known-issues" set test_args=%test_args% known_issues&goto arg-ok if /i "%1"=="jslint" set jslint=1&goto arg-ok if /i "%1"=="jslint-ci" set jslint_ci=1&goto arg-ok +if /i "%1"=="cpplint" set cpplint=1&goto arg-ok +if /i "%1"=="lint" set cpplint=1&set jslint=1&goto arg-ok +if /i "%1"=="lint-ci" set cpplint=1&set jslint_ci=1&goto arg-ok if /i "%1"=="package" set package=1&goto arg-ok if /i "%1"=="msi" set msi=1&set licensertf=1&set download_arg="--download=all"&set i18n_arg=small-icu&goto arg-ok if /i "%1"=="build-release" set build_release=1&goto arg-ok @@ -323,25 +327,70 @@ for /d %%F in (test\addons\??_*) do ( "%node_exe%" tools\doc\addon-verify.js if %errorlevel% neq 0 exit /b %errorlevel% :: building addons -SetLocal EnableDelayedExpansion +setlocal EnableDelayedExpansion for /d %%F in (test\addons\*) do ( "%node_exe%" deps\npm\node_modules\node-gyp\bin\node-gyp rebuild ^ --directory="%%F" ^ --nodedir="%cd%" if !errorlevel! neq 0 exit /b !errorlevel! ) -EndLocal +endlocal goto run-tests :run-tests -if "%test_args%"=="" goto jslint +if "%test_args%"=="" goto cpplint if "%config%"=="Debug" set test_args=--mode=debug %test_args% if "%config%"=="Release" set test_args=--mode=release %test_args% echo running 'cctest %cctest_args%' "%config%\cctest" %cctest_args% call :run-python tools\test.py %test_args% +goto cpplint + +:cpplint +if not defined cpplint goto jslint +call :run-cpplint src\*.c src\*.cc src\*.h test\addons\*.cc test\addons\*.h test\cctest\*.cc test\cctest\*.h tools\icu\*.cc tools\icu\*.h +call :run-python tools/check-imports.py goto jslint +:run-cpplint +if "%*"=="" goto exit +echo running cpplint '%*' +set cppfilelist= +setlocal enabledelayedexpansion +for /f "tokens=*" %%G in ('dir /b /s /a %*') do ( + set relpath=%%G + set relpath=!relpath:*%~dp0=! + call :add-to-list !relpath! +) +( endlocal + set cppfilelist=%localcppfilelist% +) +call :run-python tools/cpplint.py %cppfilelist% +goto exit + +:add-to-list +echo %1 | findstr /c:"src\node_root_certs.h" +if %errorlevel% equ 0 goto exit + +echo %1 | findstr /c:"src\queue.h" +if %errorlevel% equ 0 goto exit + +echo %1 | findstr /c:"src\tree.h" +if %errorlevel% equ 0 goto exit + +@rem skip subfolders under /src +echo %1 | findstr /r /c:"src\\.*\\.*" +if %errorlevel% equ 0 goto exit + +echo %1 | findstr /r /c:"test\\addons\\[0-9].*_.*\.h" +if %errorlevel% equ 0 goto exit + +echo %1 | findstr /r /c:"test\\addons\\[0-9].*_.*\.cc" +if %errorlevel% equ 0 goto exit + +set "localcppfilelist=%localcppfilelist% %1" +goto exit + :jslint if defined jslint_ci goto jslint-ci if not defined jslint goto exit @@ -365,7 +414,7 @@ echo Failed to create vc project files. goto exit :help -echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-inspector/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [small-icu/full-icu/without-intl] [nobuild] [nosign] [x86/x64] [vc2015] [download-all] [enable-vtune] +echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-inspector/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [small-icu/full-icu/without-intl] [nobuild] [nosign] [x86/x64] [vc2015] [download-all] [enable-vtune] [lint/lint-ci] echo Examples: echo vcbuild.bat : builds release build echo vcbuild.bat debug : builds debug build