Repository: apache/incubator-openwhisk-client-js
Pull request #183 (2019-07-12 07:02:35)

Allow environment level set of default user-agent
Currently it is very difficult to set the user agent globally.
We have a library which is using this library, and changing the user-agent to something we can track requires modifying the options to every client call.

codecov-io: # [Codecov](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=h1) Report
> Merging [#183](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=desc) into [master](https://codecov.io/gh/apache/incubator-openwhisk-client-js/commit/feb6a887e8c613106713fbf414228d139fc14b20?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183/graphs/tree.svg?width=650&token=j2mPEx0Tkq&height=150&src=pr)](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master     #183   +/-   ##
=======================================
  Coverage   99.26%   99.26%           
=======================================
  Files          14       14           
  Lines         409      409           
=======================================
  Hits          406      406           
  Misses          3        3
```


| [Impacted Files](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/client.js](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183/diff?src=pr&el=tree#diff-bGliL2NsaWVudC5qcw==) | `98.85% <ø> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=footer). Last update [feb6a88...c7353d4](https://codecov.io/gh/apache/incubator-openwhisk-client-js/pull/183?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

jthomas: This makes sense to me (once the code review changes has been implemented).

Patch:
diff --git a/README.md b/README.md
index 88ba2b2..010e509 100644
--- a/README.md
+++ b/README.md
@@ -131,6 +131,7 @@ Client constructor will read values for the `apihost`, `namespace`, `api_key`, `
 - *__OW_IGNORE_CERTS*
 - *__OW_APIGW_TOKEN*
 - *__OW_APIGW_SPACE_SUID*
+- *__OW_USER_AGENT*
 
 ### User-Agent
 
diff --git a/lib/client.js b/lib/client.js
index 94ab447..debde18 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -141,7 +141,7 @@ class Client {
         url: this.pathUrl(path),
         rejectUnauthorized: !this.options.ignoreCerts,
         headers: {
-          'User-Agent': (options && options['User-Agent']) || 'openwhisk-client-js',
+          'User-Agent': (options && options['User-Agent']) || process.env['__OW_USER_AGENT'] || 'openwhisk-client-js',
           Authorization: header
         }
       }, options)


Test patch:
diff --git a/test/unit/actions.test.js b/test/unit/actions.test.js
index 63c7f72..8dbed3f 100644
--- a/test/unit/actions.test.js
+++ b/test/unit/actions.test.js
@@ -521,6 +521,24 @@ test('should pass through requested User-Agent header', t => {
   return actions.create({name: '12345', action, version, 'User-Agent': userAgent})
 })
 
+test('should pass through requested User-Agent header even when __OW_USER_AGENT is set', t => {
+  t.plan(1)
+  process.env['__OW_USER_AGENT'] = 'my-useragent'
+
+  const userAgent = 'userAgentShouldPassThroughPlease'
+  const client = {}
+  const actions = new Actions(client)
+  const action = 'function main() { // main function body};'
+  const version = '1.0.0'
+
+  client.request = (method, path, options) => {
+    t.is(options['User-Agent'], userAgent)
+    delete process.env['__OW_USER_AGENT']
+  }
+
+  return actions.create({name: '12345', action, version, 'User-Agent': userAgent})
+})
+
 test('should pass through exec.image parameter', t => {
   t.plan(1)
   const image = 'openwhisk/action-nodejs-v8:latest'
diff --git a/test/unit/namespaces.test.js b/test/unit/namespaces.test.js
index fab8a6a..4e5f2ad 100644
--- a/test/unit/namespaces.test.js
+++ b/test/unit/namespaces.test.js
@@ -93,6 +93,76 @@ test('should list all namespaces, NOT passing through user-agent header (variant
   return namespaces.list({noUserAgent: true})
 })
 
+test('should list all namespaces, using __OW_USER_AGENT', t => {
+  t.plan(3)
+  const client = {}
+  process.env['__OW_USER_AGENT'] = 'my-useragent'
+  client.request = async (method, path, options) => {
+    t.is(method, 'GET')
+    t.is(path, `namespaces`)
+
+    const parms = await new Client({api: 'aaa', api_key: 'aaa'}).params(method, path, options)
+    t.is(parms.headers['User-Agent'], 'my-useragent')
+    delete process.env['__OW_USER_AGENT']
+  }
+
+  const namespaces = new Namespaces(client)
+  return namespaces.list({})
+})
+
+test('should list all namespaces, NOT using __OW_USER_AGENT when noUserAgent true', t => {
+  t.plan(3)
+  const client = {}
+  process.env['__OW_USER_AGENT'] = 'my-useragent'
+  client.request = async (method, path, options) => {
+    t.is(method, 'GET')
+    t.is(path, `namespaces`)
+
+    const parms = await new Client({api: 'aaa', api_key: 'aaa', noUserAgent: true}).params(method, path, options)
+    t.is(parms.headers['User-Agent'], undefined)
+    delete process.env['__OW_USER_AGENT']
+  }
+
+  const namespaces = new Namespaces(client)
+  return namespaces.list({})
+})
+
+test('should list all namespaces, NOT using __OW_USER_AGENT when user-agent is passed through', t => {
+  t.plan(3)
+  const client = {}
+  const userAgent = 'userAgentShouldPassThroughPlease'
+  process.env['__OW_USER_AGENT'] = 'my-useragent'
+  client.request = async (method, path, options) => {
+    t.is(method, 'GET')
+    t.is(path, `namespaces`)
+
+    const parms = await new Client({api: 'aaa', api_key: 'aaa'}).params(method, path, options)
+    t.is(parms.headers['User-Agent'], userAgent)
+    delete process.env['__OW_USER_AGENT']
+  }
+
+  const namespaces = new Namespaces(client)
+  return namespaces.list({'User-Agent': userAgent})
+})
+
+test('should list all namespaces, NOT using __OW_USER_AGENT or user-agent when noUserAgent is true', t => {
+  t.plan(3)
+  const client = {}
+  const userAgent = 'userAgentShouldPassThroughPlease'
+  process.env['__OW_USER_AGENT'] = 'my-useragent'
+  client.request = async (method, path, options) => {
+    t.is(method, 'GET')
+    t.is(path, `namespaces`)
+
+    const parms = await new Client({api: 'aaa', api_key: 'aaa', noUserAgent: true}).params(method, path, options)
+    t.is(parms.headers['User-Agent'], undefined)
+    delete process.env['__OW_USER_AGENT']
+  }
+
+  const namespaces = new Namespaces(client)
+  return namespaces.list({'User-Agent': userAgent})
+})
+
 test('should retrieve namespace entities', t => {
   t.plan(16)
   const client = {}