Repository: mcollina/autocannon
Pull request #437 (2022-03-22 21:22:44)

Add cli options to pass cert information
### Why
Currently the only way to pass custom cert information to autocannon is via the `tlsOptions` in the autocanno js api. This PR adds the ability to pass in common cert information from the cli tool so that consumers can easily use autocannon without writing a custom script.

### How
- Add logic in autocannon.js to parse arguments and read the relevant files
- Normalize all the arguments to be part of the `tlsOptions` key so that the `httpClient.js` can get the correct values


Patch:
diff --git a/README.md b/README.md
index 4c4a412..f666d78 100644
--- a/README.md
+++ b/README.md
@@ -124,8 +124,14 @@ Available options:
         Enabling this option will slow down the load testing.
   --renderStatusCodes
         Print status codes and their respective statistics.
+  --cert
+        Path to cert chain in pem format
+  --key
+        Path to private key for specified cert in pem format
+  --ca
+        Path to trusted ca certificates for the test. This argument accepts both a single file as well as a list of files
   --debug
-        Print connection errors to stderr.        
+        Print connection errors to stderr.
   -v/--version
         Print the version number.
   -h/--help
diff --git a/autocannon.js b/autocannon.js
index 0364799..f4ddd3a 100755
--- a/autocannon.js
+++ b/autocannon.js
@@ -191,6 +191,38 @@ function parseArguments (argvs) {
     }
   }
 
+  argv.tlsOptions = {}
+
+  if (argv.cert) {
+    try {
+      argv.tlsOptions.cert = fs.readFileSync(argv.cert)
+    } catch (err) {
+      throw new Error(`Failed to load cert file: ${err.message}`)
+    }
+  }
+
+  if (argv.key) {
+    try {
+      argv.tlsOptions.key = fs.readFileSync(argv.key)
+    } catch (err) {
+      throw new Error(`Failed to load key file: ${err.message}`)
+    }
+  }
+
+  if (argv.ca) {
+    if (typeof argv.ca === 'string') {
+      argv.ca = [argv.ca]
+    } else if (Array.isArray(argv.ca._)) {
+      argv.ca = argv.ca._
+    }
+
+    try {
+      argv.tlsOptions.ca = argv.ca.map(caPath => fs.readFileSync(caPath))
+    } catch (err) {
+      throw new Error(`Failed to load ca file: ${err.message}`)
+    }
+  }
+
   // This is to distinguish down the line whether it is
   // run via command-line or programmatically
   argv[Symbol.for('internal')] = true


Test patch:
diff --git a/test/argumentParsing.test.js b/test/argumentParsing.test.js
index 9102378..71c7c81 100644
--- a/test/argumentParsing.test.js
+++ b/test/argumentParsing.test.js
@@ -190,3 +190,46 @@ test('parse argument with input file and multiple workers', (t) => {
   t.equal(args.method, 'POST')
   t.equal(args.body, fs.readFileSync(inputPath, 'utf8'))
 })
+
+test('parse argument with cert, key and multiple ca paths', (t) => {
+  t.plan(5)
+
+  const certPath = 'test/cert.pem'
+  const keyPath = 'test/key.pem'
+  const caPath1 = 'help.txt'
+  const caPath2 = 'package.json'
+  const args = Autocannon.parseArguments([
+    '-m', 'POST',
+    '--cert', certPath,
+    '--key', keyPath,
+    '--ca', '[', caPath1, caPath2, ']',
+    'http://localhost/foo/bar'
+  ])
+
+  t.equal(args.url, 'http://localhost/foo/bar')
+  t.equal(args.method, 'POST')
+  t.same(args.tlsOptions.cert, fs.readFileSync(certPath))
+  t.same(args.tlsOptions.key, fs.readFileSync(keyPath))
+  t.same(args.tlsOptions.ca, [fs.readFileSync(caPath1), fs.readFileSync(caPath2)])
+})
+
+test('parse argument with cert, key and single ca path', (t) => {
+  t.plan(5)
+
+  const certPath = 'test/cert.pem'
+  const keyPath = 'test/key.pem'
+  const caPath = 'help.txt'
+  const args = Autocannon.parseArguments([
+    '-m', 'POST',
+    '--cert', certPath,
+    '--key', keyPath,
+    '--ca', caPath,
+    'http://localhost/foo/bar'
+  ])
+
+  t.equal(args.url, 'http://localhost/foo/bar')
+  t.equal(args.method, 'POST')
+  t.same(args.tlsOptions.cert, fs.readFileSync(certPath))
+  t.same(args.tlsOptions.key, fs.readFileSync(keyPath))
+  t.same(args.tlsOptions.ca, [fs.readFileSync(caPath)])
+})