mirror of
https://github.com/oven-sh/bun
synced 2026-02-28 04:21:04 +01:00
Compare commits
1 Commits
jarred/mi-
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69557ddc5a |
33
.github/workflows/codex-test-sync.yml
vendored
33
.github/workflows/codex-test-sync.yml
vendored
@@ -5,15 +5,14 @@ on:
|
||||
types: [labeled, opened]
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.2.15"
|
||||
BUN_VERSION: "canary"
|
||||
|
||||
jobs:
|
||||
sync-node-tests:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'codex') ||
|
||||
(github.event.action == 'opened' && contains(github.event.pull_request.labels.*.name, 'codex')) ||
|
||||
contains(github.head_ref, 'codex')
|
||||
(github.event.action == 'opened' && contains(github.event.pull_request.labels.*.name, 'codex'))
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -29,27 +28,15 @@ jobs:
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v44
|
||||
with:
|
||||
files: |
|
||||
test/js/node/test/parallel/**/*.{js,mjs,ts}
|
||||
test/js/node/test/sequential/**/*.{js,mjs,ts}
|
||||
|
||||
- name: Sync tests
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
shell: bash
|
||||
- name: Get changed files and sync tests
|
||||
run: |
|
||||
echo "Changed test files:"
|
||||
echo "${{ steps.changed-files.outputs.all_changed_files }}"
|
||||
|
||||
# Process each changed test file
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
# Extract test name from file path
|
||||
test_name=$(basename "$file" | sed 's/\.[^.]*$//')
|
||||
echo "Syncing test: $test_name"
|
||||
bun node:test:cp "$test_name"
|
||||
# Get the list of changed files from the PR
|
||||
git diff --name-only origin/main...HEAD | while read -r file; do
|
||||
if [[ "$file" =~ ^test/js/node/test/(parallel|sequential)/(.+)\.js$ ]]; then
|
||||
test_name="${BASH_REMATCH[2]}"
|
||||
echo "Syncing test: $test_name"
|
||||
bun node:test:cp "$test_name"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Commit changes
|
||||
|
||||
17
.lldbinit
17
.lldbinit
@@ -1 +1,16 @@
|
||||
command source -C -s true -e true misctools/lldb/init.lldb
|
||||
# Tell LLDB what to do when the debugged process receives SIGPWR: pass it through to the process
|
||||
# (-p), but do not stop the process (-s) or notify the user (-n).
|
||||
#
|
||||
# JSC's garbage collector sends this signal (as configured by Bun WebKit in
|
||||
# Thread::initializePlatformThreading() in ThreadingPOSIX.cpp) to the JS thread to suspend or resume
|
||||
# it. So stopping the process would just create noise when debugging any long-running script.
|
||||
process handle -p true -s false -n false SIGPWR
|
||||
|
||||
command script import misctools/lldb/lldb_pretty_printers.py
|
||||
type category enable zig.lang
|
||||
type category enable zig.std
|
||||
|
||||
command script import misctools/lldb/lldb_webkit.py
|
||||
|
||||
command script delete btjs
|
||||
command alias btjs p {printf("gathering btjs trace...\n");printf("%s\n", (char*)dumpBtjsTrace())}
|
||||
@@ -1,19 +0,0 @@
|
||||
# This file is separate from .lldbinit because it has to be in the same directory as the Python
|
||||
# modules in order for the "attach" action to work.
|
||||
|
||||
# Tell LLDB what to do when the debugged process receives SIGPWR: pass it through to the process
|
||||
# (-p), but do not stop the process (-s) or notify the user (-n).
|
||||
#
|
||||
# JSC's garbage collector sends this signal (as configured by Bun WebKit in
|
||||
# Thread::initializePlatformThreading() in ThreadingPOSIX.cpp) to the JS thread to suspend or resume
|
||||
# it. So stopping the process would just create noise when debugging any long-running script.
|
||||
process handle -p true -s false -n false SIGPWR
|
||||
|
||||
command script import -c lldb_pretty_printers.py
|
||||
type category enable zig.lang
|
||||
type category enable zig.std
|
||||
|
||||
command script import -c lldb_webkit.py
|
||||
|
||||
command script delete btjs
|
||||
command alias btjs p {printf("gathering btjs trace...\n");printf("%s\n", (char*)dumpBtjsTrace())}
|
||||
178
packages/bun-types/bun.d.ts
vendored
178
packages/bun-types/bun.d.ts
vendored
@@ -5871,76 +5871,31 @@ declare module "bun" {
|
||||
index: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a TCP or TLS socket connection used for network communication.
|
||||
* This interface provides methods for reading, writing, managing the connection state,
|
||||
* and handling TLS-specific features if applicable.
|
||||
*
|
||||
* Sockets are created using `Bun.connect()` or accepted by a `Bun.listen()` server.
|
||||
*
|
||||
* @category HTTP & Networking
|
||||
*/
|
||||
interface Socket<Data = undefined> extends Disposable {
|
||||
/**
|
||||
* Writes `data` to the socket. This method is unbuffered and non-blocking. This uses the `sendto(2)` syscall internally.
|
||||
* Write `data` to the socket
|
||||
*
|
||||
* For optimal performance with multiple small writes, consider batching multiple
|
||||
* writes together into a single `socket.write()` call.
|
||||
* @param data The data to write to the socket
|
||||
* @param byteOffset The offset in the buffer to start writing from (defaults to 0)
|
||||
* @param byteLength The number of bytes to write (defaults to the length of the buffer)
|
||||
*
|
||||
* @param data The data to write. Can be a string (encoded as UTF-8), `ArrayBuffer`, `TypedArray`, or `DataView`.
|
||||
* @param byteOffset The offset in bytes within the buffer to start writing from. Defaults to 0. Ignored for strings.
|
||||
* @param byteLength The number of bytes to write from the buffer. Defaults to the remaining length of the buffer from the offset. Ignored for strings.
|
||||
* @returns The number of bytes written. Returns `-1` if the socket is closed or shutting down. Can return less than the input size if the socket's buffer is full (backpressure).
|
||||
* @example
|
||||
* ```ts
|
||||
* // Send a string
|
||||
* const bytesWritten = socket.write("Hello, world!\n");
|
||||
* When passed a string, `byteOffset` and `byteLength` refer to the UTF-8 offset, not the string character offset.
|
||||
*
|
||||
* // Send binary data
|
||||
* const buffer = new Uint8Array([0x01, 0x02, 0x03]);
|
||||
* socket.write(buffer);
|
||||
*
|
||||
* // Send part of a buffer
|
||||
* const largeBuffer = new Uint8Array(1024);
|
||||
* // ... fill largeBuffer ...
|
||||
* socket.write(largeBuffer, 100, 50); // Write 50 bytes starting from index 100
|
||||
* ```
|
||||
* This is unbuffered as of Bun v0.2.2. That means individual write() calls
|
||||
* will be slow. In the future, Bun will buffer writes and flush them at the
|
||||
* end of the tick, when the event loop is idle, or sooner if the buffer is full.
|
||||
*/
|
||||
write(data: string | BufferSource, byteOffset?: number, byteLength?: number): number;
|
||||
|
||||
/**
|
||||
* The user-defined data associated with this socket instance.
|
||||
* This can be set when the socket is created via `Bun.connect({ data: ... })`.
|
||||
* It can be read or updated at any time.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // In a socket handler
|
||||
* function open(socket: Socket<{ userId: string }>) {
|
||||
* console.log(`Socket opened for user: ${socket.data.userId}`);
|
||||
* socket.data.lastActivity = Date.now(); // Update data
|
||||
* }
|
||||
* ```
|
||||
* The data context for the socket.
|
||||
*/
|
||||
data: Data;
|
||||
|
||||
/**
|
||||
* Sends the final data chunk and initiates a graceful shutdown of the socket's write side.
|
||||
* After calling `end()`, no more data can be written using `write()` or `end()`.
|
||||
* The socket remains readable until the remote end also closes its write side or the connection is terminated.
|
||||
* This sends a TCP FIN packet after writing the data.
|
||||
* Like {@link Socket.write} except it includes a TCP FIN packet
|
||||
*
|
||||
* @param data Optional final data to write before closing. Same types as `write()`.
|
||||
* @param byteOffset Optional offset for buffer data.
|
||||
* @param byteLength Optional length for buffer data.
|
||||
* @returns The number of bytes written for the final chunk. Returns `-1` if the socket was already closed or shutting down.
|
||||
* @example
|
||||
* ```ts
|
||||
* // send some data and close the write side
|
||||
* socket.end("Goodbye!");
|
||||
* // or close write side without sending final data
|
||||
* socket.end();
|
||||
* ```
|
||||
* Use it to send your last message and close the connection.
|
||||
*/
|
||||
end(data?: string | BufferSource, byteOffset?: number, byteLength?: number): number;
|
||||
|
||||
@@ -5967,33 +5922,20 @@ declare module "bun" {
|
||||
timeout(seconds: number): void;
|
||||
|
||||
/**
|
||||
* Forcefully closes the socket connection immediately. This is an abrupt termination, unlike the graceful shutdown initiated by `end()`.
|
||||
* It uses `SO_LINGER` with `l_onoff=1` and `l_linger=0` before calling `close(2)`.
|
||||
* Consider using {@link close close()} or {@link end end()} for graceful shutdowns.
|
||||
* Forcefully close the socket. The other end may not receive all data, and
|
||||
* the socket will be closed immediately.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* socket.terminate();
|
||||
* ```
|
||||
* This passes `SO_LINGER` with `l_onoff` set to `1` and `l_linger` set to
|
||||
* `0` and then calls `close(2)`.
|
||||
*/
|
||||
terminate(): void;
|
||||
|
||||
/**
|
||||
* Shuts down the write-half or both halves of the connection.
|
||||
* This allows the socket to enter a half-closed state where it can still receive data
|
||||
* but can no longer send data (`halfClose = true`), or close both read and write
|
||||
* (`halfClose = false`, similar to `end()` but potentially more immediate depending on OS).
|
||||
* Calls `shutdown(2)` syscall internally.
|
||||
* Shutdown writes to a socket
|
||||
*
|
||||
* @param halfClose If `true`, only shuts down the write side (allows receiving). If `false` or omitted, shuts down both read and write. Defaults to `false`.
|
||||
* @example
|
||||
* ```ts
|
||||
* // Stop sending data, but allow receiving
|
||||
* socket.shutdown(true);
|
||||
* This makes the socket a half-closed socket. It can still receive data.
|
||||
*
|
||||
* // Shutdown both reading and writing
|
||||
* socket.shutdown();
|
||||
* ```
|
||||
* This calls [shutdown(2)](https://man7.org/linux/man-pages/man2/shutdown.2.html) internally
|
||||
*/
|
||||
shutdown(halfClose?: boolean): void;
|
||||
|
||||
@@ -6019,11 +5961,6 @@ declare module "bun" {
|
||||
|
||||
/**
|
||||
* Flush any buffered data to the socket
|
||||
* This attempts to send the data immediately, but success depends on the network conditions
|
||||
* and the receiving end.
|
||||
* It might be necessary after several `write` calls if immediate sending is critical,
|
||||
* though often the OS handles flushing efficiently. Note that `write` calls outside
|
||||
* `open`/`data`/`drain` might benefit from manual `cork`/`flush`.
|
||||
*/
|
||||
flush(): void;
|
||||
|
||||
@@ -6045,31 +5982,17 @@ declare module "bun" {
|
||||
|
||||
/**
|
||||
* Remote IP address connected to the socket
|
||||
* @example "192.168.1.100" | "2001:db8::1"
|
||||
*/
|
||||
readonly remoteAddress: string;
|
||||
|
||||
/**
|
||||
* Remote port connected to the socket
|
||||
* @example 8080
|
||||
*/
|
||||
readonly remotePort: number;
|
||||
|
||||
/**
|
||||
* IP protocol family used for the local endpoint of the socket
|
||||
* @example "IPv4" | "IPv6"
|
||||
*/
|
||||
readonly localFamily: "IPv4" | "IPv6";
|
||||
|
||||
/**
|
||||
* Local IP address connected to the socket
|
||||
* @example "192.168.1.100" | "2001:db8::1"
|
||||
*/
|
||||
readonly localAddress: string;
|
||||
|
||||
/**
|
||||
* local port connected to the socket
|
||||
* @example 8080
|
||||
*/
|
||||
readonly localPort: number;
|
||||
|
||||
@@ -6233,8 +6156,6 @@ declare module "bun" {
|
||||
/**
|
||||
* See `Session Resumption` for more information.
|
||||
* @return `true` if the session was reused, `false` otherwise.
|
||||
* **TLS Only:** Checks if the current TLS session was resumed from a previous session.
|
||||
* Returns `true` if the session was resumed, `false` otherwise.
|
||||
*/
|
||||
isSessionReused(): boolean;
|
||||
|
||||
@@ -6277,91 +6198,30 @@ declare module "bun" {
|
||||
setKeepAlive(enable?: boolean, initialDelay?: number): boolean;
|
||||
|
||||
/**
|
||||
* The total number of bytes successfully written to the socket since it was established.
|
||||
* This includes data currently buffered by the OS but not yet acknowledged by the remote peer.
|
||||
* The number of bytes written to the socket.
|
||||
*/
|
||||
readonly bytesWritten: number;
|
||||
|
||||
/**
|
||||
* Alias for `socket.end()`. Allows the socket to be used with `using` declarations
|
||||
* for automatic resource management.
|
||||
* @example
|
||||
* ```ts
|
||||
* async function processSocket() {
|
||||
* using socket = await Bun.connect({ ... });
|
||||
* socket.write("Data");
|
||||
* // socket.end() is called automatically when exiting the scope
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
[Symbol.dispose](): void;
|
||||
|
||||
resume(): void;
|
||||
|
||||
pause(): void;
|
||||
|
||||
/**
|
||||
* If this is a TLS Socket
|
||||
*/
|
||||
renegotiate(): void;
|
||||
|
||||
/**
|
||||
* Sets the verify mode of the socket.
|
||||
*
|
||||
* @param requestCert Whether to request a certificate.
|
||||
* @param rejectUnauthorized Whether to reject unauthorized certificates.
|
||||
*/
|
||||
setVerifyMode(requestCert: boolean, rejectUnauthorized: boolean): void;
|
||||
|
||||
getSession(): void;
|
||||
|
||||
/**
|
||||
* Sets the session of the socket.
|
||||
*
|
||||
* @param session The session to set.
|
||||
*/
|
||||
setSession(session: string | Buffer | BufferSource): void;
|
||||
|
||||
/**
|
||||
* Exports the keying material of the socket.
|
||||
*
|
||||
* @param length The length of the keying material to export.
|
||||
* @param label The label of the keying material to export.
|
||||
* @param context The context of the keying material to export.
|
||||
*/
|
||||
exportKeyingMaterial(length: number, label: string, context?: string | BufferSource): void;
|
||||
|
||||
/**
|
||||
* Upgrades the socket to a TLS socket.
|
||||
*
|
||||
* @param options The options for the upgrade.
|
||||
* @returns A tuple containing the raw socket and the TLS socket.
|
||||
* @see {@link TLSUpgradeOptions}
|
||||
*/
|
||||
upgradeTLS<Data>(options: TLSUpgradeOptions<Data>): [raw: Socket<Data>, tls: Socket<Data>];
|
||||
|
||||
/**
|
||||
* Closes the socket.
|
||||
*
|
||||
* This is a wrapper around `end()` and `shutdown()`.
|
||||
*
|
||||
* @see {@link end}
|
||||
* @see {@link shutdown}
|
||||
*/
|
||||
close(): void;
|
||||
|
||||
/**
|
||||
* Returns the servername of the socket.
|
||||
*
|
||||
* @see {@link setServername}
|
||||
*/
|
||||
getServername(): string;
|
||||
|
||||
/**
|
||||
* Sets the servername of the socket.
|
||||
*
|
||||
* @see {@link getServername}
|
||||
*/
|
||||
setServername(name: string): void;
|
||||
}
|
||||
|
||||
|
||||
20
packages/bun-types/test.d.ts
vendored
20
packages/bun-types/test.d.ts
vendored
@@ -88,19 +88,15 @@ declare module "bun:test" {
|
||||
*/
|
||||
export function setSystemTime(now?: Date | number): ThisType<void>;
|
||||
|
||||
interface Jest {
|
||||
restoreAllMocks(): void;
|
||||
clearAllMocks(): void;
|
||||
fn<T extends (...args: any[]) => any>(func?: T): Mock<T>;
|
||||
setSystemTime(now?: number | Date): void;
|
||||
setTimeout(milliseconds: number): void;
|
||||
}
|
||||
export const jest: Jest;
|
||||
export namespace jest {
|
||||
function restoreAllMocks(): void;
|
||||
function clearAllMocks(): void;
|
||||
function fn<T extends (...args: any[]) => any>(func?: T): Mock<T>;
|
||||
function setSystemTime(now?: number | Date): void;
|
||||
function setTimeout(milliseconds: number): void;
|
||||
function useFakeTimers(): void;
|
||||
function useRealTimers(): void;
|
||||
function spyOn<T extends object, K extends keyof T>(
|
||||
obj: T,
|
||||
methodOrPropertyValue: K,
|
||||
): Mock<Extract<T[K], (...args: any[]) => any>>;
|
||||
|
||||
/**
|
||||
* Constructs the type of a mock function, e.g. the return type of `jest.fn()`.
|
||||
*/
|
||||
|
||||
@@ -327,6 +327,7 @@ pub fn finalize(this: *SocketAddress) void {
|
||||
pub fn intoDTO(this: *SocketAddress, global: *JSC.JSGlobalObject) JSC.JSValue {
|
||||
var addr_str = this.address();
|
||||
defer this._presentation = .dead;
|
||||
defer this.* = undefined; // removed in release builds, so setting _presentation to dead is still needed.
|
||||
return JSSocketAddressDTO__create(global, addr_str.transferToJS(global), this.port(), this.family() == AF.INET6);
|
||||
}
|
||||
|
||||
@@ -336,15 +337,21 @@ pub fn intoDTO(this: *SocketAddress, global: *JSC.JSGlobalObject) JSC.JSValue {
|
||||
///
|
||||
/// - The address string is assumed to be ASCII and a valid IP address (either v4 or v6).
|
||||
/// - Port is a valid `in_port_t` (between 0 and 2^16) in host byte order.
|
||||
pub fn createDTO(globalObject: *JSC.JSGlobalObject, addr_: []const u8, port_: u16, is_ipv6: bool) JSC.JSValue {
|
||||
pub fn createDTO(globalObject: *JSC.JSGlobalObject, addr_: []const u8, port_: i32, is_ipv6: bool) JSC.JSValue {
|
||||
if (comptime bun.Environment.isDebug) {
|
||||
bun.assertWithLocation(port_ >= 0 and port_ <= std.math.maxInt(i32), @src());
|
||||
bun.assertWithLocation(addr_.len > 0, @src());
|
||||
}
|
||||
|
||||
return JSSocketAddressDTO__create(globalObject, bun.String.createUTF8ForJS(globalObject, addr_), port_, is_ipv6);
|
||||
return JSSocketAddressDTO__create(
|
||||
globalObject,
|
||||
bun.String.createUTF8ForJS(globalObject, addr_),
|
||||
port_,
|
||||
is_ipv6,
|
||||
);
|
||||
}
|
||||
|
||||
extern "c" fn JSSocketAddressDTO__create(globalObject: *JSC.JSGlobalObject, address_: JSC.JSValue, port_: u16, is_ipv6: bool) JSC.JSValue;
|
||||
extern "c" fn JSSocketAddressDTO__create(globalObject: *JSC.JSGlobalObject, address_: JSC.JSValue, port_: c_int, is_ipv6: bool) JSC.JSValue;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <JavaScriptCore/VM.h>
|
||||
#include <JavaScriptCore/Heap.h>
|
||||
#include <mimalloc.h>
|
||||
|
||||
// It would be nicer to construct a DropAllLocks in us_loop_run_bun_tick (the only function that
|
||||
// uses onBeforeWait and onAfterWait), but that code is in C. We use an optional as that lets us
|
||||
@@ -21,7 +20,6 @@ extern "C" void Bun__JSC_onBeforeWait(JSC::VM* vm)
|
||||
drop_all_locks.emplace(*vm);
|
||||
if (previouslyHadAccess) {
|
||||
vm->heap.releaseAccess();
|
||||
mi_collect(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1379,6 +1379,27 @@ static bool isJSValueEqualToASCIILiteral(JSC::JSGlobalObject* globalObject, JSC:
|
||||
return view == literal;
|
||||
}
|
||||
|
||||
static bool processNoWarnings(JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
if (Bun__Node__ProcessNoWarnings)
|
||||
return true;
|
||||
|
||||
static bool checked = false;
|
||||
static bool result = false;
|
||||
if (!checked) {
|
||||
checked = true;
|
||||
ZigString name = { reinterpret_cast<const unsigned char*>("NODE_NO_WARNINGS"), sizeof("NODE_NO_WARNINGS") - 1 };
|
||||
ZigString value = { nullptr, 0 };
|
||||
if (Bun__getEnvValue(globalObject, &name, &value)) {
|
||||
if (value.len == 1 && value.ptr[0] == '1') {
|
||||
result = true;
|
||||
Bun__Node__ProcessNoWarnings = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" void Bun__Process__emitWarning(Zig::GlobalObject* globalObject, EncodedJSValue warning, EncodedJSValue type, EncodedJSValue code, EncodedJSValue ctor)
|
||||
{
|
||||
// ignoring return value -- emitWarning only ever returns undefined or throws
|
||||
@@ -1397,6 +1418,10 @@ JSValue Process::emitWarningErrorInstance(JSC::JSGlobalObject* lexicalGlobalObje
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto* process = globalObject->processObject();
|
||||
|
||||
if (processNoWarnings(globalObject)) {
|
||||
return jsUndefined();
|
||||
}
|
||||
|
||||
auto warningName = errorInstance.get(lexicalGlobalObject, vm.propertyNames->name);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (isJSValueEqualToASCIILiteral(globalObject, warningName, "DeprecationWarning"_s)) {
|
||||
@@ -1426,6 +1451,10 @@ JSValue Process::emitWarning(JSC::JSGlobalObject* lexicalGlobalObject, JSValue w
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSValue detail = jsUndefined();
|
||||
|
||||
if (processNoWarnings(globalObject)) {
|
||||
return jsUndefined();
|
||||
}
|
||||
|
||||
if (Bun__Node__ProcessNoDeprecation && isJSValueEqualToASCIILiteral(globalObject, type, "DeprecationWarning"_s)) {
|
||||
return jsUndefined();
|
||||
}
|
||||
@@ -3309,6 +3338,17 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessNoDeprecation, (JSC::JSGlobalObject * globalO
|
||||
return true;
|
||||
}
|
||||
|
||||
JSC_DEFINE_CUSTOM_GETTER(processNoProcessWarnings, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName name))
|
||||
{
|
||||
return JSValue::encode(jsBoolean(Bun__Node__ProcessNoWarnings));
|
||||
}
|
||||
|
||||
JSC_DEFINE_CUSTOM_SETTER(setProcessNoProcessWarnings, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName))
|
||||
{
|
||||
Bun__Node__ProcessNoWarnings = JSC::JSValue::decode(encodedValue).toBoolean(globalObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSValue constructFeatures(VM& vm, JSObject* processObject)
|
||||
{
|
||||
// {
|
||||
@@ -3649,6 +3689,8 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu
|
||||
moduleLoadList Process_stubEmptyArray PropertyCallback
|
||||
nextTick constructProcessNextTickFn PropertyCallback
|
||||
noDeprecation processNoDeprecation CustomAccessor
|
||||
noProcessWarnings processNoProcessWarnings
|
||||
CustomAccessor
|
||||
openStdin Process_functionOpenStdin Function 0
|
||||
pid constructPid PropertyCallback
|
||||
platform constructPlatform PropertyCallback
|
||||
|
||||
@@ -67,8 +67,10 @@ Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
|
||||
} // namespace JSSocketAddress
|
||||
} // namespace Bun
|
||||
|
||||
extern "C" JSC::EncodedJSValue JSSocketAddressDTO__create(JSGlobalObject* globalObject, EncodedJSValue address, uint16_t port, bool isIPv6)
|
||||
extern "C" JSC::EncodedJSValue JSSocketAddressDTO__create(JSGlobalObject* globalObject, EncodedJSValue address, int32_t port, bool isIPv6)
|
||||
{
|
||||
ASSERT(port < std::numeric_limits<uint16_t>::max());
|
||||
|
||||
VM& vm = globalObject->vm();
|
||||
auto* global = jsCast<Zig::GlobalObject*>(globalObject);
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@ JSObject* create(Zig::GlobalObject* globalObject, JSString* value, int port, boo
|
||||
} // namespace JSSocketAddress
|
||||
} // namespace Bun
|
||||
|
||||
extern "C" JSC::EncodedJSValue JSSocketAddressDTO__create(JSGlobalObject* globalObject, EncodedJSValue address, uint16_t port, bool isIPv6);
|
||||
extern "C" JSC::EncodedJSValue JSSocketAddressDTO__create(JSGlobalObject* globalObject, EncodedJSValue address, int32_t port, bool isIPv6);
|
||||
|
||||
@@ -700,11 +700,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateObject, (JSC::JSGlobalObject * globa
|
||||
|
||||
auto value = callFrame->argument(0);
|
||||
|
||||
if (value.isNull() || JSC::isArray(globalObject, value) || value.isCallable()) {
|
||||
if (value.isNull() || JSC::isArray(globalObject, value)) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
|
||||
}
|
||||
|
||||
if (!value.isObject()) {
|
||||
if (!value.isObject() || value.asCell()->type() != FinalObjectType) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, callFrame->argument(1), "object"_s, value);
|
||||
}
|
||||
|
||||
@@ -713,11 +713,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateObject, (JSC::JSGlobalObject * globa
|
||||
|
||||
JSC::EncodedJSValue V::validateObject(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name)
|
||||
{
|
||||
if (value.isNull() || JSC::isArray(globalObject, value) || value.isCallable()) {
|
||||
if (value.isNull() || JSC::isArray(globalObject, value)) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
|
||||
}
|
||||
|
||||
if (!value.isObject()) {
|
||||
if (!value.isObject() || value.asCell()->type() != FinalObjectType) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "object"_s, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ DEFINE_VISIT_CHILDREN(NapiHandleScopeImpl);
|
||||
|
||||
void NapiHandleScopeImpl::append(JSC::JSValue val)
|
||||
{
|
||||
WTF::Locker locker { cellLock() };
|
||||
m_storage.append(Slot(vm(), this, val));
|
||||
}
|
||||
|
||||
@@ -76,7 +75,6 @@ bool NapiHandleScopeImpl::escape(JSC::JSValue val)
|
||||
|
||||
NapiHandleScopeImpl::Slot* NapiHandleScopeImpl::reserveSlot()
|
||||
{
|
||||
WTF::Locker locker { cellLock() };
|
||||
m_storage.append(Slot());
|
||||
return &m_storage.last();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ const OOM = bun.OOM;
|
||||
export var Bun__Node__ZeroFillBuffers = false;
|
||||
export var Bun__Node__ProcessNoDeprecation = false;
|
||||
export var Bun__Node__ProcessThrowDeprecation = false;
|
||||
export var Bun__Node__ProcessNoWarnings = false;
|
||||
|
||||
pub var Bun__Node__ProcessTitle: ?string = null;
|
||||
|
||||
|
||||
@@ -21,17 +21,6 @@ const WorkspaceFilter = PackageManager.WorkspaceFilter;
|
||||
const OOM = bun.OOM;
|
||||
|
||||
pub const OutdatedCommand = struct {
|
||||
fn resolveCatalogDependency(manager: *PackageManager, dep: Install.Dependency) ?Install.Dependency.Version {
|
||||
return if (dep.version.tag == .catalog) blk: {
|
||||
const catalog_dep = manager.lockfile.catalogs.get(
|
||||
manager.lockfile,
|
||||
dep.version.value.catalog,
|
||||
dep.name,
|
||||
) orelse return null;
|
||||
break :blk catalog_dep.version;
|
||||
} else dep.version;
|
||||
}
|
||||
|
||||
pub fn exec(ctx: Command.Context) !void {
|
||||
Output.prettyln("<r><b>bun outdated <r><d>v" ++ Global.package_json_version_with_sha ++ "<r>", .{});
|
||||
Output.flush();
|
||||
@@ -292,8 +281,7 @@ pub const OutdatedCommand = struct {
|
||||
const package_id = lockfile.buffers.resolutions.items[dep_id];
|
||||
if (package_id == invalid_package_id) continue;
|
||||
const dep = lockfile.buffers.dependencies.items[dep_id];
|
||||
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
|
||||
if (resolved_version.tag != .npm and resolved_version.tag != .dist_tag) continue;
|
||||
if (dep.version.tag != .npm and dep.version.tag != .dist_tag) continue;
|
||||
const resolution = pkg_resolutions[package_id];
|
||||
if (resolution.tag != .npm) continue;
|
||||
|
||||
@@ -332,10 +320,10 @@ pub const OutdatedCommand = struct {
|
||||
|
||||
const latest = manifest.findByDistTag("latest") orelse continue;
|
||||
|
||||
const update_version = if (resolved_version.tag == .npm)
|
||||
manifest.findBestVersion(resolved_version.value.npm.version, string_buf) orelse continue
|
||||
const update_version = if (dep.version.tag == .npm)
|
||||
manifest.findBestVersion(dep.version.value.npm.version, string_buf) orelse continue
|
||||
else
|
||||
manifest.findByDistTag(resolved_version.value.dist_tag.tag.slice(string_buf)) orelse continue;
|
||||
manifest.findByDistTag(dep.version.value.dist_tag.tag.slice(string_buf)) orelse continue;
|
||||
|
||||
if (resolution.value.npm.version.order(latest.version, string_buf, manifest.string_buf) != .lt) continue;
|
||||
|
||||
@@ -452,11 +440,10 @@ pub const OutdatedCommand = struct {
|
||||
) orelse continue;
|
||||
|
||||
const latest = manifest.findByDistTag("latest") orelse continue;
|
||||
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
|
||||
const update = if (resolved_version.tag == .npm)
|
||||
manifest.findBestVersion(resolved_version.value.npm.version, string_buf) orelse continue
|
||||
const update = if (dep.version.tag == .npm)
|
||||
manifest.findBestVersion(dep.version.value.npm.version, string_buf) orelse continue
|
||||
else
|
||||
manifest.findByDistTag(resolved_version.value.dist_tag.tag.slice(string_buf)) orelse continue;
|
||||
manifest.findByDistTag(dep.version.value.dist_tag.tag.slice(string_buf)) orelse continue;
|
||||
|
||||
table.printLineSeparator();
|
||||
|
||||
@@ -550,8 +537,7 @@ pub const OutdatedCommand = struct {
|
||||
const package_id = resolutions[dep_id];
|
||||
if (package_id == invalid_package_id) continue;
|
||||
const dep = dependencies[dep_id];
|
||||
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
|
||||
if (resolved_version.tag != .npm and resolved_version.tag != .dist_tag) continue;
|
||||
if (dep.version.tag != .npm and dep.version.tag != .dist_tag) continue;
|
||||
const resolution: Install.Resolution = pkg_resolutions[package_id];
|
||||
if (resolution.tag != .npm) continue;
|
||||
|
||||
|
||||
@@ -1498,12 +1498,10 @@ function nodeToBun(item: string, index: number): string | number | null | NodeJS
|
||||
}
|
||||
if (isNodeStreamReadable(item)) {
|
||||
if (Object.hasOwn(item, "fd") && typeof item.fd === "number") return item.fd;
|
||||
if (item._handle && typeof item._handle.fd === "number") return item._handle.fd;
|
||||
throw new Error(`TODO: stream.Readable stdio @ ${index}`);
|
||||
}
|
||||
if (isNodeStreamWritable(item)) {
|
||||
if (Object.hasOwn(item, "fd") && typeof item.fd === "number") return item.fd;
|
||||
if (item._handle && typeof item._handle.fd === "number") return item._handle.fd;
|
||||
throw new Error(`TODO: stream.Writable stdio @ ${index}`);
|
||||
}
|
||||
const result = nodeToBunLookup[item];
|
||||
|
||||
@@ -8444,46 +8444,6 @@ describe("outdated", () => {
|
||||
expect(out).not.toContain("@foo/bar");
|
||||
expect(out).toContain("@scope/pkg1");
|
||||
});
|
||||
|
||||
test("catalog dependencies", async () => {
|
||||
await Promise.all([
|
||||
write(
|
||||
packageJson,
|
||||
JSON.stringify({
|
||||
name: "catalog-outdated-test",
|
||||
workspaces: {
|
||||
packages: ["packages/*"],
|
||||
catalog: {
|
||||
"no-deps": "1.0.0",
|
||||
},
|
||||
catalogs: {
|
||||
dev: {
|
||||
"a-dep": "1.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
write(
|
||||
join(packageDir, "packages", "pkg1", "package.json"),
|
||||
JSON.stringify({
|
||||
name: "pkg1",
|
||||
dependencies: {
|
||||
"no-deps": "catalog:",
|
||||
},
|
||||
devDependencies: {
|
||||
"a-dep": "catalog:dev",
|
||||
},
|
||||
}),
|
||||
),
|
||||
]);
|
||||
|
||||
await runBunInstall(env, packageDir);
|
||||
|
||||
const out = await runBunOutdated(env, packageDir, "--filter", "*");
|
||||
expect(out).toContain("no-deps");
|
||||
expect(out).toContain("a-dep");
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: setup registry to run across multiple test files, then move this and a few other describe
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, jest, type Mock, spyOn, test } from "bun:test";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, type Mock, spyOn, test } from "bun:test";
|
||||
import { expectType } from "./utilities";
|
||||
|
||||
const hooks = [beforeAll, beforeEach, afterAll, afterEach];
|
||||
@@ -141,6 +141,3 @@ expectType<Mock<(name: string) => string>>(myNormalSpiedMethod);
|
||||
|
||||
const spy = spyOn(console, "log");
|
||||
expectType(spy.mock.calls).is<[message?: any, ...optionalParams: any[]][]>();
|
||||
|
||||
jest.spyOn(console, "log");
|
||||
jest.fn(() => 123 as const);
|
||||
|
||||
@@ -75,5 +75,5 @@ describe("Bun.spawn", () => {
|
||||
const pct = delta / memBefore.rss;
|
||||
console.log(`RSS delta: ${delta / MB}MB (${Math.round(100 * pct)}%)`);
|
||||
expect(pct).toBeLessThan(0.5);
|
||||
}, 30_000); // NOTE: this test doesn't actually take this long, but keeping the limit high will help avoid flakyness
|
||||
}, 10_000); // NOTE: this test doesn't actually take this long, but keeping the limit high will help avoid flakyness
|
||||
});
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { fork, spawn } = require('child_process');
|
||||
const net = require('net');
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
|
||||
// Run in a child process because the PIPE file descriptor stays open until
|
||||
// Node.js completes, blocking the tmpdir and preventing cleanup.
|
||||
|
||||
if (process.argv[2] !== 'child') {
|
||||
// Parent
|
||||
tmpdir.refresh();
|
||||
|
||||
// Run test
|
||||
const child = fork(__filename, ['child'], { stdio: 'inherit' });
|
||||
child.on('exit', common.mustCall(function(code) {
|
||||
assert.strictEqual(code, 0);
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Child
|
||||
const server = net.createServer((conn) => {
|
||||
spawn(process.execPath, ['-v'], {
|
||||
stdio: ['ignore', conn, 'ignore']
|
||||
}).on('close', common.mustCall(() => {
|
||||
conn.end();
|
||||
}));
|
||||
}).listen(common.PIPE, () => {
|
||||
const client = net.connect(common.PIPE, common.mustCall());
|
||||
client.once('data', () => {
|
||||
client.end(() => {
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
40
test/js/node/parallel/test-env-var-no-warnings.js
Normal file
40
test/js/node/parallel/test-env-var-no-warnings.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const cp = require('child_process');
|
||||
|
||||
if (process.argv[2] === 'child') {
|
||||
process.emitWarning('foo');
|
||||
} else {
|
||||
function test(newEnv) {
|
||||
const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" "${__filename}" child`;
|
||||
|
||||
cp.exec(cmd, { ...opts, env: { ...opts?.env, ...newEnv } }, common.mustCall((err, stdout, stderr) => {
|
||||
assert.strictEqual(err, null);
|
||||
assert.strictEqual(stdout, '');
|
||||
|
||||
if (newEnv.NODE_NO_WARNINGS === '1')
|
||||
assert.strictEqual(stderr, '');
|
||||
else
|
||||
assert.match(stderr.trim(), /Warning: foo\n/);
|
||||
}));
|
||||
}
|
||||
|
||||
test({});
|
||||
test(process.env);
|
||||
test({ NODE_NO_WARNINGS: undefined });
|
||||
test({ NODE_NO_WARNINGS: null });
|
||||
test({ NODE_NO_WARNINGS: 'foo' });
|
||||
test({ NODE_NO_WARNINGS: true });
|
||||
test({ NODE_NO_WARNINGS: false });
|
||||
test({ NODE_NO_WARNINGS: {} });
|
||||
test({ NODE_NO_WARNINGS: [] });
|
||||
test({ NODE_NO_WARNINGS: function() {} });
|
||||
test({ NODE_NO_WARNINGS: 0 });
|
||||
test({ NODE_NO_WARNINGS: -1 });
|
||||
test({ NODE_NO_WARNINGS: '0' });
|
||||
test({ NODE_NO_WARNINGS: '01' });
|
||||
test({ NODE_NO_WARNINGS: '2' });
|
||||
// Don't test the number 1 because it will come through as a string in the
|
||||
// child process environment.
|
||||
test({ NODE_NO_WARNINGS: '1' });
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const net = require('net');
|
||||
|
||||
// Test that the process does not crash.
|
||||
const socket = net.connect({
|
||||
port: 12345,
|
||||
host: 'localhost',
|
||||
// Make sure autoSelectFamily is true
|
||||
// so that lookupAndConnectMultiple is called.
|
||||
autoSelectFamily: true,
|
||||
});
|
||||
// DNS resolution fails or succeeds
|
||||
socket.on('lookup', common.mustCall(() => {
|
||||
socket.destroy();
|
||||
}));
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import assert from 'node:assert';
|
||||
import dgram from 'node:dgram';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
describe('dgram.Socket[Symbol.asyncDispose]()', () => {
|
||||
it('should close the socket', async () => {
|
||||
const server = dgram.createSocket({ type: 'udp4' });
|
||||
server.on('close', common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
|
||||
assert.throws(() => server.address(), { code: 'ERR_SOCKET_DGRAM_NOT_RUNNING' });
|
||||
});
|
||||
|
||||
it('should resolve even if the socket is already closed', async () => {
|
||||
const server = dgram.createSocket({ type: 'udp4' });
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall(), common.mustNotCall());
|
||||
});
|
||||
});
|
||||
@@ -1,79 +0,0 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import * as fixtures from '../common/fixtures.mjs';
|
||||
import fs from 'fs';
|
||||
import assert from 'assert';
|
||||
|
||||
// This test ensures that "position" argument is correctly validated
|
||||
|
||||
const filepath = fixtures.path('x.txt');
|
||||
|
||||
const buffer = Buffer.from('xyz\n');
|
||||
const offset = 0;
|
||||
const length = buffer.byteLength;
|
||||
|
||||
// allowedErrors is an array of acceptable internal errors
|
||||
// For example, on some platforms read syscall might return -EFBIG or -EOVERFLOW
|
||||
function testValid(position, allowedErrors = []) {
|
||||
let fdSync;
|
||||
try {
|
||||
fdSync = fs.openSync(filepath, 'r');
|
||||
fs.readSync(fdSync, buffer, offset, length, position);
|
||||
fs.readSync(fdSync, buffer, common.mustNotMutateObjectDeep({ offset, length, position }));
|
||||
} catch (err) {
|
||||
if (!allowedErrors.includes(err.code)) {
|
||||
assert.fail(err);
|
||||
}
|
||||
} finally {
|
||||
if (fdSync) fs.closeSync(fdSync);
|
||||
}
|
||||
}
|
||||
|
||||
function testInvalid(code, position) {
|
||||
let fdSync;
|
||||
try {
|
||||
fdSync = fs.openSync(filepath, 'r');
|
||||
assert.throws(
|
||||
() => fs.readSync(fdSync, buffer, offset, length, position),
|
||||
{ code }
|
||||
);
|
||||
assert.throws(
|
||||
() => fs.readSync(fdSync, buffer, common.mustNotMutateObjectDeep({ offset, length, position })),
|
||||
{ code }
|
||||
);
|
||||
} finally {
|
||||
if (fdSync) fs.closeSync(fdSync);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
testValid(undefined);
|
||||
testValid(null);
|
||||
testValid(-1);
|
||||
testValid(-1n);
|
||||
|
||||
testValid(0);
|
||||
testValid(0n);
|
||||
testValid(1);
|
||||
testValid(1n);
|
||||
testValid(9);
|
||||
testValid(9n);
|
||||
testValid(Number.MAX_SAFE_INTEGER, [ 'EFBIG', 'EOVERFLOW' ]);
|
||||
|
||||
testValid(2n ** 63n - 1n - BigInt(length), [ 'EFBIG', 'EOVERFLOW' ]);
|
||||
testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n);
|
||||
testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n - BigInt(length));
|
||||
|
||||
testInvalid('ERR_OUT_OF_RANGE', NaN);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -Infinity);
|
||||
testInvalid('ERR_OUT_OF_RANGE', Infinity);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -0.999);
|
||||
testInvalid('ERR_OUT_OF_RANGE', -(2n ** 64n));
|
||||
testInvalid('ERR_OUT_OF_RANGE', Number.MAX_SAFE_INTEGER + 1);
|
||||
testInvalid('ERR_OUT_OF_RANGE', Number.MAX_VALUE);
|
||||
|
||||
for (const badTypeValue of [
|
||||
false, true, '1', Symbol(1), {}, [], () => {}, Promise.resolve(1),
|
||||
]) {
|
||||
testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import * as common from '../common/index.mjs';
|
||||
import assert from 'node:assert';
|
||||
import net from 'node:net';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
describe('net.Server[Symbol.asyncDispose]()', () => {
|
||||
it('should close the server', async () => {
|
||||
const server = net.createServer();
|
||||
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
|
||||
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
assert.strictEqual(server.address(), null);
|
||||
clearTimeout(timeoutRef);
|
||||
}));
|
||||
|
||||
server.on('close', common.mustCall());
|
||||
});
|
||||
|
||||
it('should resolve even if the server is already closed', async () => {
|
||||
const server = net.createServer();
|
||||
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
|
||||
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall());
|
||||
await server[Symbol.asyncDispose]().then(common.mustCall(), common.mustNotCall());
|
||||
clearTimeout(timeoutRef);
|
||||
}));
|
||||
});
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const http = require('http');
|
||||
const stream = require('stream');
|
||||
|
||||
// Verify that when piping a stream to an `OutgoingMessage` (or a type that
|
||||
// inherits from `OutgoingMessage`), if data is emitted after the
|
||||
// `OutgoingMessage` was closed - a `write after end` error is raised
|
||||
|
||||
class MyStream extends stream {}
|
||||
|
||||
const server = http.createServer(common.mustCall(function(req, res) {
|
||||
const myStream = new MyStream();
|
||||
myStream.pipe(res);
|
||||
|
||||
process.nextTick(common.mustCall(() => {
|
||||
res.end();
|
||||
myStream.emit('data', 'some data');
|
||||
res.on('error', common.expectsError({
|
||||
code: 'ERR_STREAM_WRITE_AFTER_END',
|
||||
name: 'Error'
|
||||
}));
|
||||
|
||||
process.nextTick(common.mustCall(() => server.close()));
|
||||
}));
|
||||
}));
|
||||
|
||||
server.listen(0);
|
||||
|
||||
server.on('listening', common.mustCall(function() {
|
||||
http.request({
|
||||
port: server.address().port,
|
||||
method: 'GET',
|
||||
path: '/'
|
||||
}).end();
|
||||
}));
|
||||
@@ -1,81 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
const { suite, test } = require('node:test');
|
||||
const testName = path.join(__dirname, 'test-http-max-http-headers.js');
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting failure');
|
||||
|
||||
// Validate that the test fails if the max header size is too small.
|
||||
const args = ['--expose-internals',
|
||||
'--max-http-header-size=1024',
|
||||
testName];
|
||||
const cp = spawn(process.execPath, args, { stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 1);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting success');
|
||||
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_DEBUG: 'http'
|
||||
});
|
||||
|
||||
// Validate that the test now passes if the same limit is large enough.
|
||||
const args = ['--expose-internals',
|
||||
'--max-http-header-size=1024',
|
||||
testName,
|
||||
'1024'];
|
||||
const cp = spawn(process.execPath, args, {
|
||||
env,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
const skip = process.config.variables.node_without_node_options;
|
||||
suite('same checks using NODE_OPTIONS if it is supported', { skip }, () => {
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_OPTIONS: '--max-http-header-size=1024'
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
console.log('running subtest expecting failure');
|
||||
|
||||
// Validate that the test fails if the max header size is too small.
|
||||
const args = ['--expose-internals', testName];
|
||||
const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 1);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
|
||||
test(function(_, cb) {
|
||||
// Validate that the test now passes if the same limit is large enough.
|
||||
const args = ['--expose-internals', testName, '1024'];
|
||||
const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
||||
|
||||
cp.on('close', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
cb();
|
||||
}));
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
// This tests checks that if server._handle.getsockname
|
||||
// returns an error number, an error is thrown.
|
||||
|
||||
const server = net.createServer({});
|
||||
server.listen(0, common.mustCall(function() {
|
||||
server._handle.getsockname = function(out) {
|
||||
return -1;
|
||||
};
|
||||
assert.throws(() => this.address(),
|
||||
/^Error: address [\w|\s-\d]+$/);
|
||||
server.close();
|
||||
}));
|
||||
@@ -1,62 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) { common.skip('missing crypto'); }
|
||||
|
||||
const { Readable } = require('stream');
|
||||
const process = require('process');
|
||||
const { randomBytes } = require('crypto');
|
||||
const assert = require('assert');
|
||||
|
||||
// Based on: https://github.com/nodejs/node/issues/46347#issuecomment-1413886707
|
||||
// edit: make it cross-platform as /dev/urandom is not available on Windows
|
||||
{
|
||||
let currentMemoryUsage = process.memoryUsage().arrayBuffers;
|
||||
|
||||
// We initialize a stream, but not start consuming it
|
||||
const randomNodeStream = new Readable({
|
||||
read(size) {
|
||||
randomBytes(size, (err, buffer) => {
|
||||
if (err) {
|
||||
// If an error occurs, emit an 'error' event
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Push the random bytes to the stream
|
||||
this.push(buffer);
|
||||
});
|
||||
}
|
||||
});
|
||||
// after 2 seconds, it'll get converted to web stream
|
||||
let randomWebStream;
|
||||
|
||||
// We check memory usage every second
|
||||
// since it's a stream, it shouldn't be higher than the chunk size
|
||||
const reportMemoryUsage = () => {
|
||||
const { arrayBuffers } = process.memoryUsage();
|
||||
currentMemoryUsage = arrayBuffers;
|
||||
|
||||
assert(currentMemoryUsage <= 256 * 1024 * 1024);
|
||||
};
|
||||
setInterval(reportMemoryUsage, 1000);
|
||||
|
||||
// after 1 second we use Readable.toWeb
|
||||
// memory usage should stay pretty much the same since it's still a stream
|
||||
setTimeout(() => {
|
||||
randomWebStream = Readable.toWeb(randomNodeStream);
|
||||
}, 1000);
|
||||
|
||||
// after 2 seconds we start consuming the stream
|
||||
// memory usage will grow, but the old chunks should be garbage-collected pretty quickly
|
||||
setTimeout(async () => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const _ of randomWebStream) {
|
||||
// Do nothing, just let the stream flow
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
// Test considered passed if we don't crash
|
||||
process.exit(0);
|
||||
}, 5000);
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const tls = require('tls');
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const { getEventListeners, once } = require('events');
|
||||
|
||||
const serverOptions = {
|
||||
key: fixtures.readKey('agent1-key.pem'),
|
||||
cert: fixtures.readKey('agent1-cert.pem')
|
||||
};
|
||||
const server = tls.createServer(serverOptions);
|
||||
server.listen(0, common.mustCall(async () => {
|
||||
const port = server.address().port;
|
||||
const host = 'localhost';
|
||||
const connectOptions = (signal) => ({
|
||||
port,
|
||||
host,
|
||||
signal,
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
|
||||
function assertAbort(socket, testName) {
|
||||
return assert.rejects(() => once(socket, 'close'), {
|
||||
name: 'AbortError',
|
||||
}, `close ${testName} should have thrown`);
|
||||
}
|
||||
|
||||
async function postAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
ac.abort();
|
||||
await assertAbort(socket, 'postAbort');
|
||||
}
|
||||
|
||||
async function preAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
ac.abort();
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
|
||||
await assertAbort(socket, 'preAbort');
|
||||
}
|
||||
|
||||
async function tickAbort() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = tls.connect(connectOptions(signal));
|
||||
setImmediate(() => ac.abort());
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
await assertAbort(socket, 'tickAbort');
|
||||
}
|
||||
|
||||
async function testConstructor() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
ac.abort();
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
|
||||
await assertAbort(socket, 'testConstructor');
|
||||
}
|
||||
|
||||
async function testConstructorPost() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
ac.abort();
|
||||
await assertAbort(socket, 'testConstructorPost');
|
||||
}
|
||||
|
||||
async function testConstructorPostTick() {
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const socket = new tls.TLSSocket(undefined, connectOptions(signal));
|
||||
setImmediate(() => ac.abort());
|
||||
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
|
||||
await assertAbort(socket, 'testConstructorPostTick');
|
||||
}
|
||||
|
||||
await postAbort();
|
||||
await preAbort();
|
||||
await tickAbort();
|
||||
await testConstructor();
|
||||
await testConstructorPost();
|
||||
await testConstructorPostTick();
|
||||
|
||||
server.close(common.mustCall());
|
||||
}));
|
||||
@@ -1,49 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
if (!common.hasIPv6)
|
||||
common.skip('no IPv6 support');
|
||||
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tls = require('tls');
|
||||
const dns = require('dns');
|
||||
|
||||
function runTest() {
|
||||
tls.createServer({
|
||||
cert: fixtures.readKey('agent1-cert.pem'),
|
||||
key: fixtures.readKey('agent1-key.pem'),
|
||||
}).on('connection', common.mustCall(function() {
|
||||
this.close();
|
||||
})).listen(0, '::1', common.mustCall(function() {
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: this.address().port,
|
||||
family: 6,
|
||||
rejectUnauthorized: false,
|
||||
};
|
||||
// Will fail with ECONNREFUSED if the address family is not honored.
|
||||
tls.connect(options).once('secureConnect', common.mustCall(function() {
|
||||
assert.strictEqual(this.remoteAddress, '::1');
|
||||
this.destroy();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
dns.lookup('localhost', {
|
||||
family: 6, all: true
|
||||
}, common.mustCall((err, addresses) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOTFOUND' || err.code === 'EAI_AGAIN')
|
||||
common.skip('localhost does not resolve to ::1');
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (addresses.some((val) => val.address === '::1'))
|
||||
runTest();
|
||||
else
|
||||
common.skip('localhost does not resolve to ::1');
|
||||
}));
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const tls = require('tls');
|
||||
const net = require('net');
|
||||
|
||||
const options = {
|
||||
key: fixtures.readKey('agent2-key.pem'),
|
||||
cert: fixtures.readKey('agent2-cert.pem')
|
||||
};
|
||||
|
||||
const server = tls.createServer(options, common.mustNotCall());
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const c = net.createConnection(this.address().port);
|
||||
|
||||
c.on('data', function() {
|
||||
// We must consume all data sent by the server. Otherwise the
|
||||
// end event will not be sent and the test will hang.
|
||||
// For example, when compiled with OpenSSL32 we see the
|
||||
// following response '15 03 03 00 02 02 16' which
|
||||
// decodes as a fatal (0x02) TLS error alert number 22 (0x16),
|
||||
// which corresponds to TLS1_AD_RECORD_OVERFLOW which matches
|
||||
// the error we see if NODE_DEBUG is turned on.
|
||||
// Some earlier OpenSSL versions did not seem to send a response
|
||||
// but the TLS spec seems to indicate there should be one
|
||||
// https://datatracker.ietf.org/doc/html/rfc8446#page-85
|
||||
// and error handling seems to have been re-written/improved
|
||||
// in OpenSSL32. Consuming the data allows the test to pass
|
||||
// either way.
|
||||
});
|
||||
|
||||
c.on('connect', common.mustCall(function() {
|
||||
c.write('blah\nblah\nblah\n');
|
||||
}));
|
||||
|
||||
c.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
|
||||
function loadPEM(n) {
|
||||
return fixtures.readKey(`${n}.pem`);
|
||||
}
|
||||
|
||||
const serverOptions = {
|
||||
key: loadPEM('agent2-key'),
|
||||
cert: loadPEM('agent2-cert')
|
||||
};
|
||||
|
||||
const SNIContexts = {
|
||||
'a.example.com': {
|
||||
key: loadPEM('agent1-key'),
|
||||
cert: loadPEM('agent1-cert')
|
||||
},
|
||||
'asterisk.test.com': {
|
||||
key: loadPEM('agent3-key'),
|
||||
cert: loadPEM('agent3-cert')
|
||||
},
|
||||
'chain.example.com': {
|
||||
key: loadPEM('agent6-key'),
|
||||
// NOTE: Contains ca3 chain cert
|
||||
cert: loadPEM('agent6-cert')
|
||||
}
|
||||
};
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'a.example.com'
|
||||
},
|
||||
true,
|
||||
'a.example.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca2-cert')],
|
||||
servername: 'b.test.com',
|
||||
},
|
||||
true,
|
||||
'b.test.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca2-cert')],
|
||||
servername: 'a.b.test.com',
|
||||
},
|
||||
false,
|
||||
'a.b.test.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'c.wrong.com',
|
||||
},
|
||||
false,
|
||||
'c.wrong.com'
|
||||
);
|
||||
|
||||
test(
|
||||
{
|
||||
ca: [loadPEM('ca1-cert')],
|
||||
servername: 'chain.example.com',
|
||||
},
|
||||
true,
|
||||
'chain.example.com'
|
||||
);
|
||||
|
||||
function test(options, clientResult, serverResult) {
|
||||
const server = tls.createServer(serverOptions, (c) => {
|
||||
assert.strictEqual(c.servername, serverResult);
|
||||
assert.strictEqual(c.authorized, false);
|
||||
});
|
||||
|
||||
server.addContext('a.example.com', SNIContexts['a.example.com']);
|
||||
server.addContext('*.test.com', SNIContexts['asterisk.test.com']);
|
||||
server.addContext('chain.example.com', SNIContexts['chain.example.com']);
|
||||
|
||||
server.on('tlsClientError', common.mustNotCall());
|
||||
|
||||
server.listen(0, () => {
|
||||
const client = tls.connect({
|
||||
...options,
|
||||
port: server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, () => {
|
||||
const result = client.authorizationError &&
|
||||
(client.authorizationError === 'ERR_TLS_CERT_ALTNAME_INVALID');
|
||||
assert.strictEqual(result, clientResult);
|
||||
client.end();
|
||||
});
|
||||
|
||||
client.on('close', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// This test ensures that CryptoKey instances can be correctly
|
||||
// sent to a Worker via postMessage.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const { subtle } = globalThis.crypto;
|
||||
const { once } = require('events');
|
||||
|
||||
const {
|
||||
Worker,
|
||||
parentPort,
|
||||
} = require('worker_threads');
|
||||
|
||||
const keyData =
|
||||
Buffer.from(
|
||||
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex');
|
||||
|
||||
const sig = '13691a79fb55a0417e4d6699a32f91ad29283fa2c1439865cc0632931f4f48dc';
|
||||
|
||||
async function doSig(key) {
|
||||
const signature = await subtle.sign({
|
||||
name: 'HMAC'
|
||||
}, key, Buffer.from('some data'));
|
||||
assert.strictEqual(Buffer.from(signature).toString('hex'), sig);
|
||||
}
|
||||
|
||||
if (process.env.HAS_STARTED_WORKER) {
|
||||
return parentPort.once('message', (key) => {
|
||||
assert.strictEqual(key.algorithm.name, 'HMAC');
|
||||
doSig(key).then(common.mustCall());
|
||||
});
|
||||
}
|
||||
|
||||
// Don't use isMainThread to allow running this test inside a worker.
|
||||
process.env.HAS_STARTED_WORKER = 1;
|
||||
|
||||
(async function() {
|
||||
const worker = new Worker(__filename);
|
||||
|
||||
await once(worker, 'online');
|
||||
|
||||
const key = await subtle.importKey(
|
||||
'raw',
|
||||
keyData,
|
||||
{ name: 'HMAC', hash: 'SHA-256' },
|
||||
true, ['sign', 'verify']);
|
||||
|
||||
worker.postMessage(key);
|
||||
|
||||
await doSig(key);
|
||||
})().then(common.mustCall());
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (common.isWindows)
|
||||
common.skip('no RLIMIT_NOFILE on Windows');
|
||||
|
||||
const assert = require('assert');
|
||||
const child_process = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
const ulimit = Number(child_process.execSync('ulimit -Hn'));
|
||||
if (ulimit > 64 || Number.isNaN(ulimit)) {
|
||||
const [cmd, opts] = common.escapePOSIXShell`ulimit -n 64 && "${process.execPath}" "${__filename}"`;
|
||||
// Sorry about this nonsense. It can be replaced if
|
||||
// https://github.com/nodejs/node-v0.x-archive/pull/2143#issuecomment-2847886
|
||||
// ever happens.
|
||||
const result = child_process.spawnSync(
|
||||
'/bin/sh',
|
||||
['-c', cmd],
|
||||
opts,
|
||||
);
|
||||
assert.strictEqual(result.stdout.toString(), '');
|
||||
assert.strictEqual(result.stderr.toString(), '');
|
||||
assert.strictEqual(result.status, 0);
|
||||
assert.strictEqual(result.error, undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const openFds = [];
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
openFds.push(fs.openSync(__filename, 'r'));
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.code, 'EMFILE');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should emit an error, not throw.
|
||||
const proc = child_process.spawn(process.execPath, ['-e', '0']);
|
||||
|
||||
// Verify that stdio is not setup on EMFILE or ENFILE.
|
||||
assert.strictEqual(proc.stdin, undefined);
|
||||
assert.strictEqual(proc.stdout, undefined);
|
||||
assert.strictEqual(proc.stderr, undefined);
|
||||
assert.strictEqual(proc.stdio, undefined);
|
||||
|
||||
proc.on('error', common.mustCall(function(err) {
|
||||
assert.strictEqual(err.code, 'EMFILE');
|
||||
}));
|
||||
|
||||
proc.on('exit', common.mustNotCall('"exit" event should not be emitted'));
|
||||
|
||||
// Close one fd for LSan
|
||||
if (openFds.length >= 1) {
|
||||
fs.closeSync(openFds.pop());
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
|
||||
['foobar', 1, {}, []].forEach(function connectThrows(input) {
|
||||
const opts = {
|
||||
host: 'localhost',
|
||||
port: common.PORT,
|
||||
lookup: input
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
tls.connect(opts);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
});
|
||||
|
||||
connectDoesNotThrow(common.mustCall());
|
||||
|
||||
function connectDoesNotThrow(input) {
|
||||
const opts = {
|
||||
host: 'localhost',
|
||||
port: common.PORT,
|
||||
lookup: input
|
||||
};
|
||||
|
||||
tls.connect(opts);
|
||||
}
|
||||
@@ -24,19 +24,6 @@ describe("setTimeout", () => {
|
||||
expect(c.signal.aborted).toBe(true);
|
||||
expect(unhandledRejectionCaught).toBe(false);
|
||||
});
|
||||
|
||||
it("AbortController can be passed as the `options` argument", () => {
|
||||
expect(async () => await setTimeout(0, undefined, new AbortController())).not.toThrow();
|
||||
});
|
||||
|
||||
it("should reject promise when AbortController is aborted", async () => {
|
||||
const abortController = new AbortController();
|
||||
const promise = setTimeout(100, undefined, abortController);
|
||||
abortController.abort();
|
||||
|
||||
await expect(promise).rejects.toThrow(expect.objectContaining({ name: "AbortError" }));
|
||||
expect(abortController.signal.aborted).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setImmediate", () => {
|
||||
|
||||
Reference in New Issue
Block a user