Repository: mcollina/autocannon (js)

Issue:
Setting workers to >= 10 yields eventemitter warnings
```
root@DESKTOP-5KK9VIR:~/node/node# autocannon -w 10 localhost:3000
Running 10s test @ http://localhost:3000
10 connections
10 workers

⠋ running...(node:9067) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11
 unpipe listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)
(node:9067) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error liste
ners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(node:9067) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close liste
ners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(node:9067) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish list
eners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
⠦ running...
```

Pull request:
fix: do not show warnings when workers >= 10
Replaces ora with char-spinner to avoid the warning altogether.

### old explanation

I didn't actually figure out the root cause of why this is happening, and I do realize that making this initialization eager is doing something that's probably unnecessary unless workers are being used. Nevertheless, that's the most reliable way I found to fix this.

The problem seems to come from the bl package used by ora, which does some fancy stream manipulation, eventually leading to the warnings being generated.

Making the initialization of ora eager in the module root makes the issue disappear. 

Closes #337 

Patch:
diff --git a/lib/progressTracker.js b/lib/progressTracker.js
index 2265e5c..35c06e4 100644
--- a/lib/progressTracker.js
+++ b/lib/progressTracker.js
@@ -8,7 +8,7 @@
 const ProgressBar = require('progress')
 const Chalk = require('chalk')
 const testColorSupport = require('color-support')
-const ora = require('ora')
+const charSpinner = require('char-spinner')
 const printResult = require('./printResult')
 const { isMainThread } = require('./worker_threads')
 const defaults = {
@@ -79,13 +79,12 @@ function track (instance, opts) {
   })
 
   function showSpinner () {
-    spinner = ora('running...')
-    spinner.start()
+    spinner = charSpinner()
   }
 
   function hideSpinner () {
     if (spinner) {
-      spinner.stop()
+      clearInterval(spinner)
       spinner = null
     }
   }
diff --git a/package.json b/package.json
index e138c77..13469ed 100644
--- a/package.json
+++ b/package.json
@@ -42,12 +42,14 @@
     "busboy": "^0.3.1",
     "pre-commit": "^1.1.2",
     "proxyquire": "^2.1.3",
+    "sinon": "^9.2.4",
     "split2": "^3.2.2",
     "standard": "^16.0.3",
     "tap": "^14.10.8"
   },
   "dependencies": {
     "chalk": "^4.1.0",
+    "char-spinner": "^1.0.1",
     "cli-table3": "^0.6.0",
     "clone": "^2.1.2",
     "color-support": "^1.1.1",
@@ -61,7 +63,6 @@
     "manage-path": "^2.0.0",
     "minimist": "^1.2.0",
     "on-net-listen": "^1.1.1",
-    "ora": "^5.1.0",
     "pretty-bytes": "^5.4.1",
     "progress": "^2.0.3",
     "reinterval": "^1.1.0",


Test patch:
diff --git a/test/cli.test.js b/test/cli.test.js
index 5d906ec..ac2c5c2 100644
--- a/test/cli.test.js
+++ b/test/cli.test.js
@@ -205,7 +205,6 @@ test('run with workers', { skip: !hasWorkerSupport }, (t) => {
     /4 workers.*$/,
     /$/,
     /.*/,
-    /.*/, // spinner text is shown even though it's supposed to be cleared
     /Stat.*2\.5%.*50%.*97\.5%.*99%.*Avg.*Stdev.*Max.*$/,
     /.*/,
     /Latency.*$/,
diff --git a/test/progressTracker.test.stub.js b/test/progressTracker.test.js
similarity index 75%
rename from test/progressTracker.test.stub.js
rename to test/progressTracker.test.js
index fc4be71..11bd17d 100644
--- a/test/progressTracker.test.stub.js
+++ b/test/progressTracker.test.js
@@ -2,8 +2,12 @@
 
 const helper = require('./helper')
 const test = require('tap').test
+const { defaultMaxListeners } = require('events')
+const sinon = require('sinon')
 const progressTracker = require('../lib/progressTracker')
 const autocannon = require('../autocannon')
+const { hasWorkerSupport } = require('../lib/util')
+
 test('progress tracker should throw if no instance is provided', t => {
   t.plan(1)
   try {
@@ -94,3 +98,24 @@ test('should log resets', t => {
   })
   t.pass()
 })
+
+test(`should not emit warnings when using >= ${defaultMaxListeners} workers`, { skip: !hasWorkerSupport }, t => {
+  const server = helper.startServer()
+
+  const instance = autocannon({
+    url: `http://localhost:${server.address().port}`,
+    workers: defaultMaxListeners,
+    duration: 1
+  })
+
+  setTimeout(() => {
+    instance.stop()
+    t.false(emitWarningSpy.called)
+    emitWarningSpy.restore()
+    t.end()
+  }, 2000)
+
+  const emitWarningSpy = sinon.spy(process, 'emitWarning')
+
+  autocannon.track(instance)
+})