Repository: mcollina/autocannon
Pull request #491 (2023-07-02 20:38:40)

Add Node 20 to the test matrix

kibertoad: Curious to see if this passes, locally autocannon is failing on Node 20 for me, wonder if it's me or if it's autocannon.

Patch:
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index c4b709e..01b3a42 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -16,7 +16,7 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, windows-latest, macos-latest]
-        node-version: [14, 16, 18]
+        node-version: [14, 16, 18, 20]
 
     steps:
     - uses: actions/checkout@v3
@@ -41,7 +41,7 @@ jobs:
     runs-on: ubuntu-latest
     permissions:
       pull-requests: write
-      contents: write    
+      contents: write
     steps:
       - uses: fastify/github-action-merge-dependabot@v3
         with:
diff --git a/lib/httpRequestBuilder.js b/lib/httpRequestBuilder.js
index 1319902..efd86ec 100644
--- a/lib/httpRequestBuilder.js
+++ b/lib/httpRequestBuilder.js
@@ -72,6 +72,8 @@ function requestBuilder (defaults) {
 
     if (typeof body === 'string') {
       bodyBuf = Buffer.from(body)
+    } else if (typeof body === 'number') {
+      bodyBuf = Buffer.from(body + '')
     } else if (Buffer.isBuffer(body)) {
       bodyBuf = body
     } else if (body && Array.isArray(body._)) {
diff --git a/lib/printResult.js b/lib/printResult.js
index 279fd94..0563190 100644
--- a/lib/printResult.js
+++ b/lib/printResult.js
@@ -30,7 +30,7 @@ const printResult = (result, opts) => {
     head: asColor(chalk.cyan, ['Stat', '1%', '2.5%', '50%', '97.5%', 'Avg', 'Stdev', 'Min'])
   })
 
-  requests.push(asHighRow(chalk.bold('Req/Sec'), result.requests))
+  requests.push(asHighRow(chalk.bold('Req/Sec'), asNumber(result.requests)))
   requests.push(asHighRow(chalk.bold('Bytes/Sec'), asBytes(result.throughput)))
   logToLocalStr(requests.toString())
 
@@ -135,6 +135,18 @@ function asMs (stat) {
   return result
 }
 
+function asNumber (stat) {
+  const result = Object.create(null)
+  for (const k of Object.keys(stat)) {
+    result[k] = stat[k].toLocaleString(undefined, {
+      // to show all digits
+      maximumFractionDigits: 20
+    })
+  }
+
+  return result
+}
+
 function asBytes (stat) {
   const result = Object.create(stat)
 
diff --git a/package.json b/package.json
index 9561671..e4356aa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "autocannon",
-  "version": "7.11.0",
+  "version": "7.12.0",
   "description": "Fast HTTP benchmarking tool written in Node.js",
   "main": "autocannon.js",
   "bin": {


Test patch:
diff --git a/test/cli.test.js b/test/cli.test.js
index 3ef17b0..fe16b5d 100644
--- a/test/cli.test.js
+++ b/test/cli.test.js
@@ -254,3 +254,97 @@ test('run with workers', { skip: !hasWorkerSupport }, (t) => {
     })
     .on('end', t.end)
 })
+
+test('should run handle PUT bodies', (t) => {
+  t.test('"number" bodies work', t => {
+    t.plan(2)
+
+    const server = helper.startServer()
+    const url = 'http://localhost:' + server.address().port
+
+    const cmd = [
+      path.join(__dirname, '..'),
+      '-d', '1',
+      '-m', 'PUT',
+      '-H', 'content-type="application/x-www-form-urlencoded"',
+      '-b', '1',
+      url
+    ]
+    const child = childProcess.spawn(process.execPath, cmd, {
+      cwd: __dirname,
+      env: process.env,
+      stdio: ['ignore', 'pipe', 'pipe'],
+      detached: false
+    })
+
+    t.teardown(() => {
+      child.kill()
+    })
+
+    const outputLines = []
+    child
+      .stderr
+      .pipe(split())
+      .on('data', (line) => {
+        outputLines.push(line)
+      })
+      .on('end', () => {
+        t.equal(
+          outputLines.some(l => l === 'body must be either a string or a buffer'),
+          false
+        )
+        t.equal(
+          /.* requests in ([0-9]|\.)+s, .* read/.test(outputLines.pop()),
+          true
+        )
+        t.end()
+      })
+  })
+
+  t.test('"string" bodies work', t => {
+    t.plan(2)
+
+    const server = helper.startServer()
+    const url = 'http://localhost:' + server.address().port
+
+    const cmd = [
+      path.join(__dirname, '..'),
+      '-d', '1',
+      '-m', 'PUT',
+      '-H', 'content-type="application/x-www-form-urlencoded"',
+      '-b', '"1"',
+      url
+    ]
+    const child = childProcess.spawn(process.execPath, cmd, {
+      cwd: __dirname,
+      env: process.env,
+      stdio: ['ignore', 'pipe', 'pipe'],
+      detached: false
+    })
+
+    t.teardown(() => {
+      child.kill()
+    })
+
+    const outputLines = []
+    child
+      .stderr
+      .pipe(split())
+      .on('data', (line) => {
+        outputLines.push(line)
+      })
+      .on('end', () => {
+        t.equal(
+          outputLines.some(l => l === 'body must be either a string or a buffer'),
+          false
+        )
+        t.equal(
+          /.* requests in ([0-9]|\.)+s, .* read/.test(outputLines.pop()),
+          true
+        )
+        t.end()
+      })
+  })
+
+  t.end()
+})