mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Implement process.memoryUsage() and process.cpuUsage() (#3586)
* Implement process.memoryUsage() and process.cpuUsage() * Avoid mi_process_info * Update bench * Update Process.cpp * fixup * More tests + linux fixup * Skip it for now since it seems less accurate --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
33
bench/snippets/process-info.mjs
Normal file
33
bench/snippets/process-info.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import { bench, run } from "./runner.mjs";
|
||||
import { performance } from "perf_hooks";
|
||||
|
||||
bench("process.memoryUsage()", () => {
|
||||
process.memoryUsage();
|
||||
});
|
||||
|
||||
bench("process.memoryUsage.rss()", () => {
|
||||
process.memoryUsage.rss();
|
||||
});
|
||||
|
||||
bench("process.cpuUsage()", () => {
|
||||
process.cpuUsage();
|
||||
});
|
||||
|
||||
const init = process.cpuUsage();
|
||||
bench("process.cpuUsage(delta)", () => {
|
||||
process.cpuUsage(init);
|
||||
});
|
||||
|
||||
bench("performance.now()", () => {
|
||||
performance.now();
|
||||
});
|
||||
|
||||
bench("process.hrtime()", () => {
|
||||
process.hrtime();
|
||||
});
|
||||
|
||||
bench("process.hrtime.bigint()", () => {
|
||||
process.hrtime.bigint();
|
||||
});
|
||||
|
||||
await run();
|
||||
@@ -12,8 +12,24 @@
|
||||
#include "ZigConsoleClient.h"
|
||||
#include <JavaScriptCore/GetterSetter.h>
|
||||
#include <JavaScriptCore/JSSet.h>
|
||||
#include <JavaScriptCore/LazyProperty.h>
|
||||
#include <JavaScriptCore/LazyPropertyInlines.h>
|
||||
#include <JavaScriptCore/VMTrapsInlines.h>
|
||||
|
||||
#pragma mark - Node.js Process
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <unistd.h> // setuid, getuid
|
||||
#endif
|
||||
@@ -335,9 +351,12 @@ extern "C" uint64_t Bun__readOriginTimer(void*);
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
|
||||
(JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
|
||||
{
|
||||
|
||||
Zig::GlobalObject* globalObject
|
||||
= reinterpret_cast<Zig::GlobalObject*>(globalObject_);
|
||||
auto& vm = globalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
uint64_t time = Bun__readOriginTimer(globalObject->bunVM());
|
||||
int64_t seconds = static_cast<int64_t>(time / 1000000000);
|
||||
int64_t nanoseconds = time % 1000000000;
|
||||
@@ -346,7 +365,6 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
|
||||
JSC::JSValue arg0 = callFrame->uncheckedArgument(0);
|
||||
if (!arg0.isUndefinedOrNull()) {
|
||||
JSArray* relativeArray = JSC::jsDynamicCast<JSC::JSArray*>(arg0);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
if ((!relativeArray && !arg0.isUndefinedOrNull()) || relativeArray->length() < 2) {
|
||||
JSC::throwTypeError(globalObject, throwScope, "hrtime() argument must be an array or undefined"_s);
|
||||
return JSC::JSValue::encode(JSC::JSValue {});
|
||||
@@ -366,14 +384,28 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionHRTime,
|
||||
seconds--;
|
||||
nanoseconds += 1000000000;
|
||||
}
|
||||
throwScope.release();
|
||||
}
|
||||
}
|
||||
|
||||
auto* array = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), 2);
|
||||
array->setIndexQuickly(vm, 0, JSC::jsNumber(seconds));
|
||||
array->setIndexQuickly(vm, 1, JSC::jsNumber(nanoseconds));
|
||||
return JSC::JSValue::encode(JSC::JSValue(array));
|
||||
JSC::JSArray* array = nullptr;
|
||||
{
|
||||
JSC::ObjectInitializationScope initializationScope(vm);
|
||||
if ((array = JSC::JSArray::tryCreateUninitializedRestricted(
|
||||
initializationScope, nullptr,
|
||||
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
|
||||
2))) {
|
||||
|
||||
array->initializeIndex(initializationScope, 0, JSC::jsNumber(seconds));
|
||||
array->initializeIndex(initializationScope, 1, JSC::jsNumber(nanoseconds));
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(!array)) {
|
||||
JSC::throwOutOfMemoryError(globalObject, throwScope);
|
||||
return JSC::JSValue::encode(JSC::JSValue {});
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(array));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionHRTimeBigInt,
|
||||
@@ -680,10 +712,10 @@ static JSValue constructProcessHrtimeObject(VM& vm, JSObject* processObject)
|
||||
{
|
||||
auto* globalObject = processObject->globalObject();
|
||||
JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, globalObject, 0,
|
||||
MAKE_STATIC_STRING_IMPL("hrtime"), Process_functionHRTime, ImplementationVisibility::Public);
|
||||
String("hrtime"_s), Process_functionHRTime, ImplementationVisibility::Public);
|
||||
|
||||
JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, globalObject, 0,
|
||||
MAKE_STATIC_STRING_IMPL("bigint"), Process_functionHRTimeBigInt, ImplementationVisibility::Public);
|
||||
String("bigint"_s), Process_functionHRTimeBigInt, ImplementationVisibility::Public);
|
||||
|
||||
hrtime->putDirect(vm, JSC::Identifier::fromString(vm, "bigint"_s), hrtimeBigInt);
|
||||
|
||||
@@ -945,6 +977,317 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionReallyExit, (JSGlobalObject * globalObj
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void Process::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
{
|
||||
Process* thisObject = jsCast<Process*>(cell);
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
Base::visitChildren(thisObject, visitor);
|
||||
thisObject->cpuUsageStructure.visit(visitor);
|
||||
thisObject->memoryUsageStructure.visit(visitor);
|
||||
}
|
||||
|
||||
DEFINE_VISIT_CHILDREN(Process);
|
||||
|
||||
static Structure* constructCPUUsageStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(globalObject, globalObject->objectPrototype(), 2);
|
||||
PropertyOffset offset;
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "user"_s),
|
||||
0,
|
||||
offset);
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "system"_s),
|
||||
0,
|
||||
offset);
|
||||
return structure;
|
||||
}
|
||||
static Structure* constructMemoryUsageStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(globalObject, globalObject->objectPrototype(), 5);
|
||||
PropertyOffset offset;
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "rss"_s),
|
||||
0,
|
||||
offset);
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "heapTotal"_s),
|
||||
0,
|
||||
offset);
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "heapUsed"_s),
|
||||
0,
|
||||
offset);
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "external"_s),
|
||||
0,
|
||||
offset);
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "arrayBuffers"_s),
|
||||
0,
|
||||
offset);
|
||||
|
||||
return structure;
|
||||
}
|
||||
|
||||
static Process* getProcessObject(JSC::JSGlobalObject* lexicalGlobalObject, JSValue thisValue)
|
||||
{
|
||||
Process* process = jsDynamicCast<Process*>(thisValue);
|
||||
|
||||
// Handle "var memoryUsage = process.memoryUsage; memoryUsage()"
|
||||
if (UNLIKELY(!process)) {
|
||||
// Handle calling this function from inside a node:vm
|
||||
Zig::GlobalObject* zigGlobalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
|
||||
if (UNLIKELY(!zigGlobalObject)) {
|
||||
zigGlobalObject = Bun__getDefaultGlobal();
|
||||
}
|
||||
|
||||
return jsCast<Process*>(zigGlobalObject->processObject());
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage,
|
||||
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
struct rusage rusage;
|
||||
if (getrusage(RUSAGE_SELF, &rusage) != 0) {
|
||||
SystemError error;
|
||||
error.errno_ = errno;
|
||||
error.syscall = Bun::toString("getrusage"_s);
|
||||
error.message = Bun::toString("Failed to get CPU usage"_s);
|
||||
throwException(globalObject, throwScope, JSValue::decode(SystemError__toErrorInstance(&error, globalObject)));
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
auto* process = getProcessObject(globalObject, callFrame->thisValue());
|
||||
|
||||
Structure* cpuUsageStructure = process->cpuUsageStructure.getInitializedOnMainThread(process);
|
||||
|
||||
constexpr double MICROS_PER_SEC = 1000000.0;
|
||||
|
||||
double user = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
|
||||
double system = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
|
||||
|
||||
if (callFrame->argumentCount() > 0) {
|
||||
JSValue comparatorValue = callFrame->argument(0);
|
||||
if (!comparatorValue.isUndefined()) {
|
||||
if (UNLIKELY(!comparatorValue.isObject())) {
|
||||
throwTypeError(globalObject, throwScope, "Expected an object as the first argument"_s);
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
JSC::JSObject* comparator = comparatorValue.getObject();
|
||||
JSValue userValue;
|
||||
JSValue systemValue;
|
||||
|
||||
if (LIKELY(comparator->structureID() == cpuUsageStructure->id())) {
|
||||
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()));
|
||||
|
||||
systemValue = comparator->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "system"_s));
|
||||
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
|
||||
}
|
||||
|
||||
if (UNLIKELY(!userValue || !userValue.isNumber())) {
|
||||
throwTypeError(globalObject, throwScope, "Expected a number for the user property"_s);
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
if (UNLIKELY(!systemValue || !systemValue.isNumber())) {
|
||||
throwTypeError(globalObject, throwScope, "Expected a number for the system property"_s);
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
double userComparator = userValue.asNumber();
|
||||
double systemComparator = systemValue.asNumber();
|
||||
|
||||
user -= userComparator;
|
||||
system -= systemComparator;
|
||||
}
|
||||
}
|
||||
|
||||
JSC::JSObject* result = JSC::constructEmptyObject(vm, cpuUsageStructure);
|
||||
RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
|
||||
|
||||
result->putDirectOffset(vm, 0, JSC::jsNumber(user));
|
||||
result->putDirectOffset(vm, 1, JSC::jsNumber(system));
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(result));
|
||||
}
|
||||
|
||||
static int getRSS(size_t* rss)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
mach_msg_type_number_t count;
|
||||
task_basic_info_data_t info;
|
||||
kern_return_t err;
|
||||
|
||||
count = TASK_BASIC_INFO_COUNT;
|
||||
err = task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO,
|
||||
reinterpret_cast<task_info_t>(&info),
|
||||
&count);
|
||||
|
||||
if (err == KERN_SUCCESS) {
|
||||
*rss = (size_t)info.resident_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
#elif defined(__linux__)
|
||||
// Taken from libuv.
|
||||
char buf[1024];
|
||||
const char* s;
|
||||
ssize_t n;
|
||||
long val;
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
do
|
||||
fd = open("/proc/self/stat", O_RDONLY);
|
||||
while (fd == -1 && errno == EINTR);
|
||||
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
|
||||
do
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
int closeErrno = 0;
|
||||
do {
|
||||
closeErrno = close(fd);
|
||||
} while (closeErrno == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1)
|
||||
return errno;
|
||||
buf[n] = '\0';
|
||||
|
||||
s = strchr(buf, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
s += 1;
|
||||
if (*s != '(')
|
||||
goto err;
|
||||
|
||||
s = strchr(s, ')');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 1; i <= 22; i++) {
|
||||
s = strchr(s + 1, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = strtol(s, NULL, 10);
|
||||
if (errno != 0)
|
||||
goto err;
|
||||
if (val < 0)
|
||||
goto err;
|
||||
|
||||
*rss = val * getpagesize();
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return EINVAL;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsage,
|
||||
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
auto* process = getProcessObject(globalObject, callFrame->thisValue());
|
||||
|
||||
size_t current_rss = 0;
|
||||
if (getRSS(¤t_rss) != 0) {
|
||||
SystemError error;
|
||||
error.errno_ = errno;
|
||||
error.syscall = Bun::toString("memoryUsage"_s);
|
||||
error.message = Bun::toString("Failed to get memory usage"_s);
|
||||
throwException(globalObject, throwScope, JSValue::decode(SystemError__toErrorInstance(&error, globalObject)));
|
||||
return JSC::JSValue::encode(JSC::JSValue {});
|
||||
}
|
||||
|
||||
JSC::JSObject* result = JSC::constructEmptyObject(vm, process->memoryUsageStructure.getInitializedOnMainThread(process));
|
||||
if (UNLIKELY(throwScope.exception())) {
|
||||
return JSC::JSValue::encode(JSC::JSValue {});
|
||||
}
|
||||
|
||||
// Node.js:
|
||||
// {
|
||||
// rss: 4935680,
|
||||
// heapTotal: 1826816,
|
||||
// heapUsed: 650472,
|
||||
// external: 49879,
|
||||
// arrayBuffers: 9386
|
||||
// }
|
||||
|
||||
result->putDirectOffset(vm, 0, JSC::jsNumber(current_rss));
|
||||
result->putDirectOffset(vm, 1, JSC::jsNumber(vm.heap.blockBytesAllocated()));
|
||||
|
||||
// heap.size() loops through every cell...
|
||||
// TODO: add a binding for heap.sizeAfterLastCollection()
|
||||
result->putDirectOffset(vm, 2, JSC::jsNumber(vm.heap.sizeAfterLastEdenCollection()));
|
||||
|
||||
result->putDirectOffset(vm, 3, JSC::jsNumber(vm.heap.externalMemorySize()));
|
||||
|
||||
// We report 0 for this because m_arrayBuffers in JSC::Heap is private and we need to add a binding
|
||||
// If we use objectTypeCounts(), it's hideously slow because it loops through every single object in the heap
|
||||
// TODO: add a binding for m_arrayBuffers, registerWrapper() in TypedArrayController doesn't work
|
||||
result->putDirectOffset(vm, 4, JSC::jsNumber(0));
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(result));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsageRSS,
|
||||
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
size_t current_rss = 0;
|
||||
if (getRSS(¤t_rss) != 0) {
|
||||
SystemError error;
|
||||
error.errno_ = errno;
|
||||
error.syscall = Bun::toString("memoryUsage"_s);
|
||||
error.message = Bun::toString("Failed to get memory usage"_s);
|
||||
throwException(globalObject, throwScope, JSValue::decode(SystemError__toErrorInstance(&error, globalObject)));
|
||||
return JSC::JSValue::encode(JSC::JSValue {});
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsNumber(current_rss)));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(Process_functionOpenStdin, (JSGlobalObject * globalObject, CallFrame* callFrame))
|
||||
{
|
||||
auto& vm = globalObject->vm();
|
||||
@@ -1010,6 +1353,19 @@ static JSValue Process_stubEmptySet(VM& vm, JSObject* processObject)
|
||||
return JSSet::create(vm, globalObject->setStructure());
|
||||
}
|
||||
|
||||
static JSValue constructMemoryUsage(VM& vm, JSObject* processObject)
|
||||
{
|
||||
auto* globalObject = processObject->globalObject();
|
||||
JSC::JSFunction* memoryUsage = JSC::JSFunction::create(vm, globalObject, 0,
|
||||
String("memoryUsage"_s), Process_functionMemoryUsage, ImplementationVisibility::Public);
|
||||
|
||||
JSC::JSFunction* rss = JSC::JSFunction::create(vm, globalObject, 0,
|
||||
String("rss"_s), Process_functionMemoryUsageRSS, ImplementationVisibility::Public);
|
||||
|
||||
memoryUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), rss, JSC::PropertyAttribute::Function | 0);
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
static JSValue constructFeatures(VM& vm, JSObject* processObject)
|
||||
{
|
||||
// {
|
||||
@@ -1133,16 +1489,16 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCwd,
|
||||
browser constructBrowser PropertyCallback
|
||||
chdir Process_functionChdir Function 1
|
||||
config constructProcessConfigObject PropertyCallback
|
||||
debugPort processDebugPort CustomAccessor
|
||||
exitCode processExitCode CustomAccessor
|
||||
title processTitle CustomAccessor
|
||||
cpuUsage Process_functionCpuUsage Function 1
|
||||
cwd Process_functionCwd Function 1
|
||||
debugPort processDebugPort CustomAccessor
|
||||
dlopen Process_functionDlopen Function 1
|
||||
emitWarning Process_emitWarning Function 1
|
||||
env constructEnv PropertyCallback
|
||||
execArgv constructExecArgv PropertyCallback
|
||||
execPath constructExecPath PropertyCallback
|
||||
exit Process_functionExit Function 1
|
||||
exitCode processExitCode CustomAccessor
|
||||
features constructFeatures PropertyCallback
|
||||
getActiveResourcesInfo Process_stubFunctionReturningArray Function 0
|
||||
getegid Process_functiongetegid Function 0
|
||||
@@ -1153,6 +1509,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCwd,
|
||||
hrtime constructProcessHrtimeObject PropertyCallback
|
||||
isBun constructIsBun PropertyCallback
|
||||
mainModule JSBuiltin ReadOnly|Builtin|Accessor|Function 0
|
||||
memoryUsage constructMemoryUsage PropertyCallback
|
||||
moduleLoadList Process_stubEmptyArray PropertyCallback
|
||||
nextTick Process_functionNextTick Function 1
|
||||
openStdin Process_functionOpenStdin Function 0
|
||||
@@ -1166,6 +1523,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCwd,
|
||||
stderr constructStderr PropertyCallback
|
||||
stdin constructStdin PropertyCallback
|
||||
stdout constructStdout PropertyCallback
|
||||
title processTitle CustomAccessor
|
||||
umask Process_functionUmask Function 1
|
||||
uptime Process_functionUptime Function 1
|
||||
version constructVersion PropertyCallback
|
||||
@@ -1192,6 +1550,14 @@ void Process::finishCreation(JSC::VM& vm)
|
||||
{
|
||||
Base::finishCreation(vm);
|
||||
|
||||
this->cpuUsageStructure.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::Structure>::Initializer& init) {
|
||||
init.set(constructCPUUsageStructure(init.vm, init.owner->globalObject()));
|
||||
});
|
||||
|
||||
this->memoryUsageStructure.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::Structure>::Initializer& init) {
|
||||
init.set(constructMemoryUsageStructure(init.vm, init.owner->globalObject()));
|
||||
});
|
||||
|
||||
this->putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(vm, String("process"_s)), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,24 @@ public:
|
||||
return accessor;
|
||||
}
|
||||
|
||||
LazyProperty<JSObject, Structure> cpuUsageStructure;
|
||||
LazyProperty<JSObject, Structure> memoryUsageStructure;
|
||||
|
||||
DECLARE_VISIT_CHILDREN;
|
||||
|
||||
template<typename, SubspaceAccess mode>
|
||||
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
|
||||
return nullptr;
|
||||
return WebCore::subspaceForImpl<Process, WebCore::UseCustomHeapCellType::No>(
|
||||
vm,
|
||||
[](auto& spaces) { return spaces.m_clientSubspaceForProcessObject.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForProcessObject = std::forward<decltype(space)>(space); },
|
||||
[](auto& spaces) { return spaces.m_subspaceForProcessObject.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_subspaceForProcessObject = std::forward<decltype(space)>(space); });
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM& vm);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
// File generated via `make generate-builtins`
|
||||
static const struct CompactHashIndex processObjectTableIndex[141] = {
|
||||
{ 42, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 16, 130 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 19, 137 },
|
||||
{ -1, -1 },
|
||||
static const struct CompactHashIndex processObjectTableIndex[142] = {
|
||||
{ 43, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
@@ -27,43 +11,59 @@ static const struct CompactHashIndex processObjectTableIndex[141] = {
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 15, 129 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 18, 138 },
|
||||
{ -1, -1 },
|
||||
{ 45, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 3, 140 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 3, 141 },
|
||||
{ 1, 128 },
|
||||
{ -1, -1 },
|
||||
{ 57, -1 },
|
||||
{ 59, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 30, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 50, -1 },
|
||||
{ 27, -1 },
|
||||
{ 10, -1 },
|
||||
{ -1, -1 },
|
||||
{ 11, -1 },
|
||||
{ -1, -1 },
|
||||
{ 15, 136 },
|
||||
{ 31, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 52, -1 },
|
||||
{ 27, -1 },
|
||||
{ 12, -1 },
|
||||
{ -1, -1 },
|
||||
{ 19, -1 },
|
||||
{ -1, -1 },
|
||||
{ 14, 137 },
|
||||
{ -1, -1 },
|
||||
{ 36, -1 },
|
||||
{ -1, -1 },
|
||||
{ 38, -1 },
|
||||
{ 55, -1 },
|
||||
{ 35, -1 },
|
||||
{ 6, 139 },
|
||||
{ -1, -1 },
|
||||
{ 37, -1 },
|
||||
{ 53, -1 },
|
||||
{ 34, -1 },
|
||||
{ 6, 138 },
|
||||
{ -1, -1 },
|
||||
{ 49, -1 },
|
||||
{ 51, -1 },
|
||||
{ 4, -1 },
|
||||
{ 45, -1 },
|
||||
{ 47, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
@@ -75,23 +75,23 @@ static const struct CompactHashIndex processObjectTableIndex[141] = {
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 39, -1 },
|
||||
{ 40, -1 },
|
||||
{ -1, -1 },
|
||||
{ 36, -1 },
|
||||
{ 37, -1 },
|
||||
{ -1, -1 },
|
||||
{ 0, -1 },
|
||||
{ 12, 129 },
|
||||
{ 17, 131 },
|
||||
{ 38, -1 },
|
||||
{ 26, 135 },
|
||||
{ 16, 130 },
|
||||
{ 39, -1 },
|
||||
{ -1, -1 },
|
||||
{ 23, -1 },
|
||||
{ 13, -1 },
|
||||
{ 11, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 56, -1 },
|
||||
{ 58, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 47, -1 },
|
||||
{ 30, 136 },
|
||||
{ -1, -1 },
|
||||
{ 29, -1 },
|
||||
{ 22, -1 },
|
||||
@@ -105,45 +105,46 @@ static const struct CompactHashIndex processObjectTableIndex[141] = {
|
||||
{ 5, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 46, -1 },
|
||||
{ 48, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 14, 132 },
|
||||
{ 13, 131 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 9, -1 },
|
||||
{ 25, 134 },
|
||||
{ 25, 133 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 21, 135 },
|
||||
{ 21, 134 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ 44, 139 },
|
||||
{ 46, 140 },
|
||||
{ -1, -1 },
|
||||
{ 18, -1 },
|
||||
{ 17, -1 },
|
||||
{ 8, -1 },
|
||||
{ 26, -1 },
|
||||
{ 28, -1 },
|
||||
{ 31, 133 },
|
||||
{ 32, -1 },
|
||||
{ 32, 132 },
|
||||
{ 33, -1 },
|
||||
{ 40, -1 },
|
||||
{ 34, -1 },
|
||||
{ 41, -1 },
|
||||
{ 48, -1 },
|
||||
{ 51, -1 },
|
||||
{ 52, -1 },
|
||||
{ 42, -1 },
|
||||
{ 44, -1 },
|
||||
{ 49, -1 },
|
||||
{ 50, -1 },
|
||||
{ 53, -1 },
|
||||
{ 54, -1 },
|
||||
{ 55, -1 },
|
||||
{ 56, -1 },
|
||||
{ 57, -1 },
|
||||
};
|
||||
|
||||
static const struct HashTableValue processObjectTableValues[58] = {
|
||||
static const struct HashTableValue processObjectTableValues[60] = {
|
||||
{ "abort"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionAbort, 1 } },
|
||||
{ "allowedNodeEnvironmentFlags"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, Process_stubEmptySet } },
|
||||
{ "arch"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructArch } },
|
||||
@@ -154,16 +155,16 @@ static const struct HashTableValue processObjectTableValues[58] = {
|
||||
{ "browser"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructBrowser } },
|
||||
{ "chdir"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionChdir, 1 } },
|
||||
{ "config"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessConfigObject } },
|
||||
{ "debugPort"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processDebugPort, setProcessDebugPort } },
|
||||
{ "exitCode"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processExitCode, setProcessExitCode } },
|
||||
{ "title"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processTitle, setProcessTitle } },
|
||||
{ "cpuUsage"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCpuUsage, 1 } },
|
||||
{ "cwd"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCwd, 1 } },
|
||||
{ "debugPort"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processDebugPort, setProcessDebugPort } },
|
||||
{ "dlopen"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionDlopen, 1 } },
|
||||
{ "emitWarning"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_emitWarning, 1 } },
|
||||
{ "env"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructEnv } },
|
||||
{ "execArgv"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructExecArgv } },
|
||||
{ "execPath"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructExecPath } },
|
||||
{ "exit"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionExit, 1 } },
|
||||
{ "exitCode"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processExitCode, setProcessExitCode } },
|
||||
{ "features"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructFeatures } },
|
||||
{ "getActiveResourcesInfo"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_stubFunctionReturningArray, 0 } },
|
||||
{ "getegid"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functiongetegid, 0 } },
|
||||
@@ -174,6 +175,7 @@ static const struct HashTableValue processObjectTableValues[58] = {
|
||||
{ "hrtime"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessHrtimeObject } },
|
||||
{ "isBun"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructIsBun } },
|
||||
{ "mainModule"_s, ((static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Builtin|PropertyAttribute::Accessor|PropertyAttribute::Function)) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinGeneratorType, processObjectMainModuleCodeGenerator, 0 } },
|
||||
{ "memoryUsage"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructMemoryUsage } },
|
||||
{ "moduleLoadList"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, Process_stubEmptyArray } },
|
||||
{ "nextTick"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionNextTick, 1 } },
|
||||
{ "openStdin"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionOpenStdin, 0 } },
|
||||
@@ -187,6 +189,7 @@ static const struct HashTableValue processObjectTableValues[58] = {
|
||||
{ "stderr"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStderr } },
|
||||
{ "stdin"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStdin } },
|
||||
{ "stdout"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStdout } },
|
||||
{ "title"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processTitle, setProcessTitle } },
|
||||
{ "umask"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionUmask, 1 } },
|
||||
{ "uptime"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionUptime, 1 } },
|
||||
{ "version"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructVersion } },
|
||||
@@ -205,4 +208,4 @@ static const struct HashTableValue processObjectTableValues[58] = {
|
||||
};
|
||||
|
||||
static const struct HashTable processObjectTable =
|
||||
{ 58, 127, true, nullptr, processObjectTableValues, processObjectTableIndex };
|
||||
{ 60, 127, true, nullptr, processObjectTableValues, processObjectTableIndex };
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSMockImplementation;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSMockFunction;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMockWithImplementationCleanupData;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForProcessObject;
|
||||
|
||||
#include "ZigGeneratedClasses+DOMClientIsoSubspaces.h"
|
||||
/* --- bun --- */
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSMockImplementation;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSMockFunction;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForMockWithImplementationCleanupData;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForProcessObject;
|
||||
|
||||
#include "ZigGeneratedClasses+DOMIsoSubspaces.h"
|
||||
/*-- BUN --*/
|
||||
|
||||
@@ -162,7 +162,8 @@ it("process.umask()", () => {
|
||||
expect(process.umask()).toBe(orig);
|
||||
});
|
||||
|
||||
const versions = existsSync(import.meta.dir + "/../../src/generated_versions_list.zig");
|
||||
const generated_versions_list = join(import.meta.dir, "../../../../src/generated_versions_list.zig");
|
||||
const versions = existsSync(generated_versions_list);
|
||||
(versions ? it : it.skip)("process.versions", () => {
|
||||
// Generate a list of all the versions in the versions object
|
||||
// example:
|
||||
@@ -178,7 +179,7 @@ const versions = existsSync(import.meta.dir + "/../../src/generated_versions_lis
|
||||
// pub const c_ares = "0e7a5dee0fbb04080750cf6eabbe89d8bae87faa";
|
||||
// pub const usockets = "fafc241e8664243fc0c51d69684d5d02b9805134";
|
||||
const versions = Object.fromEntries(
|
||||
readFileSync(import.meta.dir + "/../../src/generated_versions_list.zig", "utf8")
|
||||
readFileSync(generated_versions_list, "utf8")
|
||||
.split("\n")
|
||||
.filter(line => line.startsWith("pub const") && !line.includes("zig") && line.includes(' = "'))
|
||||
.map(line => line.split(" = "))
|
||||
@@ -291,3 +292,140 @@ describe("process.onBeforeExit", () => {
|
||||
expect(stdout.toString().trim()).toBe("beforeExit: 0\nbeforeExit: 1\nexit: 2");
|
||||
});
|
||||
});
|
||||
|
||||
it("process.memoryUsage", () => {
|
||||
expect(process.memoryUsage()).toEqual({
|
||||
rss: expect.any(Number),
|
||||
heapTotal: expect.any(Number),
|
||||
heapUsed: expect.any(Number),
|
||||
external: expect.any(Number),
|
||||
arrayBuffers: expect.any(Number),
|
||||
});
|
||||
});
|
||||
|
||||
it("process.memoryUsage.rss", () => {
|
||||
expect(process.memoryUsage.rss()).toEqual(expect.any(Number));
|
||||
});
|
||||
|
||||
describe("process.cpuUsage", () => {
|
||||
it("works", () => {
|
||||
expect(process.cpuUsage()).toEqual({
|
||||
user: expect.any(Number),
|
||||
system: expect.any(Number),
|
||||
});
|
||||
});
|
||||
|
||||
it("works with diff", () => {
|
||||
const init = process.cpuUsage();
|
||||
for (let i = 0; i < 1000; i++) {}
|
||||
const delta = process.cpuUsage(init);
|
||||
expect(delta.user).toBeGreaterThan(0);
|
||||
expect(delta.system).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("works with diff of different structure", () => {
|
||||
const init = {
|
||||
user: 0,
|
||||
system: 0,
|
||||
};
|
||||
for (let i = 0; i < 1000; i++) {}
|
||||
const delta = process.cpuUsage(init);
|
||||
expect(delta.user).toBeGreaterThan(0);
|
||||
expect(delta.system).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("throws on invalid property", () => {
|
||||
const fixtures = [
|
||||
{},
|
||||
{ user: null },
|
||||
{ user: {} },
|
||||
{ user: "potato" },
|
||||
|
||||
{ user: 123 },
|
||||
{ user: 123, system: null },
|
||||
{ user: 123, system: "potato" },
|
||||
];
|
||||
for (const fixture of fixtures) {
|
||||
expect(() => process.cpuUsage(fixture)).toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
// Skipped on Linux because it seems to not change as often as on macOS
|
||||
it.skipIf(process.platform === "linux")("increases monotonically", () => {
|
||||
const init = process.cpuUsage();
|
||||
for (let i = 0; i < 10000; i++) {}
|
||||
const another = process.cpuUsage();
|
||||
expect(another.user).toBeGreaterThan(init.user);
|
||||
expect(another.system).toBeGreaterThan(init.system);
|
||||
});
|
||||
});
|
||||
|
||||
it("process.getegid", () => {
|
||||
expect(typeof process.getegid()).toBe("number");
|
||||
});
|
||||
it("process.geteuid", () => {
|
||||
expect(typeof process.geteuid()).toBe("number");
|
||||
});
|
||||
it("process.getgid", () => {
|
||||
expect(typeof process.getgid()).toBe("number");
|
||||
});
|
||||
it("process.getgroups", () => {
|
||||
expect(process.getgroups()).toBeInstanceOf(Array);
|
||||
expect(process.getgroups().length).toBeGreaterThan(0);
|
||||
});
|
||||
it("process.getuid", () => {
|
||||
expect(typeof process.getuid()).toBe("number");
|
||||
});
|
||||
|
||||
it("process.getuid", () => {
|
||||
expect(typeof process.getuid()).toBe("number");
|
||||
});
|
||||
|
||||
const undefinedStubs = [
|
||||
"_debugEnd",
|
||||
"_debugProcess",
|
||||
"_fatalException",
|
||||
"_linkedBinding",
|
||||
"_rawDebug",
|
||||
"_startProfilerIdleNotifier",
|
||||
"_stopProfilerIdleNotifier",
|
||||
"_tickCallback",
|
||||
];
|
||||
|
||||
for (const stub of undefinedStubs) {
|
||||
it(`process.${stub}`, () => {
|
||||
expect(process[stub]()).toBeUndefined();
|
||||
});
|
||||
}
|
||||
|
||||
const arrayStubs = ["getActiveResourcesInfo", "_getActiveRequests", "_getActiveHandles"];
|
||||
|
||||
for (const stub of arrayStubs) {
|
||||
it(`process.${stub}`, () => {
|
||||
expect(process[stub]()).toBeInstanceOf(Array);
|
||||
});
|
||||
}
|
||||
|
||||
const emptyObjectStubs = ["_preload_modules"];
|
||||
const emptySetStubs = ["allowedNodeEnvironmentFlags"];
|
||||
const emptyArrayStubs = ["moduleLoadList"];
|
||||
|
||||
for (const stub of emptyObjectStubs) {
|
||||
it(`process.${stub}`, () => {
|
||||
expect(process[stub]).toEqual({});
|
||||
});
|
||||
}
|
||||
|
||||
for (const stub of emptySetStubs) {
|
||||
it(`process.${stub}`, () => {
|
||||
expect(process[stub]).toBeInstanceOf(Set);
|
||||
expect(process[stub].size).toBe(0);
|
||||
});
|
||||
}
|
||||
|
||||
for (const stub of emptyArrayStubs) {
|
||||
it(`process.${stub}`, () => {
|
||||
expect(process[stub]).toBeInstanceOf(Array);
|
||||
expect(process[stub]).toHaveLength(0);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user