Mercurial > hg > thermostat-ng > web-client
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'); + }); + }); + });