Compare commits

...

29 Commits

Author SHA1 Message Date
Meghan Denny
44069ef29f Merge branch 'main' into nektro-patch-63596 2024-12-03 16:44:44 -08:00
Meghan Denny
eed13c7823 Merge branch 'main' into nektro-patch-63596 2024-11-16 07:05:05 -08:00
Meghan Denny
f7652e6a3d Merge branch 'main' into nektro-patch-63596 2024-10-22 22:58:21 -07:00
Meghan Denny
5ea9de6214 Merge branch 'main' into nektro-patch-63596 2024-10-17 19:37:58 -07:00
Meghan Denny
234ba97830 uv_get_available_memory is a c decl 2024-10-17 19:23:09 -07:00
Meghan Denny
63780d5411 add availableMemory impl 2024-10-17 18:55:43 -07:00
Meghan Denny
fdcf59d5fb add constrainedMemory impl 2024-10-17 18:54:39 -07:00
Meghan Denny
0c59cb4566 fix child-process-stdio.test.js on windows 2024-10-17 15:09:31 -07:00
Meghan Denny
bc4a0e4d04 this test is supposed to be allowed to fail with either message 2024-10-17 13:34:42 -07:00
Meghan Denny
de82b4a34c rework id validation 2024-10-16 22:00:01 -07:00
Meghan Denny
c588751082 dont overflow array access 2024-10-16 21:59:44 -07:00
Meghan Denny
b4b82b8555 reorder test to separate cases 2024-10-16 21:59:29 -07:00
Meghan Denny
c69815ca66 add these exception checks just in case 2024-10-16 20:46:53 -07:00
Meghan Denny
77e8a35cad change these to 32 2024-10-16 20:46:40 -07:00
Meghan Denny
a985b076c5 another one without asterisks 2024-10-16 20:19:24 -07:00
Meghan Denny
d4828a1743 limit gid_t and uid_t parsing to 2**31-1 2024-10-16 20:17:33 -07:00
Meghan Denny
eb293d5a5a fix child-process-windows-hide.test.js running in ci 2024-10-16 16:55:08 -07:00
Meghan Denny
54e674404f fix regressions 2024-10-16 16:31:10 -07:00
Meghan Denny
842c713f81 fix process-setgroups.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
76147dad5a fix process-uid-gid.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
2d49f62034 fix process-release.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
15ddb36f50 fix process-really-exit.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
fbe9b9136b fix process-hrtime.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
358eb10f1d fix process-cpuusage.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
aa4244b4d2 fix process-constrained-memory.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
3271b2bb47 fix process-chdir.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
b6cd955f7e add definition for process.availableMemory() 2024-10-16 15:23:23 -07:00
Meghan Denny
c154559f24 fix child-process-stdio.test.js 2024-10-16 15:23:23 -07:00
Meghan Denny
f34bf7be42 add tests already passing 2024-10-16 15:23:23 -07:00
26 changed files with 1298 additions and 113 deletions

View File

@@ -31,6 +31,8 @@
#include <JavaScriptCore/LazyPropertyInlines.h>
#include <JavaScriptCore/VMTrapsInlines.h>
#include "wtf-bindings.h"
#include "NodeValidator.h"
#include <webcore/SerializedScriptValue.h>
#include "ProcessBindingTTYWrap.h"
#include "wtf/text/ASCIILiteral.h"
@@ -49,6 +51,9 @@
#include <netdb.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#else
#include <uv.h>
#include <io.h>
@@ -226,13 +231,10 @@ static JSValue constructProcessReleaseObject(VM& vm, JSObject* processObject)
auto* globalObject = processObject->globalObject();
auto* release = JSC::constructEmptyObject(globalObject);
// SvelteKit compatibility hack
release->putDirect(vm, vm.propertyNames->name, jsString(vm, WTF::String("node"_s)), 0);
release->putDirect(vm, vm.propertyNames->name, jsString(vm, String("node"_s)), 0); // maybe this should be 'bun' eventually
release->putDirect(vm, Identifier::fromString(vm, "lts"_s), jsBoolean(false), 0);
release->putDirect(vm, Identifier::fromString(vm, "sourceUrl"_s), jsString(vm, WTF::String(std::span { Bun__githubURL, strlen(Bun__githubURL) })), 0);
release->putDirect(vm, Identifier::fromString(vm, "headersUrl"_s), jsEmptyString(vm), 0);
release->putDirect(vm, Identifier::fromString(vm, "libUrl"_s), jsEmptyString(vm), 0);
release->putDirect(vm, Identifier::fromString(vm, "headersUrl"_s), jsString(vm, String("https://nodejs.org/download/release/v" REPORTED_NODEJS_VERSION "/node-v" REPORTED_NODEJS_VERSION "-headers.tar.gz"_s)), 0);
return release;
}
@@ -463,7 +465,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionUmask,
double number = numberValue.toNumber(globalObject);
int64_t newUmask = isInt52(number) ? tryConvertToInt52(number) : numberValue.toInt32(globalObject);
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {}));
RETURN_IF_EXCEPTION(throwScope, {});
if (newUmask < 0 || newUmask > 4294967295) {
return Bun::ERR::OUT_OF_RANGE(throwScope, globalObject, "mask"_s, 0, 4294967295, numberValue);
}
@@ -507,21 +509,21 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionUptime,
return JSC::JSValue::encode(JSC::jsNumber(result));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionExit,
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
JSC_DEFINE_HOST_FUNCTION(Process_functionExit, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
uint8_t exitCode = 0;
JSValue arg0 = callFrame->argument(0);
if (arg0.isAnyInt()) {
int extiCode32 = arg0.toInt32(globalObject) % 256;
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {}));
RETURN_IF_EXCEPTION(throwScope, {});
exitCode = static_cast<uint8_t>(extiCode32);
Bun__setExitCode(bunVM(globalObject), exitCode);
} else if (!arg0.isUndefinedOrNull()) {
throwTypeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s);
return {};
return Bun::ERR::INVALID_ARG_TYPE(throwScope, globalObject, "code"_s, "number"_s, arg0);
} else {
exitCode = Bun__getExitCode(bunVM(globalObject));
}
@@ -531,7 +533,15 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionExit,
process->m_isExitCodeObservable = true;
Process__dispatchOnExit(zigGlobal, exitCode);
Bun__Process__exit(zigGlobal, exitCode);
// process.reallyExit(exitCode);
auto reallyExitVal = process->get(globalObject, Identifier::fromString(vm, "reallyExit"_s));
RETURN_IF_EXCEPTION(throwScope, {});
MarkedArgumentBuffer args;
args.append(jsNumber(exitCode));
JSC::call(globalObject, reallyExitVal, args, ""_s);
RETURN_IF_EXCEPTION(throwScope, {});
return JSC::JSValue::encode(jsUndefined());
}
@@ -563,12 +573,9 @@ JSC_DEFINE_HOST_FUNCTION(Process_hasUncaughtExceptionCaptureCallback,
extern "C" uint64_t Bun__readOriginTimer(void*);
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
(JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime, (JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
{
Zig::GlobalObject* globalObject
= reinterpret_cast<Zig::GlobalObject*>(globalObject_);
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject_);
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
@@ -576,29 +583,25 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
int64_t seconds = static_cast<int64_t>(time / 1000000000);
int64_t nanoseconds = time % 1000000000;
if (callFrame->argumentCount() > 0) {
JSC::JSValue arg0 = callFrame->uncheckedArgument(0);
if (!arg0.isUndefinedOrNull()) {
JSArray* relativeArray = JSC::jsDynamicCast<JSC::JSArray*>(arg0);
if ((!relativeArray && !arg0.isUndefinedOrNull()) || relativeArray->length() < 2) {
JSC::throwTypeError(globalObject, throwScope, "hrtime() argument must be an array or undefined"_s);
return {};
}
JSValue relativeSecondsValue = relativeArray->getIndexQuickly(0);
JSValue relativeNanosecondsValue = relativeArray->getIndexQuickly(1);
if (!relativeSecondsValue.isNumber() || !relativeNanosecondsValue.isNumber()) {
JSC::throwTypeError(globalObject, throwScope, "hrtime() argument must be an array of 2 integers"_s);
return {};
}
auto arg0 = callFrame->argument(0);
if (callFrame->argumentCount() > 0 && !arg0.isUndefined()) {
JSArray* relativeArray = JSC::jsDynamicCast<JSC::JSArray*>(arg0);
if (!relativeArray) {
return Bun::ERR::INVALID_ARG_TYPE(throwScope, globalObject, "time"_s, "Array"_s, arg0);
}
Bun::V::validateInteger(throwScope, globalObject, jsNumber(relativeArray->length()), jsString(vm, String("time"_s)), jsNumber(2), jsNumber(2));
RETURN_IF_EXCEPTION(throwScope, {});
int64_t relativeSeconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeSecondsValue));
int64_t relativeNanoseconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeNanosecondsValue));
seconds -= relativeSeconds;
nanoseconds -= relativeNanoseconds;
if (nanoseconds < 0) {
seconds--;
nanoseconds += 1000000000;
}
JSValue relativeSecondsValue = relativeArray->getIndexQuickly(0);
JSValue relativeNanosecondsValue = relativeArray->getIndexQuickly(1);
int64_t relativeSeconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeSecondsValue));
int64_t relativeNanoseconds = JSC__JSValue__toInt64(JSC::JSValue::encode(relativeNanosecondsValue));
seconds -= relativeSeconds;
nanoseconds -= relativeNanoseconds;
if (nanoseconds < 0) {
seconds--;
nanoseconds += 1000000000;
}
}
@@ -623,8 +626,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(array));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTimeBigInt,
(JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTimeBigInt, (JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
{
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject_);
return JSC::JSValue::encode(JSValue(JSC::JSBigInt::createFrom(globalObject, Bun__readOriginTimer(globalObject->bunVM()))));
@@ -636,11 +638,11 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionChdir,
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
ZigString str = ZigString { nullptr, 0 };
if (callFrame->argumentCount() > 0) {
str = Zig::toZigString(callFrame->uncheckedArgument(0).toWTFString(globalObject));
}
auto value = callFrame->argument(0);
Bun::V::validateString(scope, globalObject, value, jsString(vm, String("directory"_s)));
RETURN_IF_EXCEPTION(scope, {});
ZigString str = Zig::toZigString(value.toWTFString(globalObject));
JSC::JSValue result = JSC::JSValue::decode(Bun__Process__setCwd(globalObject, &str));
RETURN_IF_EXCEPTION(scope, {});
@@ -1834,11 +1836,9 @@ static JSValue constructProcessConfigObject(VM& vm, JSObject* processObject)
static JSValue constructProcessHrtimeObject(VM& vm, JSObject* processObject)
{
auto* globalObject = processObject->globalObject();
JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, globalObject, 0,
String("hrtime"_s), Process_functionHRTime, ImplementationVisibility::Public);
JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, globalObject, 0, String("hrtime"_s), Process_functionHRTime, ImplementationVisibility::Public);
JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, globalObject, 0,
String("bigint"_s), Process_functionHRTimeBigInt, ImplementationVisibility::Public);
JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, globalObject, 0, String("bigint"_s), Process_functionHRTimeBigInt, ImplementationVisibility::Public);
hrtime->putDirect(vm, JSC::Identifier::fromString(vm, "bigint"_s), hrtimeBigInt);
@@ -2120,6 +2120,166 @@ JSC_DEFINE_HOST_FUNCTION(Process_functiongetgroups, (JSGlobalObject * globalObje
return JSValue::encode(groups);
}
static JSValue maybe_uid_by_name(JSC::ThrowScope& throwScope, JSGlobalObject* globalObject, JSValue value)
{
if (!value.isNumber() && !value.isString()) return JSValue::decode(Bun::ERR::INVALID_ARG_TYPE(throwScope, globalObject, "id"_s, "number or string"_s, value));
if (!value.isString()) return value;
auto str = value.getString(globalObject);
if (!str.is8Bit()) {
auto message = makeString("User identifier does not exist: "_s, str);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_CREDENTIAL, message));
return {};
}
auto name = (const char*)(str.span8().data());
struct passwd pwd;
struct passwd* pp = nullptr;
char buf[8192];
if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr) {
return jsNumber(pp->pw_uid);
}
auto message = makeString("User identifier does not exist: "_s, str);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_CREDENTIAL, message));
return {};
}
static JSValue maybe_gid_by_name(JSC::ThrowScope& throwScope, JSGlobalObject* globalObject, JSValue value)
{
if (!value.isNumber() && !value.isString()) return JSValue::decode(Bun::ERR::INVALID_ARG_TYPE(throwScope, globalObject, "id"_s, "number or string"_s, value));
if (!value.isString()) return value;
auto str = value.getString(globalObject);
if (!str.is8Bit()) {
auto message = makeString("Group identifier does not exist: "_s, str);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_CREDENTIAL, message));
return {};
}
auto name = (const char*)(str.span8().data());
struct group pwd;
struct group* pp = nullptr;
char buf[8192];
if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr) {
return jsNumber(pp->gr_gid);
}
auto message = makeString("Group identifier does not exist: "_s, str);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_CREDENTIAL, message));
return {};
}
JSC_DEFINE_HOST_FUNCTION(Process_functionsetuid, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto value = callFrame->argument(0);
auto is_number = value.isNumber();
value = maybe_uid_by_name(scope, globalObject, value);
RETURN_IF_EXCEPTION(scope, {});
if (is_number) Bun::V::validateInteger(scope, globalObject, value, jsString(vm, String("id"_s)), jsNumber(0), jsNumber(std::pow(2, 31) - 1));
RETURN_IF_EXCEPTION(scope, {});
auto id = value.toUInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto result = setuid(id);
if (result != 0) throwSystemError(scope, globalObject, "setuid"_s, errno);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsNumber(result));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionseteuid, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto value = callFrame->argument(0);
auto is_number = value.isNumber();
value = maybe_uid_by_name(scope, globalObject, value);
RETURN_IF_EXCEPTION(scope, {});
if (is_number) Bun::V::validateInteger(scope, globalObject, value, jsString(vm, String("id"_s)), jsNumber(0), jsNumber(std::pow(2, 31) - 1));
RETURN_IF_EXCEPTION(scope, {});
auto id = value.toUInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto result = seteuid(id);
if (result != 0) throwSystemError(scope, globalObject, "seteuid"_s, errno);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsNumber(result));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionsetegid, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto value = callFrame->argument(0);
auto is_number = value.isNumber();
value = maybe_gid_by_name(scope, globalObject, value);
RETURN_IF_EXCEPTION(scope, {});
if (is_number) Bun::V::validateInteger(scope, globalObject, value, jsString(vm, String("id"_s)), jsNumber(0), jsNumber(std::pow(2, 31) - 1));
RETURN_IF_EXCEPTION(scope, {});
auto id = value.toUInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto result = setegid(id);
if (result != 0) throwSystemError(scope, globalObject, "setegid"_s, errno);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsNumber(result));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionsetgid, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto value = callFrame->argument(0);
auto is_number = value.isNumber();
value = maybe_gid_by_name(scope, globalObject, value);
RETURN_IF_EXCEPTION(scope, {});
if (is_number) Bun::V::validateInteger(scope, globalObject, value, jsString(vm, String("id"_s)), jsNumber(0), jsNumber(std::pow(2, 31) - 1));
RETURN_IF_EXCEPTION(scope, {});
auto id = value.toUInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto result = setgid(id);
if (result != 0) throwSystemError(scope, globalObject, "setgid"_s, errno);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsNumber(result));
}
JSC_DEFINE_HOST_FUNCTION(Process_functionsetgroups, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto groups = callFrame->argument(0);
Bun::V::validateArray(scope, globalObject, groups, jsString(vm, String("groups"_s)), jsUndefined());
RETURN_IF_EXCEPTION(scope, {});
auto groupsArray = JSC::jsDynamicCast<JSC::JSArray*>(groups);
auto count = groupsArray->length();
gid_t groupsStack[64];
if (count > 64) return Bun::ERR::OUT_OF_RANGE(scope, globalObject, "groups.length"_s, 0, 64, groups);
for (unsigned i = 0; i < count; i++) {
auto item = groupsArray->getIndexQuickly(i);
auto name = makeString("groups["_s, i, "]"_s);
if (item.isNumber()) {
Bun::V::validateUint32(scope, globalObject, item, jsString(vm, name), jsUndefined());
RETURN_IF_EXCEPTION(scope, {});
groupsStack[i] = item.toUInt32(globalObject);
continue;
} else if (item.isString()) {
item = maybe_gid_by_name(scope, globalObject, item);
RETURN_IF_EXCEPTION(scope, {});
groupsStack[i] = item.toUInt32(globalObject);
continue;
}
return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "number or string"_s, item);
}
auto result = setgroups(count, groupsStack);
if (result != 0) throwSystemError(scope, globalObject, "setgid"_s, errno);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsNumber(result));
}
#endif
JSC_DEFINE_HOST_FUNCTION(Process_functionAssert, (JSGlobalObject * globalObject, CallFrame* callFrame))
@@ -2143,6 +2303,12 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionAssert, (JSGlobalObject * globalObject,
return {};
}
extern "C" uint64_t Bun__Os__getFreeMemory(void);
JSC_DEFINE_HOST_FUNCTION(Process_availableMemory, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
return JSValue::encode(jsDoubleNumber(Bun__Os__getFreeMemory()));
}
#define PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE(str, issue) \
{ \
throwScope.throwException(globalObject, createError(globalObject, String("process.binding(\"" str "\") is not implemented in Bun. Track the status & thumbs up the issue: https://github.com/oven-sh/bun/issues/" issue ""_s))); \
@@ -2236,12 +2402,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionReallyExit, (JSGlobalObject * globalObj
JSValue arg0 = callFrame->argument(0);
if (arg0.isAnyInt()) {
exitCode = static_cast<uint8_t>(arg0.toInt32(globalObject) % 256);
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::JSValue {}));
} else if (!arg0.isUndefinedOrNull()) {
throwTypeError(globalObject, throwScope, "The \"code\" argument must be an integer"_s);
return {};
} else {
exitCode = Bun__getExitCode(bunVM(globalObject));
RETURN_IF_EXCEPTION(throwScope, {});
}
auto* zigGlobal = defaultGlobalObject(globalObject);
@@ -2338,14 +2499,9 @@ static Process* getProcessObject(JSC::JSGlobalObject* lexicalGlobalObject, JSVal
return process;
}
JSC_DEFINE_HOST_FUNCTION(Process_functionConstrainedMemory,
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
JSC_DEFINE_HOST_FUNCTION(Process_functionConstrainedMemory, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
#if OS(LINUX) || OS(FREEBSD)
return JSValue::encode(jsDoubleNumber(static_cast<double>(WTF::ramSize())));
#else
return JSValue::encode(jsUndefined());
#endif
}
JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage,
@@ -2381,8 +2537,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage,
if (!comparatorValue.isUndefined()) {
JSC::JSObject* comparator = comparatorValue.getObject();
if (UNLIKELY(!comparator)) {
throwTypeError(globalObject, throwScope, "Expected an object as the first argument"_s);
return JSC::JSValue::encode(JSC::jsUndefined());
return Bun::ERR::INVALID_ARG_TYPE(throwScope, globalObject, "previousValue"_s, "object"_s, comparatorValue);
}
JSValue userValue;
@@ -2392,34 +2547,28 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage,
userValue = comparator->getDirect(0);
systemValue = comparator->getDirect(1);
} else {
userValue = comparator->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "user"_s));
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
userValue = comparator->get(globalObject, JSC::Identifier::fromString(vm, "user"_s));
RETURN_IF_EXCEPTION(throwScope, {});
systemValue = comparator->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "system"_s));
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
systemValue = comparator->get(globalObject, JSC::Identifier::fromString(vm, "system"_s));
RETURN_IF_EXCEPTION(throwScope, {});
}
if (UNLIKELY(!userValue || !userValue.isNumber())) {
throwTypeError(globalObject, throwScope, "Expected a number for the 'user' property"_s);
return JSC::JSValue::encode(JSC::jsUndefined());
}
Bun::V::validateNumber(throwScope, globalObject, userValue, jsString(vm, String("prevValue.user"_s)), jsUndefined(), jsUndefined());
RETURN_IF_EXCEPTION(throwScope, {});
if (UNLIKELY(!systemValue || !systemValue.isNumber())) {
throwTypeError(globalObject, throwScope, "Expected a number for the 'system' property"_s);
return JSC::JSValue::encode(JSC::jsUndefined());
}
Bun::V::validateNumber(throwScope, globalObject, systemValue, jsString(vm, String("prevValue.system"_s)), jsUndefined(), jsUndefined());
RETURN_IF_EXCEPTION(throwScope, {});
double userComparator = userValue.toNumber(globalObject);
double systemComparator = systemValue.toNumber(globalObject);
if (userComparator > JSC::maxSafeInteger() || userComparator < 0 || std::isnan(userComparator)) {
throwRangeError(globalObject, throwScope, "The 'user' property must be a number between 0 and 2^53"_s);
return JSC::JSValue::encode(JSC::jsUndefined());
if (!(userComparator >= 0 && userComparator <= JSC::maxSafeInteger())) {
return Bun::ERR::INVALID_ARG_VALUE(throwScope, globalObject, "prevValue.user"_s, userValue, "must be a number between 0 and 2^53"_s);
}
if (systemComparator > JSC::maxSafeInteger() || systemComparator < 0 || std::isnan(systemComparator)) {
throwRangeError(globalObject, throwScope, "The 'system' property must be a number between 0 and 2^53"_s);
return JSC::JSValue::encode(JSC::jsUndefined());
if (!(systemComparator >= 0 && systemComparator <= JSC::maxSafeInteger())) {
return Bun::ERR::INVALID_ARG_VALUE(throwScope, globalObject, "prevValue.system"_s, systemValue, "must be a number between 0 and 2^53"_s);
}
user -= userComparator;
@@ -2536,7 +2685,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsage,
JSC::JSObject* result = JSC::constructEmptyObject(vm, process->memoryUsageStructure());
if (UNLIKELY(throwScope.exception())) {
return JSC::JSValue::encode(JSC::JSValue {});
return {};
}
// Node.js:
@@ -3011,6 +3160,7 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu
argv constructArgv PropertyCallback
argv0 constructArgv0 PropertyCallback
assert Process_functionAssert Function 1
availableMemory Process_availableMemory Function 0
binding Process_functionBinding Function 1
browser constructBrowser PropertyCallback
chdir Process_functionChdir Function 1
@@ -3070,12 +3220,19 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu
_stopProfilerIdleNotifier Process_stubEmptyFunction Function 0
_tickCallback Process_stubEmptyFunction Function 0
_kill Process_functionReallyKill Function 2
#if !OS(WINDOWS)
getegid Process_functiongetegid Function 0
geteuid Process_functiongeteuid Function 0
getgid Process_functiongetgid Function 0
getgroups Process_functiongetgroups Function 0
getuid Process_functiongetuid Function 0
setegid Process_functionsetegid Function 1
seteuid Process_functionseteuid Function 1
setgid Process_functionsetgid Function 1
setgroups Process_functionsetgroups Function 1
setuid Process_functionsetuid Function 1
#endif
@end
*/

View File

@@ -304,7 +304,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
auto arg_name = val_arg_name.span8();
ASSERT(WTF::charactersAreAllASCII(arg_name));
auto arg_kind = String(arg_name).startsWith("options."_s) ? "property"_s : "argument"_s;
auto arg_kind = String(arg_name).contains("."_s) ? "property"_s : "argument"_s;
auto expected_type = val_expected_type.span8();
ASSERT(WTF::charactersAreAllASCII(expected_type));
@@ -324,7 +324,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
auto arg_name = val_arg_name.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
auto arg_kind = String(arg_name).startsWith("options."_s) ? "property"_s : "argument"_s;
auto arg_kind = String(arg_name).contains("."_s) ? "property"_s : "argument"_s;
auto expected_type = val_expected_type.span8();
ASSERT(WTF::charactersAreAllASCII(expected_type));
@@ -360,6 +360,11 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
auto actual_value = JSValueToStringSafe(globalObject, actual);
RETURN_IF_EXCEPTION(throwScope, {});
if (lower == upper) {
auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, lowerStr, ". Received "_s, actual_value);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
return {};
}
auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be >= "_s, lowerStr, " and <= "_s, upperStr, ". Received "_s, actual_value);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
return {};
@@ -407,13 +412,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& name, JSC::JSValue value, const WTF::String& reason)
{
ASCIILiteral type;
{
auto sp = name.span8();
auto str = std::string_view((const char*)(sp.data()), sp.size());
auto has = str.find('.') == std::string::npos;
type = has ? "property"_s : "argument"_s;
}
auto type = name.contains("."_s) ? "property"_s : "argument"_s;
auto value_string = JSValueToStringSafe(globalObject, value);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -614,6 +613,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_BUFFER_OUT_OF_BOUNDS, (JSC::JSGlobalObje
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS, "Attempt to access memory outside buffer bounds"_s));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_IPC_ONE_PIPE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame*))
{
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_IPC_ONE_PIPE, "Child process can have only one IPC pipe"_s));
}
} // namespace Bun
JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason)

View File

@@ -67,6 +67,7 @@ JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BROTLI_INVALID_PARAM);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BUFFER_TOO_LARGE);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_ZLIB_INITIALIZATION_FAILED);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BUFFER_OUT_OF_BOUNDS);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_IPC_ONE_PIPE);
enum Bound {
LOWER,

View File

@@ -45,6 +45,8 @@ export default [
["ERR_BUFFER_OUT_OF_BOUNDS", RangeError, "RangeError"],
["ERR_UNKNOWN_SIGNAL", TypeError, "TypeError"],
["ERR_SOCKET_BAD_PORT", RangeError, "RangeError"],
["ERR_IPC_ONE_PIPE", Error, "Error"],
["ERR_UNKNOWN_CREDENTIAL", Error, "Error"],
["ERR_STREAM_RELEASE_LOCK", Error, "AbortError"],
// Bun-specific

View File

@@ -297,6 +297,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateArray, (JSC::JSGlobalObject * global
auto value = callFrame->argument(0);
auto name = callFrame->argument(1);
auto minLength = callFrame->argument(2);
return V::validateArray(scope, globalObject, value, name, minLength);
}
JSC::EncodedJSValue V::validateArray(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name, JSValue minLength)
{
JSC::VM& vm = globalObject->vm();
if (minLength.isUndefined()) minLength = jsNumber(0);
@@ -348,7 +353,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateUint32, (JSC::JSGlobalObject * globa
auto value = callFrame->argument(0);
auto name = callFrame->argument(1);
auto positive = callFrame->argument(2);
return V::validateUint32(scope, globalObject, value, name, positive);
}
JSC::EncodedJSValue V::validateUint32(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name, JSValue positive)
{
if (!value.isNumber()) return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "number"_s, value);
if (positive.isUndefined()) positive = jsBoolean(false);

View File

@@ -31,6 +31,8 @@ JSC::EncodedJSValue validateNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject*
JSC::EncodedJSValue validateFiniteNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue number, JSC::JSValue name);
JSC::EncodedJSValue validateString(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name);
JSC::EncodedJSValue validateString(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name);
JSC::EncodedJSValue validateArray(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name, JSValue minLength);
JSC::EncodedJSValue validateUint32(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name, JSValue positive);
}

View File

@@ -14,12 +14,31 @@ extern "C" uint64_t Bun__Os__getFreeMemory(void)
vm_statistics_data_t info;
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count)
!= KERN_SUCCESS) {
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count) != KERN_SUCCESS) {
return 0;
}
return (uint64_t)info.free_count * sysconf(_SC_PAGESIZE);
}
#endif
#if OS(LINUX)
#include <sys/sysinfo.h>
extern "C" uint64_t Bun__Os__getFreeMemory(void)
{
struct sysinfo info;
if (sysinfo(&info) == 0) {
return info.freeram * info.mem_unit;
}
return 0;
}
#endif
#if OS(WINDOWS)
extern "C" uint64_t uv_get_available_memory(void);
extern "C" uint64_t Bun__Os__getFreeMemory(void)
{
return uv_get_available_memory();
}
#endif

View File

@@ -1,6 +1,260 @@
#include "root.h"
#include "helpers.h"
#include "BunClientData.h"
#include <string.h>
const char* errno_string(int errorno)
{
#define ERRNO_CASE(e) \
case e: \
return #e;
switch (errorno) {
#ifdef EACCES
ERRNO_CASE(EACCES);
#endif
#ifdef EADDRINUSE
ERRNO_CASE(EADDRINUSE);
#endif
#ifdef EADDRNOTAVAIL
ERRNO_CASE(EADDRNOTAVAIL);
#endif
#ifdef EAFNOSUPPORT
ERRNO_CASE(EAFNOSUPPORT);
#endif
#ifdef EAGAIN
ERRNO_CASE(EAGAIN);
#endif
#ifdef EWOULDBLOCK
#if EAGAIN != EWOULDBLOCK
ERRNO_CASE(EWOULDBLOCK);
#endif
#endif
#ifdef EALREADY
ERRNO_CASE(EALREADY);
#endif
#ifdef EBADF
ERRNO_CASE(EBADF);
#endif
#ifdef EBADMSG
ERRNO_CASE(EBADMSG);
#endif
#ifdef EBUSY
ERRNO_CASE(EBUSY);
#endif
#ifdef ECANCELED
ERRNO_CASE(ECANCELED);
#endif
#ifdef ECHILD
ERRNO_CASE(ECHILD);
#endif
#ifdef ECONNABORTED
ERRNO_CASE(ECONNABORTED);
#endif
#ifdef ECONNREFUSED
ERRNO_CASE(ECONNREFUSED);
#endif
#ifdef ECONNRESET
ERRNO_CASE(ECONNRESET);
#endif
#ifdef EDEADLK
ERRNO_CASE(EDEADLK);
#endif
#ifdef EDESTADDRREQ
ERRNO_CASE(EDESTADDRREQ);
#endif
#ifdef EDOM
ERRNO_CASE(EDOM);
#endif
#ifdef EDQUOT
ERRNO_CASE(EDQUOT);
#endif
#ifdef EEXIST
ERRNO_CASE(EEXIST);
#endif
#ifdef EFAULT
ERRNO_CASE(EFAULT);
#endif
#ifdef EFBIG
ERRNO_CASE(EFBIG);
#endif
#ifdef EHOSTUNREACH
ERRNO_CASE(EHOSTUNREACH);
#endif
#ifdef EIDRM
ERRNO_CASE(EIDRM);
#endif
#ifdef EILSEQ
ERRNO_CASE(EILSEQ);
#endif
#ifdef EINPROGRESS
ERRNO_CASE(EINPROGRESS);
#endif
#ifdef EINTR
ERRNO_CASE(EINTR);
#endif
#ifdef EINVAL
ERRNO_CASE(EINVAL);
#endif
#ifdef EIO
ERRNO_CASE(EIO);
#endif
#ifdef EISCONN
ERRNO_CASE(EISCONN);
#endif
#ifdef EISDIR
ERRNO_CASE(EISDIR);
#endif
#ifdef ELOOP
ERRNO_CASE(ELOOP);
#endif
#ifdef EMFILE
ERRNO_CASE(EMFILE);
#endif
#ifdef EMLINK
ERRNO_CASE(EMLINK);
#endif
#ifdef EMSGSIZE
ERRNO_CASE(EMSGSIZE);
#endif
#ifdef EMULTIHOP
ERRNO_CASE(EMULTIHOP);
#endif
#ifdef ENAMETOOLONG
ERRNO_CASE(ENAMETOOLONG);
#endif
#ifdef ENETDOWN
ERRNO_CASE(ENETDOWN);
#endif
#ifdef ENETRESET
ERRNO_CASE(ENETRESET);
#endif
#ifdef ENETUNREACH
ERRNO_CASE(ENETUNREACH);
#endif
#ifdef ENFILE
ERRNO_CASE(ENFILE);
#endif
#ifdef ENOBUFS
ERRNO_CASE(ENOBUFS);
#endif
#ifdef ENODATA
ERRNO_CASE(ENODATA);
#endif
#ifdef ENODEV
ERRNO_CASE(ENODEV);
#endif
#ifdef ENOENT
ERRNO_CASE(ENOENT);
#endif
#ifdef ENOEXEC
ERRNO_CASE(ENOEXEC);
#endif
#ifdef ENOLINK
ERRNO_CASE(ENOLINK);
#endif
#ifdef ENOLCK
#if ENOLINK != ENOLCK
ERRNO_CASE(ENOLCK);
#endif
#endif
#ifdef ENOMEM
ERRNO_CASE(ENOMEM);
#endif
#ifdef ENOMSG
ERRNO_CASE(ENOMSG);
#endif
#ifdef ENOPROTOOPT
ERRNO_CASE(ENOPROTOOPT);
#endif
#ifdef ENOSPC
ERRNO_CASE(ENOSPC);
#endif
#ifdef ENOSR
ERRNO_CASE(ENOSR);
#endif
#ifdef ENOSTR
ERRNO_CASE(ENOSTR);
#endif
#ifdef ENOSYS
ERRNO_CASE(ENOSYS);
#endif
#ifdef ENOTCONN
ERRNO_CASE(ENOTCONN);
#endif
#ifdef ENOTDIR
ERRNO_CASE(ENOTDIR);
#endif
#ifdef ENOTEMPTY
#if ENOTEMPTY != EEXIST
ERRNO_CASE(ENOTEMPTY);
#endif
#endif
#ifdef ENOTSOCK
ERRNO_CASE(ENOTSOCK);
#endif
#ifdef ENOTSUP
ERRNO_CASE(ENOTSUP);
#else
#ifdef EOPNOTSUPP
ERRNO_CASE(EOPNOTSUPP);
#endif
#endif
#ifdef ENOTTY
ERRNO_CASE(ENOTTY);
#endif
#ifdef ENXIO
ERRNO_CASE(ENXIO);
#endif
#ifdef EOVERFLOW
ERRNO_CASE(EOVERFLOW);
#endif
#ifdef EPERM
ERRNO_CASE(EPERM);
#endif
#ifdef EPIPE
ERRNO_CASE(EPIPE);
#endif
#ifdef EPROTO
ERRNO_CASE(EPROTO);
#endif
#ifdef EPROTONOSUPPORT
ERRNO_CASE(EPROTONOSUPPORT);
#endif
#ifdef EPROTOTYPE
ERRNO_CASE(EPROTOTYPE);
#endif
#ifdef ERANGE
ERRNO_CASE(ERANGE);
#endif
#ifdef EROFS
ERRNO_CASE(EROFS);
#endif
#ifdef ESPIPE
ERRNO_CASE(ESPIPE);
#endif
#ifdef ESRCH
ERRNO_CASE(ESRCH);
#endif
#ifdef ESTALE
ERRNO_CASE(ESTALE);
#endif
#ifdef ETIME
ERRNO_CASE(ETIME);
#endif
#ifdef ETIMEDOUT
ERRNO_CASE(ETIMEDOUT);
#endif
#ifdef ETXTBSY
ERRNO_CASE(ETXTBSY);
#endif
#ifdef EXDEV
ERRNO_CASE(EXDEV);
#endif
default:
return "";
}
}
JSC::JSValue createSystemError(JSC::JSGlobalObject* global, ASCIILiteral message, ASCIILiteral syscall, int err)
{
@@ -15,11 +269,13 @@ JSC::JSValue createSystemError(JSC::JSGlobalObject* global, ASCIILiteral message
JSC::JSValue createSystemError(JSC::JSGlobalObject* global, ASCIILiteral syscall, int err)
{
auto* instance = JSC::createError(global, makeString(String(syscall), "() failed"_s));
auto errstr = String::fromLatin1(errno_string(err));
auto* instance = JSC::createError(global, makeString(String(syscall), "() failed: "_s, errstr, ": "_s, String::fromLatin1(strerror(err))));
auto& vm = global->vm();
auto& builtinNames = WebCore::builtinNames(vm);
instance->putDirect(vm, builtinNames.syscallPublicName(), jsString(vm, String(syscall)), 0);
instance->putDirect(vm, builtinNames.errnoPublicName(), JSC::jsNumber(err), 0);
instance->putDirect(vm, vm.propertyNames->name, jsString(vm, String("SystemError"_s)), JSC::PropertyAttribute::DontEnum | 0);
instance->putDirect(vm, builtinNames.codePublicName(), jsString(vm, errstr));
return instance;
}

View File

@@ -10,4 +10,5 @@ export default {
ERR_BUFFER_TOO_LARGE: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_BUFFER_TOO_LARGE", 0),
ERR_ZLIB_INITIALIZATION_FAILED: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_ZLIB_INITIALIZATION_FAILED", 0),
ERR_BUFFER_OUT_OF_BOUNDS: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_BUFFER_OUT_OF_BOUNDS", 0),
ERR_IPC_ONE_PIPE: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_IPC_ONE_PIPE", 0),
};

View File

@@ -2,7 +2,7 @@
const EventEmitter = require("node:events");
const StreamModule = require("node:stream");
const OsModule = require("node:os");
const { ERR_INVALID_ARG_TYPE, ERR_IPC_DISCONNECTED } = require("internal/errors");
const { ERR_INVALID_ARG_TYPE, ERR_IPC_DISCONNECTED, ERR_IPC_ONE_PIPE } = require("internal/errors");
const { kHandle } = require("internal/shared");
const {
validateBoolean,
@@ -74,9 +74,7 @@ var ReadableFromWeb;
// TODO: Add these params after support added in Bun.spawn
// uid <number> Sets the user identity of the process (see setuid(2)).
// gid <number> Sets the group identity of the process (see setgid(2)).
// detached <boolean> Prepare child to run independently of its parent process. Specific behavior depends on the platform, see options.detached).
// TODO: Add support for ipc option, verify only one IPC channel in array
// stdio <Array> | <string> Child's stdio configuration (see options.stdio).
// Support wrapped ipc types (e.g. net.Socket, dgram.Socket, TTY, etc.)
// IPC FD passing support
@@ -1391,7 +1389,7 @@ const nodeToBunLookup = {
ipc: "ipc",
};
function nodeToBun(item, index) {
function nodeToBun(item: string, index: number): string | number | null {
// If not defined, use the default.
// For stdin/stdout/stderr, it's pipe. For others, it's ignore.
if (item == null) {
@@ -1460,6 +1458,7 @@ function fdToStdioName(fd) {
function getBunStdioFromOptions(stdio) {
const normalizedStdio = normalizeStdio(stdio);
if (normalizedStdio.filter(v => v === "ipc").length > 1) throw ERR_IPC_ONE_PIPE();
// Node options:
// pipe: just a pipe
// ipc = can only be one in array
@@ -1486,7 +1485,7 @@ function getBunStdioFromOptions(stdio) {
return bunStdio;
}
function normalizeStdio(stdio) {
function normalizeStdio(stdio): string[] {
if (typeof stdio === "string") {
switch (stdio) {
case "ignore":

View File

@@ -454,13 +454,13 @@ describe("process.cpuUsage", () => {
user: -1,
system: 100,
}),
).toThrow("The 'user' property must be a number between 0 and 2^53");
).toThrow("The property 'prevValue.user' must be a number between 0 and 2^53. Received -1");
expect(() =>
process.cpuUsage({
user: 100,
system: -1,
}),
).toThrow("The 'system' property must be a number between 0 and 2^53");
).toThrow("The property 'prevValue.system' must be a number between 0 and 2^53. Received -1");
});
// Skipped on Windows because it seems UV returns { user: 15000, system: 0 } constantly
@@ -680,13 +680,7 @@ it("dlopen accepts file: URLs", () => {
});
it("process.constrainedMemory()", () => {
if (process.platform === "linux") {
// On Linux, it returns 0 if the kernel doesn't support it
expect(process.constrainedMemory() >= 0).toBe(true);
} else {
// On unsupported platforms, it returns undefined
expect(process.constrainedMemory()).toBeUndefined();
}
expect(process.constrainedMemory() >= 0).toBe(true);
});
it("process.report", () => {

View File

@@ -0,0 +1,35 @@
//#FILE: test-buffer-tojson.js
//#SHA1: 39b31549a09e67c89316a24c895db2dfab939ec4
//-----------------
"use strict";
test("Buffer JSON serialization", () => {
expect(JSON.stringify(Buffer.alloc(0))).toBe('{"type":"Buffer","data":[]}');
expect(JSON.stringify(Buffer.from([1, 2, 3, 4]))).toBe('{"type":"Buffer","data":[1,2,3,4]}');
});
// issue GH-7849
test("Buffer deserialization", () => {
const buf = Buffer.from("test");
const json = JSON.stringify(buf);
const obj = JSON.parse(json);
const copy = Buffer.from(obj);
expect(copy).toEqual(buf);
});
// GH-5110
test("Buffer serialization and custom deserialization", () => {
const buffer = Buffer.from("test");
const string = JSON.stringify(buffer);
expect(string).toBe('{"type":"Buffer","data":[116,101,115,116]}');
function receiver(key, value) {
return value && value.type === "Buffer" ? Buffer.from(value.data) : value;
}
expect(JSON.parse(string, receiver)).toEqual(buffer);
});
//<#END_FILE: test-buffer-tojson.js

View File

@@ -0,0 +1,80 @@
//#FILE: test-child-process-stdio.js
//#SHA1: a121f9dd100777ada90408ac3980c35230cc119f
//-----------------
// 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 { spawn } = require("child_process");
const pwdCommand = process.platform === "win32" ? ["cmd", ["/c", "cd"]] : ["pwd"];
test("stdio piping", () => {
const child = spawn(...pwdCommand, { stdio: ["pipe"] });
expect(child.stdout).not.toBeNull();
expect(child.stderr).not.toBeNull();
});
test("stdio ignoring", () => {
const child = spawn(...pwdCommand, { stdio: "ignore" });
expect(child.stdout).toBeNull();
expect(child.stderr).toBeNull();
});
test("Asset options invariance", () => {
const options = { stdio: "ignore" };
spawn(...pwdCommand, options);
expect(options).toEqual({ stdio: "ignore" });
});
test("stdout buffering", done => {
let output = "";
const child = spawn(...pwdCommand);
child.stdout.setEncoding("utf8");
child.stdout.on("data", function (s) {
output += s;
});
child.on("exit", code => {
expect(code).toBe(0);
});
child.on("close", () => {
expect(output.length).toBeGreaterThan(1);
expect(output[output.length - 1]).toBe("\n");
done();
});
});
test("Assert only one IPC pipe allowed", () => {
expect(() => {
spawn(...pwdCommand, { stdio: ["pipe", "pipe", "pipe", "ipc", "ipc"] });
}).toThrow(
expect.objectContaining({
code: "ERR_IPC_ONE_PIPE",
name: "Error",
message: expect.any(String),
}),
);
});
//<#END_FILE: test-child-process-stdio.js

View File

@@ -0,0 +1,55 @@
//#FILE: test-child-process-windows-hide.js
//#SHA1: c3cc8bbd27694658607c3a7f42a8e7901aeab807
//-----------------
"use strict";
const cp = require("child_process");
const cmd = process.execPath;
const args = ["--print", "42"];
const options = { windowsHide: true, env: { ...Bun.env } };
delete options.env.FORCE_COLOR;
// Since windowsHide isn't really observable, we'll use Jest's mocking capabilities
// to verify that the flag is being passed through correctly.
beforeEach(() => {
jest.spyOn(cp, "spawn");
jest.spyOn(cp, "spawnSync");
});
afterEach(() => {
jest.restoreAllMocks();
});
test("spawnSync passes windowsHide option", () => {
const child = cp.spawnSync(cmd, args, options);
expect(cp.spawnSync).toHaveBeenCalledWith(cmd, args, expect.objectContaining({ windowsHide: true }));
expect(child.status).toBe(0);
expect(child.signal).toBeNull();
expect(child.stdout.toString().trim()).toBe("42");
expect(child.stderr.toString().trim()).toBe("");
});
test("spawn passes windowsHide option", done => {
const child = cp.spawn(cmd, args, options);
expect(cp.spawn).toHaveBeenCalledWith(cmd, args, expect.objectContaining({ windowsHide: true }));
child.on("exit", (code, signal) => {
expect(code).toBe(0);
expect(signal).toBeNull();
done();
});
});
test("execFile passes windowsHide option", done => {
cp.execFile(cmd, args, options, (error, stdout, stderr) => {
expect(error).toBeNull();
expect(stdout.trim()).toBe("42");
expect(stderr.trim()).toBe("");
done();
});
});
//<#END_FILE: test-child-process-windows-hide.js

View File

@@ -0,0 +1,21 @@
//#FILE: test-fs-buffertype-writesync.js
//#SHA1: 6af4aca43ae7299ed310d17733db6dcc43d0ed2b
//-----------------
'use strict';
const fs = require('fs');
test('fs.writeSync throws for invalid data input', () => {
const invalidInputs = [
true, false, 0, 1, Infinity, () => {}, {}, [], undefined, null,
];
invalidInputs.forEach((value) => {
expect(() => fs.writeSync(1, value)).toThrow(expect.objectContaining({
message: expect.stringMatching(/"buffer"/),
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError'
}));
});
});
//<#END_FILE: test-fs-buffertype-writesync.js

View File

@@ -0,0 +1,41 @@
//#FILE: test-fs-read-zero-length.js
//#SHA1: bda4b0f0c821a8479ffbf0a9099444eed6ee5c4e
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const fixturesPath = path.join(__dirname, '..', 'fixtures');
const filepath = path.join(fixturesPath, 'x.txt');
let fd;
beforeAll(() => {
fd = fs.openSync(filepath, 'r');
});
afterAll(() => {
fs.closeSync(fd);
});
test('fs.read with zero length buffer (async)', (done) => {
const bufferAsync = Buffer.alloc(0);
fs.read(fd, bufferAsync, 0, 0, 0, (err, bytesRead) => {
expect(err).toBeNull();
expect(bytesRead).toBe(0);
expect(bufferAsync).toEqual(Buffer.alloc(0));
done();
});
});
test('fs.readSync with zero length buffer', () => {
const bufferSync = Buffer.alloc(0);
const bytesRead = fs.readSync(fd, bufferSync, 0, 0, 0);
expect(bufferSync).toEqual(Buffer.alloc(0));
expect(bytesRead).toBe(0);
});
//<#END_FILE: test-fs-read-zero-length.js

View File

@@ -0,0 +1,11 @@
//#FILE: test-process-available-memory.js
//#SHA1: 9dd0a4755f67f4786a0b7fc076d81be2a0b2063b
//-----------------
"use strict";
test("process.availableMemory()", () => {
const availableMemory = process.availableMemory();
expect(typeof availableMemory).toBe("number");
});
//<#END_FILE: test-process-available-memory.js

View File

@@ -0,0 +1,70 @@
//#FILE: test-process-chdir.js
//#SHA1: af98467edcecd1605cd517f45d87e02ba840420b
//-----------------
"use strict";
const fs = require("fs");
const path = require("path");
// Skip test for workers
if (typeof process.chdir !== "function") {
test.skip("process.chdir is not available in Workers", () => {});
} else {
const originalCwd = process.cwd();
afterAll(() => {
// Ensure we return to the original directory after all tests
process.chdir(originalCwd);
});
test("process.chdir changes current working directory", () => {
process.chdir("..");
expect(process.cwd()).not.toBe(__dirname);
process.chdir(__dirname);
expect(process.cwd()).toBe(__dirname);
});
test("process.chdir works with non-ASCII characters", () => {
let dirName;
if (process.versions.icu) {
// ICU is available, use characters that could possibly be decomposed
dirName = "weird \uc3a4\uc3ab\uc3af characters \u00e1\u00e2\u00e3";
} else {
// ICU is unavailable, use characters that can't be decomposed
dirName = "weird \ud83d\udc04 characters \ud83d\udc05";
}
const tmpdir = path.resolve(__dirname, "../tmp");
const dir = path.resolve(tmpdir, dirName);
// Make sure that the tmp directory is clean
if (fs.existsSync(tmpdir)) {
fs.rmSync(tmpdir, { recursive: true, force: true });
}
fs.mkdirSync(tmpdir, { recursive: true });
fs.mkdirSync(dir);
process.chdir(dir);
expect(process.cwd().normalize()).toBe(dir.normalize());
process.chdir("..");
expect(process.cwd().normalize()).toBe(path.resolve(tmpdir).normalize());
});
test("process.chdir throws for invalid arguments", () => {
expect(() => process.chdir({})).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
message: expect.stringMatching(/The "directory" argument must be of type string/),
}),
);
expect(() => process.chdir()).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
message: expect.stringMatching(/The "directory" argument must be of type string/),
}),
);
});
}
//<#END_FILE: test-process-chdir.js

View File

@@ -0,0 +1,11 @@
//#FILE: test-process-constrained-memory.js
//#SHA1: 6c09d5733a7ac49f00b4923125a023c670423adf
//-----------------
"use strict";
test("process.constrainedMemory()", () => {
const constrainedMemory = process.constrainedMemory();
expect(typeof constrainedMemory).toBe("number");
});
//<#END_FILE: test-process-constrained-memory.js

View File

@@ -0,0 +1,112 @@
//#FILE: test-process-cpuUsage.js
//#SHA1: 68c5aeede535139b8caa17340dcad82df9677047
//-----------------
"use strict";
test("process.cpuUsage", () => {
const result = process.cpuUsage();
// Validate the result of calling with no previous value argument.
validateResult(result);
// Validate the result of calling with a previous value argument.
validateResult(process.cpuUsage(result));
// Ensure the results are >= the previous.
let thisUsage;
let lastUsage = process.cpuUsage();
for (let i = 0; i < 10; i++) {
thisUsage = process.cpuUsage();
validateResult(thisUsage);
expect(thisUsage.user).toBeGreaterThanOrEqual(lastUsage.user);
expect(thisUsage.system).toBeGreaterThanOrEqual(lastUsage.system);
lastUsage = thisUsage;
}
// Ensure that the diffs are >= 0.
let startUsage;
let diffUsage;
for (let i = 0; i < 10; i++) {
startUsage = process.cpuUsage();
diffUsage = process.cpuUsage(startUsage);
validateResult(startUsage);
validateResult(diffUsage);
expect(diffUsage.user).toBeGreaterThanOrEqual(0);
expect(diffUsage.system).toBeGreaterThanOrEqual(0);
}
// Ensure that an invalid shape for the previous value argument throws an error.
expect(() => process.cpuUsage(1)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining(`The "previousValue" argument must be of type object. Received`),
}),
);
// Check invalid types.
[{}, { user: "a" }, { user: null, system: "c" }].forEach(value => {
expect(() => process.cpuUsage(value)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining(`The "prevValue.user" property must be of type number. Received`),
}),
);
});
[
{ user: 3, system: "b" },
{ user: 3, system: null },
].forEach(value => {
expect(() => process.cpuUsage(value)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining(`The "prevValue.system" property must be of type number. Received`),
}),
);
});
// Check invalid values.
[
{ user: -1, system: 2 },
{ user: Number.POSITIVE_INFINITY, system: 4 },
].forEach(value => {
expect(() => process.cpuUsage(value)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_VALUE",
name: "TypeError",
message: expect.stringContaining(`The property 'prevValue.user' must be a number between 0 and 2^53. Received`),
}),
);
});
[
{ user: 3, system: -2 },
{ user: 5, system: Number.NEGATIVE_INFINITY },
].forEach(value => {
expect(() => process.cpuUsage(value)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_VALUE",
name: "TypeError",
message: expect.stringContaining(
`The property 'prevValue.system' must be a number between 0 and 2^53. Received`,
),
}),
);
});
});
// Ensure that the return value is the expected shape.
function validateResult(result) {
expect(result).not.toBeNull();
expect(Number.isFinite(result.user)).toBe(true);
expect(Number.isFinite(result.system)).toBe(true);
expect(result.user).toBeGreaterThanOrEqual(0);
expect(result.system).toBeGreaterThanOrEqual(0);
}
//<#END_FILE: test-process-cpuUsage.js

View File

@@ -28,7 +28,7 @@ test('Calling .exit() from within "exit" should not overflow the call stack', ()
let nexits = 0;
const exitHandler = jest.fn(code => {
expect(nexits++).toBe(0);
expect(nexits++).toBeOneOf([0, 1]);
expect(code).toBe(0);
process.exit();
});

View File

@@ -0,0 +1,96 @@
//#FILE: test-process-hrtime.js
//#SHA1: 99ce31a994db014be4c3835d3a5d46ed3ec3a89e
//-----------------
// 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";
test("process.hrtime() default behavior", () => {
// The default behavior, return an Array "tuple" of numbers
const tuple = process.hrtime();
// Validate the default behavior
validateTuple(tuple);
});
test("process.hrtime() with existing tuple", () => {
const tuple = process.hrtime();
// Validate that passing an existing tuple returns another valid tuple
validateTuple(process.hrtime(tuple));
});
test("process.hrtime() with invalid arguments", () => {
// Test that only an Array may be passed to process.hrtime()
expect(() => {
process.hrtime(1);
}).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.any(String),
}),
);
expect(() => {
process.hrtime([]);
}).toThrow(
expect.objectContaining({
code: "ERR_OUT_OF_RANGE",
name: "RangeError",
message: expect.any(String),
}),
);
expect(() => {
process.hrtime([1]);
}).toThrow(
expect.objectContaining({
code: "ERR_OUT_OF_RANGE",
name: "RangeError",
message: expect.any(String),
}),
);
expect(() => {
process.hrtime([1, 2, 3]);
}).toThrow(
expect.objectContaining({
code: "ERR_OUT_OF_RANGE",
name: "RangeError",
message: expect.any(String),
}),
);
});
function validateTuple(tuple) {
expect(Array.isArray(tuple)).toBe(true);
expect(tuple).toHaveLength(2);
expect(Number.isInteger(tuple[0])).toBe(true);
expect(Number.isInteger(tuple[1])).toBe(true);
}
test("process.hrtime() diff", () => {
const diff = process.hrtime([0, 1e9 - 1]);
expect(diff[1]).toBeGreaterThanOrEqual(0); // https://github.com/nodejs/node/issues/4751
});
//<#END_FILE: test-process-hrtime.js

View File

@@ -0,0 +1,23 @@
//#FILE: test-process-really-exit.js
//#SHA1: ad12d9cd84340ccf30df102407fc23cdc83801f0
//-----------------
"use strict";
const { spawnSync } = require("child_process");
if (process.argv[2] === "subprocess") {
process.reallyExit = function () {
console.info("really exited");
};
process.exit();
} else {
test("reallyExit hook is executed", () => {
// Ensure that the reallyExit hook is executed.
// see: https://github.com/nodejs/node/issues/25650
const out = spawnSync(process.execPath, [__filename, "subprocess"]);
const observed = out.output[1].toString("utf8").trim();
expect(observed).toBe("really exited");
});
}
//<#END_FILE: test-process-really-exit.js

View File

@@ -0,0 +1,14 @@
//#FILE: test-process-release.js
//#SHA1: c1e8d1247391778d25fb0d2aeec5525fbe7d05b1
//-----------------
"use strict";
const versionParts = process.versions.node.split(".");
test("process.release properties", () => {
expect(process.release.name).toBe("node");
expect(process.release.lts).toBeUndefined();
});
//<#END_FILE: test-process-release.js

View File

@@ -0,0 +1,63 @@
//#FILE: test-process-setgroups.js
//#SHA1: 8fe1c3ec36e208d67f92c9d1325b228cb3f46312
//-----------------
"use strict";
if (process.platform === "win32") {
test("process.setgroups is undefined on Windows", () => {
expect(process.setgroups).toBeUndefined();
});
} else if (typeof process.isMainThread !== "undefined" && !process.isMainThread) {
// Skip tests in non-main threads
} else {
describe("process.setgroups", () => {
test("throws TypeError when called without arguments", () => {
expect(() => {
process.setgroups();
}).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining('The "groups" argument must be an instance of Array'),
}),
);
});
test("throws RangeError for invalid group ID", () => {
expect(() => {
process.setgroups([1, -1]);
}).toThrow(
expect.objectContaining({
code: "ERR_OUT_OF_RANGE",
name: "RangeError",
}),
);
});
// [], https://github.com/oven-sh/bun/issues/11793
test.each([undefined, null, true, {}, () => {}])("throws TypeError for invalid group type: %p", val => {
expect(() => {
process.setgroups([val]);
}).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining('The "groups[0]" argument must be of type number or string'),
}),
);
});
test("throws ERR_UNKNOWN_CREDENTIAL for non-existent group", () => {
expect(() => {
process.setgroups([1, "fhqwhgadshgnsdhjsdbkhsdabkfabkveyb"]);
}).toThrow(
expect.objectContaining({
code: "ERR_UNKNOWN_CREDENTIAL",
message: "Group identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb",
}),
);
});
});
}
//<#END_FILE: test-process-setgroups.js

View File

@@ -0,0 +1,110 @@
//#FILE: test-process-uid-gid.js
//#SHA1: fdd637ef2fcf3bcada2c86f574494e32e5c03780
//-----------------
// 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 isWindows = process.platform === "win32";
const isMainThread = !process.env.NODE_WORKER_ID;
if (isWindows) {
test("uid/gid functions are POSIX only", () => {
// uid/gid functions are POSIX only.
expect(process.getuid).toBeUndefined();
expect(process.getgid).toBeUndefined();
expect(process.setuid).toBeUndefined();
expect(process.setgid).toBeUndefined();
});
} else if (isMainThread) {
test("setuid with invalid arguments", () => {
expect(() => process.setuid({})).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
message: expect.stringContaining('The "id" argument must be of type number or string'),
}),
);
expect(() => process.setuid("fhqwhgadshgnsdhjsdbkhsdabkfabkveyb")).toThrow(
expect.objectContaining({
code: "ERR_UNKNOWN_CREDENTIAL",
message: "User identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb",
}),
);
});
{
// Passing -0 shouldn't crash the process
// Refs: https://github.com/nodejs/node/issues/32750
// And neither should values exceeding 2 ** 31 - 1.
const ids = [-0, 2 ** 31, 2 ** 32 - 1];
const fns = [process.setuid, process.setuid, process.setgid, process.setegid];
for (const fn of fns) {
for (const id of ids) {
test(`edge cases for uid/gid functions: ${fn.name}: ${id}`, () => {
expect(() => {
try {
fn(id);
} catch {
// Continue regardless of error.
}
}).not.toThrow();
});
}
}
}
if (process.getuid() !== 0) {
test("non-root user permissions", () => {
// Should not throw.
expect(() => process.getgid()).not.toThrow();
expect(() => process.getuid()).not.toThrow();
expect(() => process.setgid("nobody")).toThrow(/EPERM|Group identifier does not exist/);
expect(() => process.setuid("nobody")).toThrow(/EPERM|User identifier does not exist/);
});
} else {
test("root user permissions", async () => {
const oldgid = process.getgid();
try {
process.setgid("nobody");
} catch (err) {
if (err.code !== "ERR_UNKNOWN_CREDENTIAL") {
throw err;
}
process.setgid("nogroup");
}
const newgid = process.getgid();
expect(newgid).not.toBe(oldgid);
const olduid = process.getuid();
process.setuid("nobody");
const newuid = process.getuid();
expect(newuid).not.toBe(olduid);
});
}
}
//<#END_FILE: test-process-uid-gid.js