Mercurial > hg > thermostat-ng > web-client
changeset 222:0e10eacbeeb7
Add byteman subview to jvm-info
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025146.html
author | Andrew Azores <aazores@redhat.com> |
---|---|
date | Fri, 22 Sep 2017 07:51:59 -0400 |
parents | 362ef36b1cef |
children | 57a4676a9343 |
files | mock-api/endpoints/jvm-byteman.endpoint.js src/app/components/jvm-info/byteman/byteman.component.js src/app/components/jvm-info/byteman/byteman.controller.js src/app/components/jvm-info/byteman/byteman.controller.spec.js src/app/components/jvm-info/byteman/byteman.html src/app/components/jvm-info/byteman/byteman.routing.js src/app/components/jvm-info/byteman/byteman.routing.spec.js src/app/components/jvm-info/byteman/byteman.service.js src/app/components/jvm-info/byteman/byteman.service.spec.js src/app/components/jvm-info/byteman/en.locale.yaml src/app/components/jvm-info/en.locale.yaml src/app/components/jvm-info/jvm-info.html |
diffstat | 12 files changed, 942 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mock-api/endpoints/jvm-byteman.endpoint.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,44 @@ +function jvmByteman (server) { + // web-gateway + var _ = require('lodash'); + server.init('jvmByteman'); + server.app.get('/jvm-byteman/0.0.1/status/jvms/:jvmId', function (req, res) { + server.logRequest('jvm-byteman', req); + + var jvmId = req.params.jvmId; + + var response = []; + var data = { + agentId: 'foo-agentId', + jvmId: jvmId, + timeStamp: { $numberLong: Date.now().toString() }, + rule: '', + listenPort: 9999 + }; + response.push(data); + + res.setHeader('Content-Type', 'application/json'); + res.send(JSON.stringify( + { + response: response + } + )); + }); + + // command channel + server.init('byteman-command'); + server.app.ws('/commands/v1/actions/byteman/systems/:systemId/agents/:agentId/jvms/:jvmId/sequence/:seqId', function (ws, req) { + server.logRequest('byteman-command', req); + ws.on('message', function (msg) { + ws.send(JSON.stringify( + { + payload: { + respType: 'OK' + } + } + )); + }); + }); +} + +module.exports = jvmByteman;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.component.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,36 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import BytemanController from './byteman.controller.js'; + +export default angular + .module('byteman', [BytemanController]) + .component('byteman', { + controller: 'BytemanController', + template: require('./byteman.html') + }) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.controller.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,96 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import service from './byteman.service.js'; + +class BytemanController { + constructor ($stateParams, $translate, bytemanService) { + 'ngInject'; + this.jvmId = $stateParams.jvmId; + this.systemId = $stateParams.systemId; + this._translate = $translate; + this._svc = bytemanService; + + this.loadedRule = ''; + } + + $onInit () { + this._updateRules(); + } + + $onDestroy () { + } + + _updateRules () { + return this._svc.getLoadedRules(this.jvmId) + .then(res => { + this.loadedRule = res; + this._clearInput(); + }); + } + + _clearInput () { + this.ruleText = ''; + } + + refresh () { + return this._updateRules(); + } + + unload () { + if (!this.loadedRule) { + return; + } + return this._svc.unloadRules(this.systemId, this.jvmId) + .then(() => this._updateRules()); + } + + push () { + return this._svc.loadRule(this.systemId, this.jvmId, this.ruleText) + .then(() => this._updateRules()); + } + + pull () { + return this._svc.getLoadedRules(this.jvmId) + .then(res => { + this.loadedRule = res; + if (res) { + this.ruleText = res; + } + }); + } + + generateTemplate () { + return this._translate('byteman.RULE_TEMPLATE') + .then(res => this.ruleText = res); + } +} + +export default angular + .module('byteman.controller', [service]) + .controller('BytemanController', BytemanController) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.controller.spec.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,183 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import controllerModule from './byteman.controller.js'; + +describe('BytemanController', () => { + + let ctrl, stateParams, translate, svc; + beforeEach(() => { + angular.mock.module(controllerModule); + + stateParams = { + jvmId: 'foo-jvmId', + systemId: 'foo-systemId' + }; + + translate = sinon.stub(); + translate.then = sinon.stub(); + translate.returns({ then: translate.then }); + + svc = { + getLoadedRules: sinon.stub(), + loadRule: sinon.stub(), + unloadRules: sinon.stub() + }; + + angular.mock.inject($controller => { + 'ngInject'; + ctrl = $controller('BytemanController', { + $stateParams: stateParams, + $translate: translate, + bytemanService: svc + }); + }); + }); + + describe('$onInit ()', () => { + it('should load injected rules', () => { + svc.getLoadedRules.should.not.be.called(); + svc.getLoadedRules.returns({ + then: sinon.stub().yields('fake rule') + }); + + ctrl.$onInit(); + + svc.getLoadedRules.should.be.calledOnce(); + svc.getLoadedRules.should.be.calledWith(stateParams.jvmId); + ctrl.loadedRule.should.equal('fake rule'); + }); + }); + + describe('_clearInput ()', () => { + it('should reset ruleText property to the empty string', () => { + ctrl.ruleText = 'foo'; + ctrl._clearInput(); + ctrl.ruleText.should.equal(''); + }); + }); + + describe('refresh ()', () => { + it('should load injected rules', () => { + svc.getLoadedRules.should.not.be.called(); + svc.getLoadedRules.returns({ + then: sinon.stub().yields('fake rule') + }); + + ctrl.refresh(); + + svc.getLoadedRules.should.be.calledOnce(); + svc.getLoadedRules.should.be.calledWith(stateParams.jvmId); + ctrl.loadedRule.should.equal('fake rule'); + }); + }); + + describe('unload ()', () => { + it('should do nothing if no loaded rule', () => { + svc.unloadRules.should.not.be.called(); + ctrl.unload(); + svc.unloadRules.should.not.be.called(); + }); + + it('should unload rules', () => { + svc.getLoadedRules.should.not.be.called(); + svc.getLoadedRules.returns({ + then: sinon.stub().yields('fake rule') + }); + ctrl.refresh(); + + svc.getLoadedRules.returns({ + then: sinon.stub().yields('') + }); + svc.unloadRules.returns({ + then: sinon.stub().yields() + }); + ctrl.unload(); + ctrl.loadedRule.should.equal(''); + }); + }); + + describe('push ()', () => { + it('should send local rule text to service', () => { + const injectedRule = 'injected rule'; + ctrl.ruleText = injectedRule; + svc.loadRule.returns({ + then: sinon.stub().yields() + }); + svc.getLoadedRules.returns({ + then: sinon.stub().yields(injectedRule) + }); + + ctrl.push(); + + svc.loadRule.should.be.calledOnce(); + svc.loadRule.should.be.calledWith(stateParams.systemId, stateParams.jvmId, injectedRule); + ctrl.loadedRule.should.equal(injectedRule); + }); + }); + + describe('pull ()', () => { + it('should pull injected rule into editor', () => { + const loadedRule = 'loaded rule'; + svc.getLoadedRules.returns({ + then: sinon.stub().yields(loadedRule) + }); + + ctrl.pull(); + + svc.getLoadedRules.should.be.calledOnce(); + svc.getLoadedRules.should.be.calledWith(stateParams.jvmId); + + ctrl.loadedRule.should.equal(loadedRule); + ctrl.ruleText.should.equal(loadedRule); + }); + + it('should not clobber rule text if no remotely injected rules', () => { + svc.getLoadedRules.returns({ + then: sinon.stub().yields() + }); + + ctrl.ruleText = 'locally edited rule'; + ctrl.pull(); + + svc.getLoadedRules.should.be.calledOnce(); + svc.getLoadedRules.should.be.calledWith(stateParams.jvmId); + + should(ctrl.loadedRule).be.undefined(); + ctrl.ruleText.should.equal('locally edited rule'); + }); + }); + + describe('generateTemplate ()', () => { + it('should set rule text from translate service', () => { + translate.then.yields('rule template'); + ctrl.generateTemplate(); + ctrl.ruleText.should.equal('rule template'); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.html Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,40 @@ +<div class="container-fluid" style="margin-top: 2vh;"> + <div class="col-md-8"> + + <div class="row"> + <div role="group" class="btn-group pull-right"> + <button type="button" class="btn btn-secondary" ng-click="$ctrl.refresh()"><span class="fa fa-refresh"></span></button> + <button type="button" class="btn btn-secondary" ng-click="$ctrl.unload()" translate>byteman.UNLOAD_BTN_LABEL</button> + </div> + </div> + + <div class="row"> + + <div class="form-group col-md-6"> + <label for="localRule" class="label label-info" translate>byteman.LOCAL_RULE_LABEL</label> + <textarea name="localRule" class="form-control" ng-model="$ctrl.ruleText" rows="8"/> + </div> + + <div role="group" class="btn-group col-md-1"> + <button type="button" class="btn btn-default" + ng-click="$ctrl.pull()" ng-disabled="!$ctrl.loadedRule" translate>byteman.PULL_BTN_LABEL</button> + <button type="button" class="btn btn-default" + ng-click="$ctrl.push()" ng-disabled="!$ctrl.ruleText.length" translate>byteman.PUSH_BTN_LABEL</button> + </div> + + <div class="form-group col-md-5"> + <label for="remoteRule" class="label label-info" translate>byteman.REMOTE_RULE_LABEL</label> + <textarea name="remoteRule" class="form-control" + translate-attr="{placeholder: 'byteman.NO_RULES_LABEL'}" ng-model="$ctrl.loadedRule" rows="8" readonly/> + </div> + + </div> + + <div class="row"> + <div role="group" class="btn-group pull-right"> + <button type="button" class="btn btn-secondary" ng-click="$ctrl.generateTemplate()" translate>byteman.GENERATE_RULE_BTN_LABEL</button> + </div> + </div> + + </div> +</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.routing.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,57 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +function config ($stateProvider) { + 'ngInject'; + + $stateProvider.state('jvmInfo.byteman', { + url: '/byteman', + component: 'byteman', + resolve: { + lazyLoad: ($q, $ocLazyLoad) => { + 'ngInject'; + return $q(resolve => { + require.ensure(['./byteman.component.js'], () => { + let module = require('./byteman.component.js'); + $ocLazyLoad.load({ name: module.default }); + resolve(module); + }); + }); + } + } + }); +} + +export { config }; + +export default angular + .module('byteman.routing', [ + 'ui.router', + 'oc.lazyLoad' + ]) + .config(config) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.routing.spec.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,77 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +describe('BytemanRouting', () => { + + let module = require('./byteman.routing.js'); + let stateProvider, args, q, ocLazyLoad; + beforeEach(() => { + angular.mock.module(module.default); + stateProvider = { + state: sinon.spy() + }; + module.config(stateProvider); + args = stateProvider.state.args[0]; + q = sinon.spy(); + ocLazyLoad = { + load: sinon.spy() + }; + }); + + describe('stateProvider', () => { + it('should call $stateProvider.state', () => { + stateProvider.state.should.be.calledOnce(); + }); + + it('should define a \'jvmInfo.byteman\' state', () => { + args[0].should.equal('jvmInfo.byteman'); + }); + + it('should map to /byteman', () => { + args[1].url.should.equal('/byteman'); + }); + + it('resolve should load byteman component', done => { + let resolveFn = args[1].resolve.lazyLoad[2]; + resolveFn.should.be.a.Function(); + resolveFn(q, ocLazyLoad); + q.should.be.calledOnce(); + + let deferred = q.args[0][0]; + deferred.should.be.a.Function(); + + let resolve = sinon.stub().callsFake(val => { + let mod = require('./byteman.component.js'); + ocLazyLoad.load.should.be.calledWith({ name: mod.default }); + val.should.equal(mod); + done(); + }); + deferred(resolve); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.service.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,141 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import services from 'shared/services/services.module.js'; +import config from 'shared/config/config.module.js'; +import urlJoin from 'url-join'; + +const LOAD_RULE_ACTION = 0; +const UNLOAD_RULE_ACTION = 1; +const INITIAL_LISTEN_PORT = -1; + +class BytemanService { + + constructor ($q, $http, gatewayUrl, commandChannelService) { + 'ngInject'; + this._q = $q; + this._http = $http; + this._gatewayUrl = gatewayUrl; + this._cmdChan = commandChannelService; + } + + getLoadedRules (jvmId) { + return this._getBytemanStatus(jvmId).then(res => { + if (!res) { + return ''; + } + return res.rule; + }); + } + + loadRule (systemId, jvmId, rule) { + return this._sendCmdChanRequest(systemId, jvmId, LOAD_RULE_ACTION, rule); + } + + unloadRules (systemId, jvmId) { + return this._sendCmdChanRequest(systemId, jvmId, UNLOAD_RULE_ACTION); + } + + _sendCmdChanRequest (systemId, jvmId, action, rule) { + let defer = this._q.defer(); + + this._q.all({ + jvmInfo: this._getJvmInfo(systemId, jvmId), + listenPort: this._getListenPort(jvmId) + }).then(result => { + const jvmInfo = result.jvmInfo; + const agentId = jvmInfo.agentId; + const pid = jvmInfo.jvmPid; + const port = result.listenPort; + + let path = urlJoin( + 'commands', + 'v1', + 'actions', + 'byteman', + 'systems', + systemId, + 'agents', + agentId, + 'jvms', + jvmId, + 'sequence', + this._cmdChan.sequence + ); + + let payload = { + 'byteman-action': action, + 'listen-port': port, + 'vm-pid': pid + }; + if (rule) { + payload['byteman-rule'] = rule; + } + this._cmdChan.sendMessage(path, payload).then( + success => { + defer.resolve({ + status: success.payload.respType.value === this._cmdChan.responseCodes.OK.value, + reason: success.payload.respType.message + }); + } + ); + }); + + return defer.promise; + } + + _getJvmInfo (systemId, jvmId) { + return this._http.get(urlJoin(this._gatewayUrl, 'jvms', '0.0.1', 'systems', systemId, 'jvms', jvmId)) + .then(res => { + return res.data.response[0]; + }); + } + + _getBytemanStatus (jvmId) { + return this._http.get(urlJoin(this._gatewayUrl, 'jvm-byteman', '0.0.1', 'status', 'jvms', jvmId)) + .then(res => { + return res.data.response[0]; + }); + } + + _getListenPort (jvmId) { + return this._getBytemanStatus(jvmId).then(res => { + if (!res) { + return INITIAL_LISTEN_PORT; + } + return res.listenPort; + }); + } +} + +export default angular + .module('byteman.service', [ + services, + config + ]) + .service('bytemanService', BytemanService) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/byteman.service.spec.js Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,248 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import serviceModule from './byteman.service.js'; +import servicesModule from 'shared/services/services.module.js'; + +describe('BytemanService', () => { + + let cmdChan; + beforeEach(() => { + angular.mock.module('configModule', $provide => { + 'ngInject'; + $provide.constant('gatewayUrl', 'http://example.com:1234'); + }); + + cmdChan = { + sendMessage: sinon.stub().returns({ + then: sinon.stub().yields({ + payload: { + respType: { + value: 'OK' + } + } + }) + }), + sequence: 5, + responseCodes: { + OK: { + value: 'OK' + } + } + }; + angular.mock.module(servicesModule, $provide => { + 'ngInject'; + $provide.constant('commandChannelService', cmdChan); + }); + + angular.mock.module(serviceModule); + }); + + let httpBackend, scope, svc; + beforeEach(inject(($httpBackend, $rootScope, bytemanService) => { + 'ngInject'; + httpBackend = $httpBackend; + + scope = $rootScope; + svc = bytemanService; + })); + + afterEach(() => { + httpBackend.verifyNoOutstandingExpectation(); + httpBackend.verifyNoOutstandingRequest(); + }); + + it('should exist', () => { + should.exist(svc); + }); + + describe('getLoadedRules (jvmId)', () => { + it('should resolve mock data', done => { + let response = { + response: [ + { + rule: 'loaded rule' + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId') + .respond(response); + svc.getLoadedRules('foo-jvmId').then(res => { + res.should.equal(response.response[0].rule); + done(); + }); + httpBackend.expectGET('http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId'); + httpBackend.flush(); + scope.$apply(); + }); + + it('should return empty string if no results', done => { + let response = { + response: [] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId') + .respond(response); + svc.getLoadedRules('foo-jvmId').then(res => { + res.should.equal(''); + done(); + }); + httpBackend.expectGET('http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId'); + httpBackend.flush(); + scope.$apply(); + }); + }); + + describe('loadRule (systemId, jvmId, rule)', () => { + it('should send rule in command channel request payload', done => { + let jvmInfo = { + response: [ + { + agentId: 'foo-agentId', + jvmPid: 100, + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId') + .respond(jvmInfo); + httpBackend.expectGET('http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId'); + + let bytemanStatus = { + response: [ + { + listenPort: 9999 + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId') + .respond(bytemanStatus); + httpBackend.expectGET('http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId'); + + svc.loadRule('foo-systemId', 'foo-jvmId', 'fake rule').then(res => { + cmdChan.sendMessage.should.be.calledOnce(); + cmdChan.sendMessage.should.be.calledWith( + 'commands/v1/actions/byteman/systems/foo-systemId/agents/foo-agentId/jvms/foo-jvmId/sequence/5', + { + 'byteman-action': 0, + 'byteman-rule': 'fake rule', + 'listen-port': 9999, + 'vm-pid': 100 + } + ); + res.should.deepEqual({ status: true, reason: undefined }); + done(); + }); + + httpBackend.flush(); + scope.$apply(); + }); + + it('should use listenPort:-1 if none in storage', done => { + let jvmInfo = { + response: [ + { + agentId: 'foo-agentId', + jvmPid: 100, + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId') + .respond(jvmInfo); + httpBackend.expectGET('http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId'); + + let bytemanStatus = { + response: [] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId') + .respond(bytemanStatus); + httpBackend.expectGET('http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId'); + + svc.loadRule('foo-systemId', 'foo-jvmId', 'fake rule').then(res => { + cmdChan.sendMessage.should.be.calledOnce(); + cmdChan.sendMessage.should.be.calledWith( + 'commands/v1/actions/byteman/systems/foo-systemId/agents/foo-agentId/jvms/foo-jvmId/sequence/5', + { + 'byteman-action': 0, + 'byteman-rule': 'fake rule', + 'listen-port': -1, + 'vm-pid': 100 + } + ); + res.should.deepEqual({ status: true, reason: undefined }); + done(); + }); + + httpBackend.flush(); + scope.$apply(); + }); + }); + + describe('unloadRules (systemId, jvmId)', () => { + it('should send unload rules request on command channel', done => { + let jvmInfo = { + response: [ + { + agentId: 'foo-agentId', + jvmPid: 100, + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId') + .respond(jvmInfo); + httpBackend.expectGET('http://example.com:1234/jvms/0.0.1/systems/foo-systemId/jvms/foo-jvmId'); + + let bytemanStatus = { + response: [ + { + listenPort: 9999 + } + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId') + .respond(bytemanStatus); + httpBackend.expectGET('http://example.com:1234/jvm-byteman/0.0.1/status/jvms/foo-jvmId'); + + svc.unloadRules('foo-systemId', 'foo-jvmId').then(res => { + cmdChan.sendMessage.should.be.calledOnce(); + cmdChan.sendMessage.should.be.calledWith( + 'commands/v1/actions/byteman/systems/foo-systemId/agents/foo-agentId/jvms/foo-jvmId/sequence/5', + { + 'byteman-action': 1, + 'listen-port': 9999, + 'vm-pid': 100 + } + ); + res.should.deepEqual({ status: true, reason: undefined }); + done(); + }); + + httpBackend.flush(); + scope.$apply(); + }); + }); + +}); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/byteman/en.locale.yaml Fri Sep 22 07:51:59 2017 -0400 @@ -0,0 +1,18 @@ +byteman: + LOCAL_RULE_LABEL: Local Rule + REMOTE_RULE_LABEL: Injected Rule + NO_RULES_LABEL: '<no-rules-loaded>' + PUSH_BTN_LABEL: '>' + PULL_BTN_LABEL: '<' + UNLOAD_BTN_LABEL: Unload Rule + GENERATE_RULE_BTN_LABEL: Generate Rule Template + RULE_TEMPLATE: | + RULE Thermostat byteman template rule for com.redhat.thermostat.main.Thermostat + CLASS com.redhat.thermostat.main.Thermostat + METHOD main + HELPER org.jboss.byteman.thermostat.helper.ThermostatHelper + AT ENTRY + IF true + DO + send("foo-marker", "action", "com.redhat.thermostat.main.Thermostat.main() called"); + ENDRULE
--- a/src/app/components/jvm-info/en.locale.yaml Thu Sep 21 17:08:50 2017 -0400 +++ b/src/app/components/jvm-info/en.locale.yaml Fri Sep 22 07:51:59 2017 -0400 @@ -35,3 +35,4 @@ MEMORY: Memory Usage GC: Garbage Collection IO: File I/O + BYTEMAN: Byteman
--- a/src/app/components/jvm-info/jvm-info.html Thu Sep 21 17:08:50 2017 -0400 +++ b/src/app/components/jvm-info/jvm-info.html Fri Sep 22 07:51:59 2017 -0400 @@ -133,6 +133,7 @@ <option value="jvmMemory" translate>jvmInfo.subview.MEMORY</option> <option value="jvmGc" translate>jvmInfo.subview.GC</option> <option value="jvmIo" translate>jvmInfo.subview.IO</option> + <option value="byteman" translate>jvmInfo.subview.BYTEMAN</option> </select> </div>