Repository: jira-node/node-jira-client
Pull request #15 (2016-01-23 16:21:33)

Add request timeout option
Should resolve PR to upstream project steves/node-jira#120

/cc @kernel72


Patch:
diff --git a/src/jira.js b/src/jira.js
index 46a0523..9c3dc2d 100644
--- a/src/jira.js
+++ b/src/jira.js
@@ -17,13 +17,23 @@ export default class JiraApi {
     this.protocol = options.protocol || 'http';
     this.host = options.host;
     this.port = options.port || 80;
-    this.username = options.username;
-    this.password = options.password;
     this.apiVersion = options.apiVersion || '2';
     this.base = options.base || '';
     this.strictSSL = options.strictSSL || true;
       // This is so we can fake during unit tests
     this.request = options.request || request;
+    this.baseOptions = {};
+
+    if (options.username && options.password) {
+      this.baseOptions.auth = {
+        user: options.username,
+        pass: options.password
+      };
+    }
+
+    if (options.timeout) {
+      this.baseOptions.timeout = options.timeout;
+    }
   }
 
   /**
@@ -47,6 +57,11 @@ export default class JiraApi {
    * authenticated?  Defaults to true.
    * @property {function} [request] - What method does this tool use to make its requests?
    * Defaults to request from request-promise
+   * @property {number} [timeout] - Integer containing the number of milliseconds to wait for a
+   * server to send response headers (and start the response body) before aborting the request. Note
+   * that if the underlying TCP connection cannot be established, the OS-wide TCP connection timeout
+   * will overrule the timeout option ([the default in Linux can be anywhere from 20-120 *
+   * seconds](http://www.sekuda.com/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout)).
    */
 
   /**
@@ -90,16 +105,10 @@ export default class JiraApi {
    * requests to jira
    */
   doRequest(requestOptions) {
-    let options = requestOptions;
-    if (this.username && this.password) {
-      options = {
-        auth: {
-          user: this.username,
-          pass: this.password
-        },
-        ...requestOptions
-      };
-    }
+    const options = {
+      ...this.baseOptions,
+      ...requestOptions
+    };
 
     return this.request(options)
       .then(response => {


Test patch:
diff --git a/test/.eslintrc b/test/.eslintrc
index e76e16f..6cfcd00 100644
--- a/test/.eslintrc
+++ b/test/.eslintrc
@@ -6,4 +6,7 @@
     "assert": true,
     "expect": true
   },
+  "rules": {
+    "no-unused-expressions": 0
+  }
 }
diff --git a/test/jira-tests.js b/test/jira-tests.js
index eb1e92d..3458ffd 100644
--- a/test/jira-tests.js
+++ b/test/jira-tests.js
@@ -23,10 +23,31 @@ describe('Jira API Tests', () => {
       expect(jira.protocol).to.eql('http');
       expect(jira.host).to.eql('jira.somehost.com');
       expect(jira.port).to.eql('8080');
-      expect(jira.username).to.eql('someusername');
-      expect(jira.password).to.eql('somepassword');
+      expect(jira.baseOptions.auth.user).to.eql('someusername');
+      expect(jira.baseOptions.auth.pass).to.eql('somepassword');
       expect(jira.apiVersion).to.eql('2.0');
     });
+
+    it('Constructor with no auth credentials', () => {
+      const {
+        username,
+        password,
+        ...options
+      } = getOptions();
+
+      const jira = new JiraApi(options);
+
+      expect(jira.baseOptions.auth).to.be.undefined;
+    });
+
+    it('Constructor with timeout', () => {
+      const jira = new JiraApi({
+        timeout: 2,
+        ...getOptions()
+      });
+
+      expect(jira.baseOptions.timeout).to.equal(2);
+    });
   });
 
   describe('makeRequestHeader Tests', () => {
@@ -86,16 +107,36 @@ describe('Jira API Tests', () => {
         return Promise.resolve(requestOptions);
       }
 
+      const username = 'someusername';
+      const password = 'somepassword';
+
       const jira = new JiraApi(getOptions({
-        username: 'someusername',
-        password: 'somepassword',
+        username,
+        password,
         request: dummyRequest
       }));
 
       jira.doRequest({})
         .then(resultObject => {
-          expect(resultObject.auth.user).to.eql(jira.username);
-          expect(resultObject.auth.pass).to.eql(jira.password);
+          expect(resultObject.auth.user).to.eql(username);
+          expect(resultObject.auth.pass).to.eql(password);
+        })
+        .should.notify(done);
+    });
+
+    it('doRequest times out with specified option', (done) => {
+      function dummyRequest(requestOptions) {
+        return Promise.resolve(requestOptions);
+      }
+
+      const jira = new JiraApi({
+        timeout: 2,
+        ...getOptions({ request: dummyRequest })
+      });
+
+      jira.doRequest({})
+        .then(resultObject => {
+          expect(resultObject.timeout).to.eql(2);
         })
         .should.notify(done);
     });