-
Notifications
You must be signed in to change notification settings - Fork 636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(node): Enable native node tests #695
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
feee95d
Move tests folder to _module
Soremwar 4a21149
Fix format
Soremwar a5e1274
Add test setup
Soremwar c15be16
Working!
Soremwar 7734aa2
Replace temporal file with Deno.Buffer for decompressing
Soremwar bc6f872
Remove linting and formatting for the suite
Soremwar 3419e6f
Add runner
Soremwar 28b9a74
Enable std/node/assert
Soremwar cd0a986
Refactor tests suites generation
Soremwar efd24cb
Fix runner
Soremwar b8baf3a
Fmt & Lint
Soremwar 6444609
Enable test suite on CI
Soremwar 589984f
Improve docs
Soremwar 9f69ae5
Add test generation to CI
Soremwar 0f850a4
Rename test folder to "testadata"
Soremwar 68a2c79
Add .gitignore instructions for the test suites
Soremwar 5721ce7
Add docs
Soremwar 5484f9b
Add docs for modules
Soremwar 3fa5213
Add copyright to generated files
Soremwar 4525f75
Fix CI
Soremwar 656843f
It's alivegit add .git add .
Soremwar fe55858
Fail test suite on failed test
Soremwar 85c6c78
Cleanup comments
Soremwar c84b451
Define middle ground between not generated and not tested
Soremwar 49e54cc
Convert script test runner to Deno.test
Soremwar 50a74e0
Add docs
Soremwar 4d47be7
Commit tests to std
Soremwar ff88eec
Adress comments
Soremwar 6f140e3
Fix missing event export
Soremwar 7f68c18
Remove the setup script from executing automatically
Soremwar 32ac255
Use filename as test name
Soremwar 070bfc0
Rename testdata to tools
Soremwar 7962b80
Add comments about automatically generated files
Soremwar 7988ed5
Fmt
Soremwar c2a9cd3
Rename
Soremwar 13911e2
Accidentally changed process_exit fixture folder
Soremwar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
versions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { join } from "../../path/mod.ts"; | ||
|
||
/** | ||
* The test suite matches the folders inside the `test` folder inside the | ||
* node repo | ||
* | ||
* Each test suite contains a list of files (which can be paths | ||
* or a regex to match) that will be pulled from the node repo | ||
*/ | ||
type TestSuites = Record<string, string[]>; | ||
|
||
interface Config { | ||
nodeVersion: string; | ||
/** Ignored files won't regenerated by the update script */ | ||
ignore: TestSuites; | ||
/** | ||
* The files that will be run by the test suite | ||
* | ||
* The files to be generated with the update script must be listed here as well, | ||
* but they won't be regenerated if they are listed in the `ignore` configuration | ||
* */ | ||
tests: TestSuites; | ||
suitesFolder: string; | ||
versionsFolder: string; | ||
} | ||
|
||
export const config: Config = JSON.parse( | ||
await Deno.readTextFile(new URL("./config.json", import.meta.url)), | ||
); | ||
|
||
export const ignoreList = Object.entries(config.ignore).reduce( | ||
(total: RegExp[], [suite, paths]) => { | ||
paths.forEach((path) => total.push(new RegExp(join(suite, path)))); | ||
return total; | ||
}, | ||
[], | ||
); | ||
|
||
export const testList = Object.entries(config.tests).reduce( | ||
(total: RegExp[], [suite, paths]) => { | ||
paths.forEach((path) => total.push(new RegExp(join(suite, path)))); | ||
return total; | ||
}, | ||
[], | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"nodeVersion": "15.5.1", | ||
"ignore": { | ||
"common": [ | ||
"index.js" | ||
] | ||
}, | ||
"tests": { | ||
"parallel": [ | ||
"test-event-emitter-listener-count.js" | ||
] | ||
}, | ||
"suitesFolder": "suites", | ||
"versionsFolder": "versions" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { createRequire } from "../module.ts"; | ||
import { isAbsolute } from "../../path/mod.ts"; | ||
|
||
/** | ||
* This module is used as an entry point for each test file | ||
* | ||
* The idea is to emulate a CommonJS environment without having to modify | ||
* the test files in any way | ||
* | ||
* Running with all permissions and unstable is recommended | ||
* | ||
* Usage: `deno run -A --unstable require.ts my_commonjs_file.js` | ||
*/ | ||
|
||
const file = Deno.args[0]; | ||
if (!file) { | ||
throw new Error("No file provided"); | ||
} else if (!isAbsolute(file)) { | ||
throw new Error("Path for file must be absolute"); | ||
} | ||
|
||
const require = createRequire(file); | ||
require(file); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import { gunzip } from "https://deno.land/x/[email protected]/gzip/gzip.ts"; | ||
import { Untar } from "../../archive/tar.ts"; | ||
import { walk } from "../../fs/walk.ts"; | ||
import { basename, fromFileUrl, join, resolve } from "../../path/mod.ts"; | ||
import { ensureFile } from "../../fs/ensure_file.ts"; | ||
import { config, ignoreList } from "./common.ts"; | ||
|
||
/** | ||
* This script will download and extract the test files specified in the | ||
* configuration file | ||
* | ||
* It will delete any previous tests unless they are specified on the `ignore` | ||
* section of the configuration file | ||
* | ||
* Usage: `deno run --allow-read --allow-net --allow-write setup.ts` | ||
*/ | ||
|
||
const NODE_URL = "https://nodejs.org/dist/vNODE_VERSION"; | ||
const NODE_FILE = "node-vNODE_VERSION.tar.gz"; | ||
|
||
/** URL for the download */ | ||
const url = `${NODE_URL}/${NODE_FILE}`.replaceAll( | ||
"NODE_VERSION", | ||
config.nodeVersion, | ||
); | ||
/** Local url location */ | ||
const path = join( | ||
config.versionsFolder, | ||
NODE_FILE.replaceAll("NODE_VERSION", config.nodeVersion), | ||
); | ||
|
||
/** | ||
* This will overwrite the file if found | ||
* */ | ||
async function downloadFile(url: string, path: string) { | ||
console.log(`Downloading: ${url}...`); | ||
const fileContent = await fetch(url) | ||
.then((response) => { | ||
if (response.ok) { | ||
if (!response.body) { | ||
throw new Error( | ||
`The requested download url ${url} doesn't contain an archive to download`, | ||
); | ||
} | ||
return response.body.getIterator(); | ||
} else if (response.status === 404) { | ||
throw new Error( | ||
`The requested version ${config.nodeVersion} could not be found for download`, | ||
); | ||
} | ||
throw new Error(`Request failed with status ${response.status}`); | ||
}); | ||
|
||
const filePath = fromFileUrl(new URL(path, import.meta.url)); | ||
|
||
await ensureFile(filePath); | ||
const file = await Deno.open(filePath, { | ||
truncate: true, | ||
write: true, | ||
}); | ||
for await (const chunk of fileContent) { | ||
await Deno.write(file.rid, chunk); | ||
} | ||
file.close(); | ||
console.log(`Downloaded: ${url} into ${path}`); | ||
} | ||
|
||
async function clearTests() { | ||
console.log("Cleaning up previous tests"); | ||
|
||
const files = walk( | ||
(fromFileUrl(new URL(config.suitesFolder, import.meta.url))), | ||
{ | ||
includeDirs: false, | ||
skip: ignoreList, | ||
}, | ||
); | ||
|
||
for await (const file of files) { | ||
await Deno.remove(file.path); | ||
} | ||
} | ||
|
||
/** | ||
* This will iterate over the ignore and test lists defined in the | ||
* configuration file | ||
* | ||
* If it were to be found in the ignore list or not found in the test list, the | ||
* function will return undefined, meaning the file won't be regenerated | ||
*/ | ||
function getRequestedFileSuite(file: string): string | undefined { | ||
for (const regex of ignoreList) { | ||
if (regex.test(file)) { | ||
return; | ||
} | ||
} | ||
|
||
for (const suite in config.tests) { | ||
for (const regex of config.tests[suite]) { | ||
if (new RegExp(regex).test(file)) { | ||
return suite; | ||
} | ||
} | ||
} | ||
} | ||
|
||
async function decompressTests(filePath: string) { | ||
console.log(`Processing ${basename(filePath)}...`); | ||
const compressedFile = await Deno.open( | ||
new URL(filePath, import.meta.url), | ||
{ read: true }, | ||
); | ||
|
||
const buffer = new Deno.Buffer(gunzip(await Deno.readAll(compressedFile))); | ||
Deno.close(compressedFile.rid); | ||
|
||
const tar = new Untar(buffer); | ||
|
||
for await (const entry of tar) { | ||
if (entry.type !== "file") continue; | ||
const suite = getRequestedFileSuite(entry.fileName); | ||
if (!suite) continue; | ||
const path = resolve( | ||
fromFileUrl(new URL(config.suitesFolder, import.meta.url)), | ||
suite, | ||
basename(entry.fileName), | ||
); | ||
await ensureFile(path); | ||
const file = await Deno.open(path, { | ||
create: true, | ||
truncate: true, | ||
write: true, | ||
}); | ||
// This will allow CI to pass without checking linting and formatting | ||
// on the test suite files, removing the need to mantain that as well | ||
await Deno.writeAll( | ||
file, | ||
new TextEncoder().encode( | ||
"// deno-fmt-ignore-file\n// deno-lint-ignore-file\n" + | ||
"\n// Copyright Joyent and Node contributors. All rights reserved. MIT license.\n" + | ||
`// Taken from Node ${config.nodeVersion}\n` + | ||
'// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually\n\n', | ||
), | ||
); | ||
await Deno.copy(entry, file); | ||
Deno.close(file.rid); | ||
} | ||
} | ||
|
||
let shouldDownload = false; | ||
try { | ||
Deno.lstatSync(new URL(path, import.meta.url)).isFile; | ||
while (true) { | ||
const r = (prompt(`File "${path}" found, use file? Y/N:`) ?? "").trim() | ||
.toUpperCase(); | ||
if (r === "Y") { | ||
break; | ||
} else if (r === "N") { | ||
shouldDownload = true; | ||
break; | ||
} else { | ||
console.log(`Unexpected: "${r}"`); | ||
} | ||
} | ||
} catch (e) { | ||
if (!(e instanceof Deno.errors.NotFound)) { | ||
throw e; | ||
} | ||
shouldDownload = true; | ||
} | ||
|
||
if (shouldDownload) { | ||
console.log(`Downloading ${url} in path "${path}" ...`); | ||
await downloadFile(url, path); | ||
} | ||
|
||
await clearTests(); | ||
|
||
await decompressTests(path); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered including Node as a git submodule? Is it too big?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A git submodule could suffice, but it makes it harder to patch some files that are needed for this to work, namely
common/index.js
.That file is used in pretty much every single file, however it uses things like child_process that are not needed in most cases, so instead I just patch it and all the tests that are enabled continue to use it without any trouble
Not to mention this is more user friendly than submodules :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about mocking
common/index.js
by injecting a fake module intorequire.cache
, using a technique described here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be more complicated than the current solution though @kt3k