Repository: denoland/deno
Pull request: fix(ext/node): support the optional `previousValue` parameter for process.cpuUsage()

The process.cpuUsage method when called with a parameter, is meant to compute the diff between the current cpu-usage and the supplied cpu-usage values

This should make [/tests/node_compat/test/pummel/test-process-cpuUsage.js](https://github.com/denoland/deno/blob/3849ace1d6b3f184645aaf077539ef7ef12f560c/tests/node_compat/test/pummel/test-process-cpuUsage.js) begin to pass

Changed files:
filename: ext/node/polyfills/process.ts
patch: @@ -4,7 +4,7 @@
 // TODO(petamoriken): enable prefer-primordials for node polyfills
 // deno-lint-ignore-file prefer-primordials
 
-import { core, internals } from "ext:core/mod.js";
+import { core, internals, primordials } from "ext:core/mod.js";
 import { initializeDebugEnv } from "ext:deno_node/internal/util/debuglog.ts";
 import {
   op_getegid,
@@ -17,9 +17,14 @@ import { warnNotImplemented } from "ext:deno_node/_utils.ts";
 import { EventEmitter } from "node:events";
 import Module, { getBuiltinModule } from "node:module";
 import { report } from "ext:deno_node/internal/process/report.ts";
-import { validateString } from "ext:deno_node/internal/validators.mjs";
+import {
+  validateNumber,
+  validateObject,
+  validateString,
+} from "ext:deno_node/internal/validators.mjs";
 import {
   ERR_INVALID_ARG_TYPE,
+  ERR_INVALID_ARG_VALUE_RANGE,
   ERR_OUT_OF_RANGE,
   ERR_UNKNOWN_SIGNAL,
   errnoException,
@@ -79,6 +84,8 @@ import type { BindingName } from "ext:deno_node/internal_binding/mod.ts";
 import { buildAllowedFlags } from "ext:deno_node/internal/process/per_thread.mjs";
 import { setProcess } from "ext:deno_node/_events.mjs";
 
+const { NumberMAX_SAFE_INTEGER } = primordials;
+
 const notImplementedEvents = [
   "multipleResolves",
   "worker",
@@ -144,6 +151,48 @@ function addReadOnlyProcessAlias(
   }
 }
 
+interface CpuUsage {
+  user: number;
+  system: number;
+}
+
+// Ensure that a previously passed in value is valid. Currently, the native
+// implementation always returns numbers <= Number.MAX_SAFE_INTEGER.
+function previousCpuUsageValueIsValid(num) {
+  return typeof num === "number" && num >= 0 && num <= NumberMAX_SAFE_INTEGER;
+}
+
+export function cpuUsage(previousValue?: CpuUsage): CpuUsage {
+  const cpuValues = Deno.cpuUsage(previousValue);
+
+  if (previousValue) {
+    if (!previousCpuUsageValueIsValid(previousValue.user)) {
+      validateObject(previousValue, "previousValue");
+
+      validateNumber(previousValue.user, "previousValue.user");
+      throw new ERR_INVALID_ARG_VALUE_RANGE(
+        "previousValue.user",
+        previousValue.user,
+      );
+    }
+
+    if (!previousCpuUsageValueIsValid(previousValue.system)) {
+      validateNumber(previousValue.system, "previousValue.system");
+      throw new ERR_INVALID_ARG_VALUE_RANGE(
+        "previousValue.system",
+        previousValue.system,
+      );
+    }
+
+    return {
+      user: cpuValues.user - previousValue.user,
+      system: cpuValues.system - previousValue.system,
+    };
+  }
+
+  return cpuValues;
+}
+
 function createWarningObject(
   warning: string,
   type: string,
@@ -574,9 +623,7 @@ process.config = {
   },
 };
 
-process.cpuUsage = function () {
-  return Deno.cpuUsage();
-};
+process.cpuUsage = cpuUsage;
 
 /** https://nodejs.org/api/process.html#process_process_cwd */
 process.cwd = cwd;

filename: tests/unit_node/process_test.ts
patch: @@ -6,6 +6,7 @@ import process, {
   arch as importedArch,
   argv,
   argv0 as importedArgv0,
+  cpuUsage as importedCpuUsage,
   env,
   execArgv as importedExecArgv,
   execPath as importedExecPath,
@@ -1145,9 +1146,56 @@ Deno.test(function importedExecPathTest() {
 });
 
 Deno.test("process.cpuUsage()", () => {
+  assert(process.cpuUsage.length === 1);
   const cpuUsage = process.cpuUsage();
   assert(typeof cpuUsage.user === "number");
   assert(typeof cpuUsage.system === "number");
+  const a = process.cpuUsage();
+  const b = process.cpuUsage(a);
+  assert(a.user > b.user);
+  assert(a.system > b.system);
+
+  assertThrows(
+    () => {
+      // @ts-ignore TS2322
+      process.cpuUsage({});
+    },
+    TypeError,
+  );
+
+  assertThrows(
+    () => {
+      // @ts-ignore TS2322
+      process.cpuUsage({ user: "1", system: 2 });
+    },
+    TypeError,
+  );
+  assertThrows(
+    () => {
+      // @ts-ignore TS2322
+      process.cpuUsage({ user: 1, system: "2" });
+    },
+    TypeError,
+  );
+
+  for (const invalidNumber of [-1, -Infinity, Infinity, NaN]) {
+    assertThrows(
+      () => {
+        process.cpuUsage({ user: invalidNumber, system: 2 });
+      },
+      RangeError,
+    );
+    assertThrows(
+      () => {
+        process.cpuUsage({ user: 2, system: invalidNumber });
+      },
+      RangeError,
+    );
+  }
+});
+
+Deno.test("importedCpuUsage", () => {
+  assert(importedCpuUsage === process.cpuUsage);
 });
 
 Deno.test("process.stdout.columns writable", () => {