# HG changeset patch # User Andrew Azores # Date 1507729145 14400 # Node ID e905e459ea483f15abfe9c0f7088d4e54cc2d69f # Parent 68d7308271aaababff3ef7a922d8605bfbf77829 Add jvm-cpu component Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025145.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-October/025348.html diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/en.locale.yaml --- a/src/app/components/jvm-info/en.locale.yaml Wed Oct 04 10:23:50 2017 -0400 +++ b/src/app/components/jvm-info/en.locale.yaml Wed Oct 11 09:39:05 2017 -0400 @@ -34,5 +34,6 @@ NONE: None MEMORY: Memory Usage GC: Garbage Collection + CPU: CPU Usage IO: File I/O BYTEMAN: Byteman diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/en.locale.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/en.locale.yaml Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,17 @@ +jvmCpu: + CARD_TITLE: JVM CPU Usage + REFRESH_RATE_LABEL: Refresh Rate + MAX_DATA_AGE_LABEL: Max Data Age + + chart: + UNITS: '%' + X_AXIS_LABEL: timestamp + Y_AXIS_LABEL: utilization + + refresh: + DISABLED: Disabled + SECONDS: '{SECONDS, plural, =0{0 Seconds} one{1 Second} other{# Seconds}}{DEFAULT, select, true{ (Default)} other{}}' + + dataAge: + SECONDS: '{SECONDS, plural, =0{0 Seconds} one{1 Second} other{# Seconds}}{DEFAULT, select, true{ (Default)} other{}}' + MINUTES: '{MINUTES, plural, =0{0 Minutes} one{1 Minute} other{# Minutes}}{DEFAULT, select, true{ (Default)} other{}}' diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.component.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.component.js Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,40 @@ +/** + * 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 controller from './jvm-cpu.controller.js'; +import service from './jvm-cpu.service.js'; + +export default angular + .module('jvmCpuComponent', [ + controller, + service + ]) + .component('jvmCpu', { + controller: 'JvmCpuController', + template: require('./jvm-cpu.html') + }) + .name; diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.controller.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.controller.js Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,176 @@ +/** + * 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 './jvm-cpu.service.js'; +import filters from 'shared/filters/filters.module.js'; + +class JvmCpuController { + constructor ($stateParams, jvmCpuService, $interval, $translate, dateFilter, DATE_FORMAT, metricToNumberFilter) { + 'ngInject'; + this.jvmId = $stateParams.jvmId; + this._svc = jvmCpuService; + this._interval = $interval; + this._translate = $translate; + this._dateFilter = dateFilter; + this._dateFormat = DATE_FORMAT; + this._metricToNumber = metricToNumberFilter; + + this._refreshRate = 2000; + this._dataAgeLimit = 30000; + + this._xData = ['timestamp']; + this._yData = ['CPU Load']; + this.data = { + xData: this._xData, + yData: this._yData + }; + } + + $onInit () { + this._makeConfig().then(() => this._start()); + } + + $onDestroy() { + this._stop(); + } + + _makeConfig () { + return this._translate([ + 'jvmCpu.chart.UNITS', + 'jvmCpu.chart.X_AXIS_LABEL', + 'jvmCpu.chart.Y_AXIS_LABEL' + ]).then(translations => { + this.config = { + chartId: 'jvm-cpu-chart', + units: translations['jvmCpu.chart.UNITS'], + axis: { + x: { + label: translations['jvmCpu.chart.X_AXIS_LABEL'], + show: true, + type: 'timeseries', + localtime: false, + tick: { + format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium), + count: 5 + } + }, + y: { + label: translations['jvmCpu.chart.Y_AXIS_LABEL'], + show: true, + tick: { + format: d => d + } + } + }, + tooltip: { + format: { + title: x => x, + value: y => y + } + }, + onmouseover: () => this._stop(), + onmouseout: () => this._start() + }; + }); + } + + _start () { + this._stop(); + this._update(); + this._refresh = this._interval(() => this._update(), this.refreshRate); + } + + _stop () { + if (angular.isDefined(this._refresh)) { + this._interval.cancel(this._refresh); + delete this._refresh; + } + } + + _update () { + this._svc.getJvmCpuData(this.jvmId).then(resp => { + let data = resp.data.response[0]; + let timestamp = this._metricToNumber(data.timeStamp); + this._xData.push(timestamp); + let load = data.cpuLoad; + this._yData.push(load); + + this._trimData(); + }); + } + + _trimData () { + let now = Date.now(); + let expiry = now - this._dataAgeLimit; + while (true) { + let oldest = this._xData[1]; + if (oldest < expiry) { + this._xData.splice(1, 1); + this._yData.splice(1, 1); + } else { + break; + } + } + } + + set refreshRate (val) { + this._stop(); + this._refreshRate = parseInt(val); + if (this._refreshRate > 0) { + this._start(); + } + } + + get refreshRate () { + return this._refreshRate.toString(); + } + + set dataAgeLimit (val) { + this._dataAgeLimit = val; + this._trimData(); + } + + get dataAgeLimit () { + return this._dataAgeLimit.toString(); + } + + multichartFn () { + return new Promise(resolve => { + this._svc.getJvmCpuData(this.jvmId).then(resp => { + resolve(resp.data.response[0].cpuLoad); + }); + }); + } +} + +export default angular + .module('jvmCpu.controller', [ + service, + filters + ]) + .controller('JvmCpuController', JvmCpuController) + .name; diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.controller.spec.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.controller.spec.js Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,285 @@ +/** + * 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 filtersModule from 'shared/filters/filters.module.js'; +import controllerModule from './jvm-cpu.controller.js'; + +describe('JvmCpuController', () => { + + beforeEach(angular.mock.module(filtersModule)); + beforeEach(angular.mock.module(controllerModule)); + + let interval, dateFilterStub, metricToNumberFilterStub, dateFormatSpy, svc, promise, ctrl, translate; + beforeEach(inject(($controller) => { + 'ngInject'; + + dateFilterStub = sinon.stub().returns('mockDate'); + dateFormatSpy = { + time: { + medium: sinon.spy() + } + }; + + metricToNumberFilterStub = sinon.stub().returns(Date.now()); + + interval = sinon.stub().returns('interval-sentinel'); + interval.cancel = sinon.spy(); + + promise = { then: sinon.spy() }; + svc = { getJvmCpuData: sinon.stub().returns(promise) }; + + translate = sinon.stub().returns({ + then: sinon.stub().yields({ + 'jvmCpu.chart.UNITS': 'microseconds', + 'jvmCpu.chart.X_AXIS_LABEL': 'timestamp', + 'jvmCpu.chart.Y_AXIS_LABEL': 'elapsed' + }).returns({ + then: sinon.stub().yields() + }) + }); + + ctrl = $controller('JvmCpuController', { + $stateParams: { jvmId: 'foo-jvmId' }, + jvmCpuService: svc, + $interval: interval, + $translate: translate, + dateFilter: dateFilterStub, + DATE_FORMAT: dateFormatSpy, + metricToNumberFilter: metricToNumberFilterStub + }); + ctrl.$onInit(); + })); + + it('should exist', () => { + should.exist(ctrl); + }); + + it('should update on init', () => { + svc.getJvmCpuData.should.be.calledOnce(); + svc.getJvmCpuData.should.be.calledWith('foo-jvmId'); + }); + + it('should call to service on update', () => { + svc.getJvmCpuData.should.be.calledOnce(); + promise.then.should.be.calledOnce(); + ctrl._update(); + svc.getJvmCpuData.should.be.calledTwice(); + promise.then.should.be.calledTwice(); + + promise.then.secondCall.should.be.calledWith(sinon.match.func); + ctrl.data.should.deepEqual({ + xData: ['timestamp'], + yData: ['CPU Load'] + }); + let successHandler = promise.then.secondCall.args[0]; + successHandler({ + data: { + response: [ + { + cpuLoad: 0.25, + programTicks: { $numberLong: '2' }, + timeStamp: { $numberLong: '100' } + } + ] + } + }); + }); + + it('should reset interval on refreshRate change', () => { + ctrl.should.have.ownProperty('_refresh'); + ctrl.refreshRate = '1'; + interval.should.be.calledWith(sinon.match.func, sinon.match(1)); + ctrl.should.have.ownProperty('_refresh'); + ctrl._refresh.should.equal('interval-sentinel'); + ctrl.refreshRate.should.equal('1'); + }); + + it('should trim data on dataAgeLimit change', () => { + sinon.spy(ctrl, '_trimData'); + ctrl._trimData.should.not.be.called(); + ctrl.dataAgeLimit = 10000; + ctrl._trimData.should.be.calledOnce(); + ctrl._trimData.restore(); + ctrl.dataAgeLimit.should.equal('10000'); + }); + + + it('should trim old data', () => { + let oldSample = { + cpuLoad: 0.125, + timestamp: 1 + }; + + let futureSample = { + cpuLoad: 0.25, + timestamp: Date.now() + 600000 + }; + + ctrl._xData = ['timestamp', oldSample.timestamp, futureSample.timestamp]; + ctrl._yData = ['utilization', oldSample.cpuLoad, futureSample.cpuLoad]; + ctrl.data = { + xData: ctrl._xData, + yData: ctrl._yData + }; + ctrl._trimData(); + + ctrl.data.should.deepEqual({ + xData: ['timestamp', futureSample.timestamp], + yData: ['utilization', futureSample.cpuLoad] + }); + }); + + it('should set interval on start', () => { + interval.should.be.calledOnce(); + interval.should.be.calledWith(sinon.match.func, '2000'); + interval.cancel.should.not.be.called(); + }); + + it('should disable when set refreshRate is called with a non-positive value', () => { + interval.cancel.should.not.be.called(); + + ctrl.refreshRate = '1'; + + interval.cancel.should.be.calledOnce(); + ctrl.should.have.ownProperty('_refresh'); + + ctrl.refreshRate = '-1'; + + interval.cancel.should.be.calledTwice(); + ctrl.should.not.have.ownProperty('_refresh'); + }); + + it('should call controller#update() on refresh', () => { + ctrl.refreshRate = 1; + let func = interval.args[0][0]; + let callCount = svc.getJvmCpuData.callCount; + func(); + svc.getJvmCpuData.callCount.should.equal(callCount + 1); + }); + + describe('_makeConfig', () => { + let cfg; + beforeEach(() => { + ctrl._makeConfig('fooCollector'); + cfg = ctrl.config; + }); + + it('should return a promise', () => { + ctrl._makeConfig().should.be.a.Promise(); + }); + + it('should set chartId', () => { + cfg.chartId.should.equal('jvm-cpu-chart'); + }); + + it('should use dateFilter with DATE_FORMAT.time.medium to format x ticks', () => { + let fn = cfg.axis.x.tick.format; + fn.should.be.a.Function(); + fn('fooTimestamp').should.equal('mockDate'); + dateFilterStub.should.be.calledWith('fooTimestamp', dateFormatSpy.time.medium); + }); + + it('should format y ticks directly', () => { + let fn = cfg.axis.y.tick.format; + fn.should.be.a.Function(); + fn(100).should.equal(100); + }); + + it('should set tooltip', () => { + let fmt = cfg.tooltip.format; + fmt.should.have.ownProperty('title'); + fmt.title.should.be.a.Function(); + fmt.should.have.ownProperty('value'); + fmt.value.should.be.a.Function(); + + fmt.title(100).should.equal(100); + fmt.value(200).should.equal(200); + }); + + it('should stop on mouseover', () => { + ctrl._start(); + let fn = cfg.onmouseover; + fn.should.be.a.Function(); + interval.cancel.should.be.calledOnce(); + fn(); + interval.cancel.should.be.calledTwice(); + }); + + it('should start on mouseout', () => { + ctrl._stop(); + let fn = cfg.onmouseout; + fn.should.be.a.Function(); + interval.should.be.calledOnce(); + fn(); + interval.should.be.calledTwice(); + }); + }); + + describe('ondestroy handler', () => { + it('should cancel refresh', () => { + ctrl._refresh = 'interval-sentinel'; + ctrl.$onDestroy(); + interval.cancel.should.be.calledWith('interval-sentinel'); + }); + + it('should do nothing if refresh is undefined', () => { + delete ctrl._refresh; + ctrl.$onDestroy(); + interval.cancel.should.not.be.called(); + }); + }); + + describe('multichartFn', () => { + it('should return a promise', () => { + let res = ctrl.multichartFn(); + res.should.be.a.Promise(); + }); + + it('should resolve jvm-cpu stat', done => { + promise.then.should.be.calledOnce(); + let res = ctrl.multichartFn(); + res.then(v => { + v.should.equal(0.4); + done(); + }); + promise.then.should.be.calledTwice(); + let prom = promise.then.secondCall.args[0]; + prom({ + data: { + response: [ + { + cpuLoad: 0.4, + programTicks: 200, + timeStamp: { $numberLong: '1000' } + } + ] + } + }); + }); + }); + +}); diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.html Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,46 @@ +
+ +
+
+ + +
+ +
+ + +
+
+ +
+
+ +
+
+
+ +
+
+ + +
+
+
+ +
+ +
+
diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.routing.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.routing.js Wed Oct 11 09:39:05 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.jvmCpu', { + url: '/jvm-cpu', + component: 'jvmCpu', + resolve: { + lazyLoad: ($q, $ocLazyLoad) => { + 'ngInject'; + return $q(resolve => { + require.ensure(['./jvm-cpu.component.js'], () => { + let module = require('./jvm-cpu.component.js'); + $ocLazyLoad.load({ name: module.default }); + resolve(module); + }); + }); + } + } + }); +} + +export { config }; + +export default angular + .module('jvmCpu.routing', [ + 'ui.router', + 'oc.lazyLoad' + ]) + .config(config) + .name; diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.routing.spec.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.routing.spec.js Wed Oct 11 09:39:05 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('JvmCpuRouting', () => { + + let module = require('./jvm-cpu.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.jvmCpu\' state', () => { + args[0].should.equal('jvmInfo.jvmCpu'); + }); + + it('should map to /jvm-cpu', () => { + args[1].url.should.equal('/jvm-cpu'); + }); + + it('resolve should load jvm-cpu 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('./jvm-cpu.component.js'); + ocLazyLoad.load.should.be.calledWith({ name: mod.default }); + val.should.equal(mod); + done(); + }); + deferred(resolve); + }); + }); + +}); diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.service.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.service.js Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,47 @@ +/** + * 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 configModule from 'shared/config/config.module.js'; +import urlJoin from 'url-join'; + +class JvmCpuService { + constructor ($http, gatewayUrl) { + 'ngInject'; + this.http = $http; + this.gatewayUrl = gatewayUrl; + } + + getJvmCpuData (jvmId) { + let params = { sort: '-timeStamp' }; + return this.http.get(urlJoin(this.gatewayUrl, 'jvm-cpu', '0.0.1', 'jvms', jvmId), { params: params }); + } +} + +export default angular + .module('jvmCpu.service', [ configModule ]) + .service('jvmCpuService', JvmCpuService) + .name; diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-cpu/jvm-cpu.service.spec.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-cpu/jvm-cpu.service.spec.js Wed Oct 11 09:39:05 2017 -0400 @@ -0,0 +1,79 @@ +/** + * 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 configModule from 'shared/config/config.module.js'; +import serviceModule from './jvm-cpu.service.js'; + +describe('JvmCpuService', () => { + + beforeEach(() => { + angular.mock.module(configModule, $provide => { + 'ngInject'; + $provide.constant('gatewayUrl', 'http://example.com:1234'); + }); + + angular.mock.module(serviceModule); + }); + + let httpBackend, scope, svc; + beforeEach(inject(($httpBackend, $rootScope, jvmCpuService) => { + 'ngInject'; + httpBackend = $httpBackend; + + scope = $rootScope; + svc = jvmCpuService; + })); + + afterEach(() => { + httpBackend.verifyNoOutstandingExpectation(); + httpBackend.verifyNoOutstandingRequest(); + }); + + it('should exist', () => { + should.exist(svc); + }); + + describe('getJvmCpuData(jvmId)', () => { + it('should resolve mock data', done => { + let expected = { + cpuLoad: 0.125, + programTicks: { $numberLong: '1000' }, + timeStamp: { $numberLong: '2000' } + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-cpu/0.0.1/jvms/foo-jvmId?sort=-timeStamp') + .respond(expected); + svc.getJvmCpuData('foo-jvmId').then(res => { + res.data.should.deepEqual(expected); + done(); + }); + httpBackend.expectGET('http://example.com:1234/jvm-cpu/0.0.1/jvms/foo-jvmId?sort=-timeStamp'); + httpBackend.flush(); + scope.$apply(); + }); + }); + +}); diff -r 68d7308271aa -r e905e459ea48 src/app/components/jvm-info/jvm-info.html --- a/src/app/components/jvm-info/jvm-info.html Wed Oct 04 10:23:50 2017 -0400 +++ b/src/app/components/jvm-info/jvm-info.html Wed Oct 11 09:39:05 2017 -0400 @@ -137,6 +137,7 @@ +