Repository: cloudant/couchbackup (js)

Issue:
Incorrect user-agent
## Bug Description

When debugging #379 it was discovered that the `user-agent` header is reporting `cloudant-node-sdk` instead of `cloudant-couchbackup`.

### 1. Steps to reproduce and the simplest code sample possible to demonstrate the issue

Check the `user-agent` header on any request.

### 2. What you expected to happen

The `user-agent` should report `cloudant-couchbackup` and some version metadata.

### 3. What actually happened

The `user-agent` is `cloudant-node-sdk` + version medata.

Although we set the header here: https://github.com/cloudant/couchbackup/blob/68c802b641673d0a29f560970fb70ce90e18cf56/includes/request.js#L134

The SDK sets the `user-agent` header later than that, so overrides the value provided by couchbackup. We need to set the header even later to make sure it is correct to assist with debugging.

## Environment details
- Version(s) that are affected by this issue.
    > 2.7.0
- Node.js version
    > 14.18.1


Pull request:
Add user-agent in interceptor
## Checklist

- [x] Tick to sign-off your agreement to the [Developer Certificate of Origin (DCO) 1.1](../blob/master/DCO1.1.txt)
- [x] Added tests for code changes _or_ test/build only changes
- [x] Updated the change log file (`CHANGES.md`|`CHANGELOG.md`) _or_ test/build only changes
- [x] Completed the PR template below:

## Description

Set the `user-agent` header to the correct value.

Fixes #380

## Approach

Set the `user-agent` header in an interceptor to avoid the SDK overriding it with its own value.

## Schema & API Changes

- "No change"

## Security and Privacy

- "No change"

## Testing

- Added new tests to assert `user-agent` header is correct.

## Monitoring and Logging

- Request header updated so easier to log/debug requests originating from couchbackup.


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 209c5ac..48ff06e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,6 @@
+# Unreleased
+- [FIXED] Corrected `user-agent` header on requests.
+
 # 2.7.0 (2021-09-14)
 - [UPGRADED] Cloudant client dependency from `@cloudant/cloudant` to `@ibm-cloud/cloudant`.
 
diff --git a/includes/request.js b/includes/request.js
index 4a913dd..54aff15 100644
--- a/includes/request.js
+++ b/includes/request.js
@@ -131,7 +131,6 @@ module.exports = {
     const serviceOpts = {
       authenticator: authenticator,
       timeout: opts.requestTimeout,
-      headers: { 'User-Agent': userAgent },
       // Axios performance options
       maxContentLength: -1
     };
@@ -180,6 +179,12 @@ module.exports = {
     // Add error interceptors to put URLs in error messages
     service.getHttpClient().interceptors.response.use(null, errorHelper);
 
+    // Add request interceptor to add user-agent (adding it with custom request headers gets overwritten)
+    service.getHttpClient().interceptors.request.use(function(requestConfig) {
+      requestConfig.headers['User-Agent'] = userAgent;
+      return requestConfig;
+    }, null);
+
     return { service: service, db: dbName, url: actUrl.toString() };
   }
 };


Test patch:
diff --git a/test/request.js b/test/request.js
index d7a86f5..4c4038f 100644
--- a/test/request.js
+++ b/test/request.js
@@ -24,11 +24,27 @@ const url = 'http://localhost:7777/testdb';
 const db = request.client(url, { parallelism: 1 });
 const timeoutDb = request.client(url, { parallelism: 1, requestTimeout: 500 });
 
-describe('#unit Check request response error callback', function() {
-  beforeEach('Clean nock', function() {
-    nock.cleanAll();
+beforeEach('Clean nock', function() {
+  nock.cleanAll();
+});
+
+describe('#unit Check request headers', function() {
+  it('should have a couchbackup user-agent', function(done) {
+    var couch = nock(url)
+      .matchHeader('user-agent', /couchbackup-cloudant\/\d+\.\d+\.\d+(?:-SNAPSHOT)? \(Node.js v\d+\.\d+\.\d+\)/)
+      .head('/good')
+      .reply(200);
+
+    db.service.headDocument({ db: db.db, docId: 'good' }).then(response => {
+      assert.ok(couch.isDone());
+      done();
+    }).catch(err => {
+      done(err);
+    });
   });
+});
 
+describe('#unit Check request response error callback', function() {
   it('should not callback with error for 200 response', function(done) {
     var couch = nock(url)
       .get('/good')