changeset 142:d78f6d641b7b

Handle non-OK status response from kill-vm command Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-July/024282.html
author Andrew Azores <aazores@redhat.com>
date Mon, 31 Jul 2017 11:17:38 -0400
parents 78532770ce37
children 06baca9efd9a
files src/app/components/jvm-info/jvm-info.controller.js src/app/components/jvm-info/jvm-info.controller.spec.js src/app/components/jvm-info/kill-vm.service.js src/app/components/jvm-info/kill-vm.service.spec.js src/app/shared/services/command-channel.service.js src/app/shared/services/command-channel.service.spec.js
diffstat 6 files changed, 171 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/app/components/jvm-info/jvm-info.controller.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/components/jvm-info/jvm-info.controller.js	Mon Jul 31 11:17:38 2017 -0400
@@ -71,8 +71,13 @@
 
   killVm () {
     this.killVmService.killVm(this.systemId, this.jvmInfo.agentId, this.jvmId, this.jvmInfo.jvmPid).then(
-      success => {
-        this.showErr = false;
+      response => {
+        if (response.status) {
+          this.showErr = false;
+        } else {
+          this.showErr = true;
+          this.errMessage = response.reason;
+        }
       },
       failure => {
         this.showErr = true;
--- a/src/app/components/jvm-info/jvm-info.controller.spec.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/components/jvm-info/jvm-info.controller.spec.js	Mon Jul 31 11:17:38 2017 -0400
@@ -132,11 +132,22 @@
       killPromise.then.should.be.calledOnce();
       killPromise.then.should.be.calledWith(sinon.match.func, sinon.match.func);
       let fn = killPromise.then.args[0][0];
-      fn();
+      fn({ status:true });
       ctrl.showErr.should.be.false();
     });
 
-    it('should show error and set message on success', () => {
+    it('should show error and message if request succeeds with unsuccessful status', () => {
+      ctrl.showErr = true;
+      ctrl.killVm();
+      killPromise.then.should.be.calledOnce();
+      killPromise.then.should.be.calledWith(sinon.match.func, sinon.match.func);
+      let fn = killPromise.then.args[0][0];
+      fn({ status:false, reason:'some reason' });
+      ctrl.showErr.should.be.true();
+      ctrl.errMessage.should.equal('some reason');
+    });
+
+    it('should show error and set message on failure', () => {
       ctrl.showErr = false;
       ctrl.killVm();
       killPromise.then.should.be.calledOnce();
--- a/src/app/components/jvm-info/kill-vm.service.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/components/jvm-info/kill-vm.service.js	Mon Jul 31 11:17:38 2017 -0400
@@ -59,7 +59,15 @@
         this.getPath(systemId, agentId, jvmId),
         'com.redhat.thermostat.killvm.agent.internal.KillVmReceiver',
         { 'vm-pid': jvmPid }
-      ).then(success => resolve(success.payload.respType === 'OK') , reject);
+      ).then(
+        success => {
+          resolve({
+            status: success.payload.respType.value === this.commandChannel.responseCodes.OK.value,
+            reason: success.payload.respType.message
+          });
+        },
+        reject
+      );
     });
   }
 }
--- a/src/app/components/jvm-info/kill-vm.service.spec.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/components/jvm-info/kill-vm.service.spec.js	Mon Jul 31 11:17:38 2017 -0400
@@ -43,6 +43,20 @@
       commandChannel.promise = promise;
       commandChannel.sendMessage = sinon.stub().returns(promise.promise);
       commandChannel.sequence = 444;
+      commandChannel.responseCodes = {
+        OK: {
+          value: 'OK',
+          message: 'Request succeeded'
+        },
+        ERROR: {
+          value: 'ERROR',
+          message: 'Request failed for unknown reason'
+        },
+        AUTH_FAIL: {
+          value: 'AUTH_FAIL',
+          message: 'Request failed due to authentication or authorization issues'
+        }
+      };
       svc = killVmService;
     });
   });
@@ -65,14 +79,18 @@
 
     it('should resolve true on command channel success', done => {
       svc.killVm('foo').then(success => {
-        success.should.be.true();
+        success.should.have.ownProperty('status');
+        success.status.should.be.true();
         done();
       });
       commandChannel.promise.resolve({
         type: 100,
         sequence: 1,
         payload: {
-          respType: 'OK'
+          respType: {
+            value: 'OK',
+            message: 'Request succeeded'
+          }
         }
       });
       scope.$apply();
@@ -80,14 +98,41 @@
 
     it('should resolve false on command channel response error', done => {
       svc.killVm('foo', 'bar', 'baz').then(success => {
-        success.should.be.false();
+        success.should.have.ownProperty('status');
+        success.status.should.be.false();
+        success.should.have.ownProperty('reason');
+        success.reason.should.equal('Request failed for unknown reason');
         done();
       });
       commandChannel.promise.resolve({
         type: 100,
         sequence: 1,
         payload: {
-          respType: 'ERROR'
+          respType: {
+            value: 'ERROR',
+            message: 'Request failed for unknown reason'
+          }
+        }
+      });
+      scope.$apply();
+    });
+
+    it('should resolve false on command channel response auth fail', done => {
+      svc.killVm('foo', 'bar', 'baz').then(success => {
+        success.should.have.ownProperty('status');
+        success.status.should.be.false();
+        success.should.have.ownProperty('reason');
+        success.reason.should.equal('Request failed due to authentication or authorization issues');
+        done();
+      });
+      commandChannel.promise.resolve({
+        type: 100,
+        sequence: 1,
+        payload: {
+          respType: {
+            value: 'AUTH_FAIL',
+            message: 'Request failed due to authentication or authorization issues'
+          }
         }
       });
       scope.$apply();
@@ -101,6 +146,27 @@
       commandChannel.promise.reject('fooFailure');
       scope.$apply();
     });
+
+    it('should handle unknown response type', done => {
+      svc.killVm('foo', 'bar', 'baz').then(success => {
+        success.should.have.ownProperty('status');
+        success.status.should.be.false();
+        success.should.have.ownProperty('reason');
+        success.reason.should.equal('Request failed with unknown response type');
+        done();
+      });
+      commandChannel.promise.resolve({
+        type: 100,
+        sequence: 1,
+        payload: {
+          respType: {
+            value: 'UNKNOWN',
+            message: 'Request failed with unknown response type'
+          }
+        }
+      });
+      scope.$apply();
+    });
   });
 
 });
--- a/src/app/shared/services/command-channel.service.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/shared/services/command-channel.service.js	Mon Jul 31 11:17:38 2017 -0400
@@ -41,6 +41,15 @@
     this.setCredentials('bar-client-user', 'client-pwd');
   }
 
+  get responseCodes () {
+    let responseCodes = [];
+    responseCodes.OK = Object.freeze({ value: 'OK', message: 'Request succeeded' });
+    responseCodes.ERROR = Object.freeze({ value: 'ERROR', message: 'Request failed for unknown reason' });
+    responseCodes.AUTH_FAIL = Object.freeze({ value: 'AUTH_FAIL', message: 'Failed due to authentication or authorization issues' });
+    responseCodes.UNKNOWN = Object.freeze({ value: 'UNKNOWN', message: 'Request failed with unknown response type' });
+    return Object.freeze(responseCodes);
+  }
+
   setCredentials (username, password) {
     this.username = username;
     this.password = password;
@@ -109,7 +118,13 @@
     socket.addEventListener('message', message => {
       socket.removeEventListener('close', closeFn);
       socket.close();
-      defer.resolve(JSON.parse(message.data));
+      let data = JSON.parse(message.data);
+      if (this.responseCodes.hasOwnProperty(data.payload.respType)) {
+        data.payload.respType = this.responseCodes[data.payload.respType];
+      } else {
+        data.payload.respType = this.responseCodes.UNKNOWN;
+      }
+      defer.resolve(data);
     });
     return defer.promise;
   }
--- a/src/app/shared/services/command-channel.service.spec.js	Thu Jul 20 11:53:35 2017 -0400
+++ b/src/app/shared/services/command-channel.service.spec.js	Mon Jul 31 11:17:38 2017 -0400
@@ -108,15 +108,29 @@
       }));
     });
 
-    it('should resolve with socket response', done => {
+    it('should resolve with socket response respType replaced', done => {
       svc.sendMessage('foo', 'bar').then(v => {
-        v.should.deepEqual({ payload: 'fooMessage' });
+        v.should.deepEqual({ payload: { respType: { value: 'OK', message: 'Request succeeded' } } });
         done();
       });
       webSocketFactory.addEventListener.should.be.calledWith('message', sinon.match.func);
       webSocketFactory.removeEventListener.should.not.be.called();
       let onmessage = webSocketFactory.addEventListener.withArgs('message').args[0][1];
-      onmessage({ data: JSON.stringify({ payload: 'fooMessage' }) });
+      onmessage({ data: JSON.stringify({ payload: { respType: 'OK' }}) });
+      webSocketFactory.close.should.be.calledOnce();
+      webSocketFactory.removeEventListener.should.be.calledWith('close');
+      scope.$apply();
+    });
+
+    it('should resolve with socket response respType replaced when respType is not recognized', done => {
+      svc.sendMessage('foo', 'bar').then(v => {
+        v.should.deepEqual({ payload: { respType: { value: 'UNKNOWN', message: 'Request failed with unknown response type' } } });
+        done();
+      });
+      webSocketFactory.addEventListener.should.be.calledWith('message', sinon.match.func);
+      webSocketFactory.removeEventListener.should.not.be.called();
+      let onmessage = webSocketFactory.addEventListener.withArgs('message').args[0][1];
+      onmessage({ data: JSON.stringify({ payload: { respType: 'FOO_RESPONSE' }}) });
       webSocketFactory.close.should.be.calledOnce();
       webSocketFactory.removeEventListener.should.be.calledWith('close');
       scope.$apply();
@@ -182,4 +196,43 @@
     });
   });
 
+  describe('responseCodes', () => {
+    it('should enumerate the expected response types', () => {
+      svc.responseCodes.should.have.size(4);
+
+      svc.responseCodes.should.have.ownProperty('OK');
+      svc.responseCodes.OK.value.should.equal('OK');
+      svc.responseCodes.OK.message.should.not.equal('');
+
+      svc.responseCodes.should.have.ownProperty('ERROR');
+      svc.responseCodes.ERROR.value.should.equal('ERROR');
+      svc.responseCodes.ERROR.message.should.not.equal('');
+
+      svc.responseCodes.should.have.ownProperty('AUTH_FAIL');
+      svc.responseCodes.AUTH_FAIL.value.should.equal('AUTH_FAIL');
+      svc.responseCodes.AUTH_FAIL.message.should.not.equal('');
+
+      svc.responseCodes.should.have.ownProperty('UNKNOWN');
+      svc.responseCodes.UNKNOWN.value.should.equal('UNKNOWN');
+      svc.responseCodes.UNKNOWN.message.should.not.equal('');
+    });
+
+    it('should be read-only', () => {
+      should.throws(() => {
+        svc.responseCodes = [];
+      }, 'property should not be assignable');
+
+      should.throws(() => {
+        svc.responseCodes.ADDED = {
+          value: 'ADDED',
+          message: 'Added a new response code'
+        };
+      }, 'property should be immutable');
+
+      should.throws(() => {
+        svc.responseCodes.OK.value = 'NOK';
+      }, 'values should be immutable');
+    });
+  });
+
 });