Mercurial > hg > thermostat-ng > web-client
changeset 195:ce6984e324a1
Add jvm-io component
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024903.html
author | Andrew Azores <aazores@redhat.com> |
---|---|
date | Tue, 12 Sep 2017 12:53:42 -0400 |
parents | 1a1cf7a34a05 |
children | a9b83aee75b0 |
files | mock-api/endpoints/jvm-io.endpoint.js src/app/components/jvm-info/en.locale.yaml src/app/components/jvm-info/jvm-info.html src/app/components/jvm-info/jvm-io/en.locale.yaml src/app/components/jvm-info/jvm-io/jvm-io.component.js src/app/components/jvm-info/jvm-io/jvm-io.controller.js src/app/components/jvm-info/jvm-io/jvm-io.controller.spec.js src/app/components/jvm-info/jvm-io/jvm-io.html src/app/components/jvm-info/jvm-io/jvm-io.routing.js src/app/components/jvm-info/jvm-io/jvm-io.routing.spec.js src/app/components/jvm-info/jvm-io/jvm-io.service.js src/app/components/jvm-info/jvm-io/jvm-io.service.spec.js |
diffstat | 12 files changed, 872 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mock-api/endpoints/jvm-io.endpoint.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,32 @@ +function jvmIo (server) { + var _ = require('lodash'); + server.init('jvmIo'); + + server.app.get('/jvm-io/0.0.1/jvms/:jvmId', function (req, res, next) { + server.logRequest('jvm-io', req); + + var jvmId = req.params.jvmId; + + var response = [ + { + agentId: 'foo-agentId', + jvmId: jvmId, + timeStamp: { $numberLong: Date.now().toString() }, + charactersRead: { $numberLong: _.floor((Math.random() * 10000000)).toString() }, + charactersWritten: { $numberLong: _.floor((Math.random() * 10000000)).toString() }, + readSysCalls: { $numberLong: _.floor((Math.random() * 25000)).toString() }, + writeSysCalls: { $numberLong: _.floor((Math.random() * 120000)).toString() } + } + ]; + + res.setHeader('Content-Type', 'application/json'); + res.send(JSON.stringify( + { + response: response + } + )); + next(); + }); +} + +module.exports = jvmIo;
--- a/src/app/components/jvm-info/en.locale.yaml Mon Sep 11 13:59:43 2017 -0400 +++ b/src/app/components/jvm-info/en.locale.yaml Tue Sep 12 12:53:42 2017 -0400 @@ -34,3 +34,4 @@ NONE: None MEMORY: Memory Usage GC: Garbage Collection + IO: File I/O
--- a/src/app/components/jvm-info/jvm-info.html Mon Sep 11 13:59:43 2017 -0400 +++ b/src/app/components/jvm-info/jvm-info.html Tue Sep 12 12:53:42 2017 -0400 @@ -133,6 +133,7 @@ <option value="" translate>jvmInfo.subview.NONE</option> <option value="jvmMemory" translate>jvmInfo.subview.MEMORY</option> <option value="jvmGc" translate>jvmInfo.subview.GC</option> + <option value="jvmIo" translate>jvmInfo.subview.IO</option> </select> </div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/en.locale.yaml Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,25 @@ +jvmIo: + + REFRESH_RATE_LABEL: Refresh Rate + MAX_DATA_AGE_LABEL: Max Data Age + + 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{}}' + + chart: + TITLE: JVM I/O + X_LABEL: Timestamp + Y1_LABEL: Characters + Y2_LABEL: System Calls + + metrics: + timestamp: Date + charactersRead: Characters Read + charactersWritten: Characters Written + readSysCalls: Read System Calls + writeSysCalls: Write System Calls
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.component.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,43 @@ +/** + * 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-io.controller.js'; +import service from './jvm-io.service.js'; + +export default angular + .module('jvmIo.component', [ + controller, + service + ]) + .component('jvmIo', { + bindings: { + jvmId: '<' + }, + controller: 'JvmIoController', + template: require('./jvm-io.html') + }) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.controller.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,192 @@ +/** + * 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 'c3'; +import service from './jvm-io.service.js'; +import services from 'shared/services/services.module.js'; +import filters from 'shared/filters/filters.module.js'; + +class JvmIoController { + constructor (jvmIoService, $interval, $translate, dateFilter, DATE_FORMAT, metricToNumberFilter) { + 'ngInject'; + this._svc = jvmIoService; + this._interval = $interval; + this._translate = $translate; + this._dateFilter = dateFilter; + this._dateFormat = DATE_FORMAT; + this._metricToNumber = metricToNumberFilter; + + this._refreshRate = 1000; + this._dataAgeLimit = 30000; + this._makeChartConfig().then(() => this._start()); + } + + $onDestroy () { + this._stop(); + } + + _makeChartConfig () { + return this._translate([ + 'jvmIo.chart.X_LABEL', + 'jvmIo.chart.Y1_LABEL', + 'jvmIo.chart.Y2_LABEL', + + 'jvmIo.metrics.timestamp', + 'jvmIo.metrics.charactersRead', + 'jvmIo.metrics.charactersWritten', + 'jvmIo.metrics.readSysCalls', + 'jvmIo.metrics.writeSysCalls', + ]).then(translations => { + this.config = { + type: 'line', + chartId: 'jvm-io-chart', + grid: { + y: { + show: true + } + }, + axis: { + x: { + label: translations['jvmIo.chart.X_LABEL'], + type: 'timeseries', + localtime: false, + tick: { + format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium), + count: 5 + } + }, + y: { + label: translations['jvmIo.chart.Y1_LABEL'], + tick: { + format: d => d + } + }, + y2: { + show: true, + label: translations['jvmIo.chart.Y2_LABEL'], + tick: { + format: d => d + } + } + }, + tooltip: { + format: { + title: x => x, + value: y => y + } + }, + data: { + x: translations['jvmIo.metrics.timestamp'], + rows: [ + [ + translations['jvmIo.metrics.timestamp'], + translations['jvmIo.metrics.charactersRead'], + translations['jvmIo.metrics.charactersWritten'], + translations['jvmIo.metrics.readSysCalls'], + translations['jvmIo.metrics.writeSysCalls'] + ] + ] + } + }; + this.config.data.axes = {}; + this.config.data.axes[translations['jvmIo.metrics.charactersRead']] = 'y'; + this.config.data.axes[translations['jvmIo.metrics.charactersWritten']] = 'y'; + this.config.data.axes[translations['jvmIo.metrics.readSysCalls']] = 'y2'; + this.config.data.axes[translations['jvmIo.metrics.writeSysCalls']] = 'y2'; + }); + } + + 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(); + } + + _start () { + this._stop(); + this._refresh = this._interval(() => this._update(), this._refreshRate); + this._update(); + } + + _stop () { + if (angular.isDefined(this._refresh)) { + this._interval.cancel(this._refresh); + delete this._refresh; + } + } + + _trimData () { + let now = Date.now(); + let limit = now - this._dataAgeLimit; + while (this.config.data.rows.length > 1 && this.config.data.rows[1][0] < limit) { + this.config.data.rows.splice(1, 1); + } + } + + _update () { + if (!angular.isDefined(this.jvmId)) { + return; + } + this._svc.getJvmIoData(this.jvmId).then(res => { + let update = res.data.response[0]; + this.config.data.rows.push([ + this._metricToNumber(update.timeStamp), + this._metricToNumber(update.charactersRead), + this._metricToNumber(update.charactersWritten), + this._metricToNumber(update.readSysCalls), + this._metricToNumber(update.writeSysCalls), + ]); + this._trimData(); + }); + } +} + +export default angular + .module('jvmIo.controller', [ + service, + services, + filters, + 'patternfly', + 'patternfly.charts' + ]) + .controller('JvmIoController', JvmIoController) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.controller.spec.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,263 @@ +/** + * 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 './jvm-io.controller.js'; + +describe('JvmIoController', () => { + + let ctrl, svc, interval, translations, translate, + dateFilter, dateFormat, metricToNumberFilter; + beforeEach(() => { + angular.mock.module(controllerModule); + angular.mock.inject($controller => { + 'ngInject'; + let svcPromise = sinon.stub(); + svc = { + getJvmIoData: sinon.stub().returns({ + then: svcPromise + }), + promise: svcPromise + }; + interval = sinon.stub().returns('intervalMock'); + interval.cancel = sinon.spy(); + + translations = { + 'jvmIo.metrics.timestamp': 'date', + 'jvmIo.metrics.charactersRead': 'characters read', + 'jvmIo.metrics.charactersWritten': 'characters written', + 'jvmIo.metrics.readSysCalls': 'read sys calls', + 'jvmIo.metrics.writeSysCalls': 'write sys calls' + }; + let translateThenThen = sinon.stub().yields(); + translate = sinon.stub().returns({ + then: sinon.stub().yields(translations).returns({ + then: translateThenThen + }) + }); + + dateFilter = sinon.stub().returns('dateFilterMock'); + dateFormat = { + time: { + medium: 'dateFormatMedium' + } + }; + metricToNumberFilter = sinon.stub().callsFake(v => parseInt(v.$numberLong)); + + ctrl = $controller('JvmIoController', { + jvmIoService: svc, + $interval: interval, + $translate: translate, + dateFilter: dateFilter, + DATE_FORMAT: dateFormat, + metricToNumberFilter: metricToNumberFilter + }); + ctrl.jvmId = 'foo-jvmId'; + }); + }); + + it('should exist', () => { + should.exist(ctrl); + }); + + describe('init', () => { + it('should set refresh rate to 1 second', () => { + ctrl.refreshRate.should.equal('1000'); + }); + + it('should set data age limit to 30 seconds', () => { + ctrl.dataAgeLimit.should.equal('30000'); + }); + + it('should use translations', () => { + translate.should.be.calledWith([ + 'jvmIo.chart.X_LABEL', + 'jvmIo.chart.Y1_LABEL', + 'jvmIo.chart.Y2_LABEL', + + 'jvmIo.metrics.timestamp', + 'jvmIo.metrics.charactersRead', + 'jvmIo.metrics.charactersWritten', + 'jvmIo.metrics.readSysCalls', + 'jvmIo.metrics.writeSysCalls', + ]); + }); + }); + + describe('chart config', () => { + it('should format x-axis ticks', () => { + let fn = ctrl.config.axis.x.tick.format; + fn(100).should.equal('dateFilterMock'); + }); + + it('should provide an identity y-axis tick format function', () => { + let fn = ctrl.config.axis.y.tick.format; + fn(100).should.equal(100); + fn(200).should.equal(200); + }); + + it('should provide an identity y2-axis tick format function', () => { + let fn = ctrl.config.axis.y2.tick.format; + fn(100).should.equal(100); + fn(200).should.equal(200); + }); + + it('should provide identity tooltip format functions', () => { + let title = ctrl.config.tooltip.format.title; + title(100).should.equal(100); + title(200).should.equal(200); + let value = ctrl.config.tooltip.format.value; + value(100).should.equal(100); + value(200).should.equal(200); + }); + }); + + describe('$onDestroy', () => { + it('should do nothing if controller is not started', () => { + ctrl._stop(); + interval.cancel.should.be.calledOnce(); + ctrl.$onDestroy(); + interval.cancel.should.be.calledOnce(); + }); + + it('should stop the controller if already started', () => { + ctrl._start(); + interval.cancel.should.be.calledOnce(); + ctrl.$onDestroy(); + interval.cancel.should.be.calledTwice(); + }); + }); + + describe('refreshRate', () => { + it('should set interval and disable if <= 0', () => { + interval.should.be.calledOnce(); + ctrl.refreshRate = 10000; + interval.cancel.should.be.calledOnce(); + interval.should.be.calledTwice(); + interval.secondCall.should.be.calledWith(sinon.match.func, 10000); + ctrl.refreshRate = -1; + interval.cancel.should.be.calledTwice(); + interval.should.be.calledTwice(); + }); + + it('should reflect changes in getter', () => { + ctrl.refreshRate.should.equal('1000'); + ctrl.refreshRate = 2000; + ctrl.refreshRate.should.equal('2000'); + }); + }); + + describe('dataAgeLimit', () => { + it('should cause a data trim on change', () => { + sinon.spy(ctrl, '_trimData'); + ctrl._trimData.should.not.be.called; + ctrl.dataAgeLimit = 10000; + ctrl._trimData.should.be.calledOnce(); + ctrl._trimData.restore(); + }); + + it('should reflect changes in getter', () => { + ctrl.dataAgeLimit.should.equal('30000'); + ctrl.dataAgeLimit = 10000; + ctrl.dataAgeLimit.should.equal('10000'); + }); + }); + + describe('_start', () => { + it('should perform updates on an interval', () => { + interval.should.be.calledOnce(); + ctrl._start(); + interval.should.be.calledTwice(); + interval.secondCall.should.be.calledWith(sinon.match.func, 1000); + + let func = interval.args[1][0]; + svc.getJvmIoData.should.be.calledOnce(); + func(); + svc.getJvmIoData.should.be.calledTwice(); + }); + }); + + describe('_stop', () => { + it('should do nothing if not started', () => { + interval.cancel.should.not.be.called(); + ctrl._stop(); + interval.cancel.should.be.calledOnce(); + interval.cancel.should.be.calledWith('intervalMock'); + ctrl._stop(); + interval.cancel.should.be.calledOnce(); + }); + }); + + describe('_update', () => { + it('should do nothing if jvmId not yet bound', () => { + svc.getJvmIoData.should.not.be.called(); + delete ctrl.jvmId; + ctrl._update(); + svc.getJvmIoData.should.not.be.called(); + }); + + it('should add update data to chart data', () => { + ctrl._update(); + svc.promise.should.be.calledOnce(); + svc.promise.should.be.calledWith(sinon.match.func); + let stamp = Date.now(); + svc.promise.args[0][0]({ + data: { + response: [{ + timeStamp: { $numberLong: stamp.toString() }, + charactersRead: { $numberLong: '1000000' }, + charactersWritten: { $numberLong: '500000' }, + readSysCalls: { $numberLong: '100' }, + writeSysCalls: { $numberLong: '50' } + }] + } + }); + ctrl.config.data.rows.should.deepEqual([ + ['date', 'characters read', 'characters written', 'read sys calls', 'write sys calls'], + [stamp, 1000000, 500000, 100, 50] + ]); + }); + }); + + describe('_trimData', () => { + it('should remove datasets older than dataAgeLimit', () => { + let now = Date.now(); + let expired = now - 60000; + ctrl.config.data.rows.push([ + expired, 1, 1, 1, 1 + ]); + ctrl.config.data.rows.push([ + now, 2, 2, 2, 2 + ]); + ctrl._trimData(); + ctrl.config.data.rows.should.deepEqual([ + ['date', 'characters read', 'characters written', 'read sys calls', 'write sys calls'], + [now, 2, 2, 2, 2] + ]); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.html Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,45 @@ +<div class="container-fluid"> + + <div class="row" style="margin-top:2vh"> + <div class="col-xs-12 col-md-3"> + <label for="refreshCombo" class="label label-info" translate>jvmIo.REFRESH_RATE_LABEL</label> + <select name="refreshCombo" class="combobox form-control" ng-model="$ctrl.refreshRate"> + <option value="-1" translate>jvmIo.refresh.DISABLED</option> + <option value="1000" selected translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 1, DEFAULT: true }" translate-interpolation="messageformat"></option> + <option value="2000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 2 }" translate-interpolation="messageformat"></option> + <option value="5000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 5 }" translate-interpolation="messageformat"></option> + <option value="10000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 10 }" translate-interpolation="messageformat"></option> + <option value="30000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 30 }" translate-interpolation="messageformat"></option> + </select> + </div> + + <div class="col-xs-12 col-md-3"> + <label for="dataAgeCombo" class="label label-info" translate>jvmIo.MAX_DATA_AGE_LABEL</label> + <select name="dataAgeCombo" class="combobox form-control" ng-model="$ctrl.dataAgeLimit"> + <option value="10000" translate="jvmIo.dataAge.SECONDS" translate-values="{ SECONDS: 10 }" translate-interpolation="messageformat"></option> + <option value="30000" selected translate="jvmIo.dataAge.SECONDS" translate-values="{ SECONDS: 30, DEFAULT: true }" translate-interpolation="messageformat"></option> + <option value="60000" translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 1 }" translate-interpolation="messageformat"></option> + <option value="300000" translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 5 }" translate-interpolation="messageformat"></option> + <option value="900000" translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 15 }" translate-interpolation="messageformat"></option> + </select> + </div> + </div><!-- row --> + + <div class="row row-cards-pf"> + <div class="container-fluid container-cards-pf"> + + <div class="col-md-12"> + <div class="card-pf card-pf-view"> + <div class="card-pf-heading"> + <label class="card-pf-title" translate>jvmIo.chart.TITLE</label> + </div> + <div ng-if="$ctrl.config" class="card-pf-body text-center"> + <pf-c3-chart id="jvm-io-chart" config="$ctrl.config"></pf-c3-chart> + </div> + </div><!-- card-pf --> + </div><!-- col --> + </div><!-- container-cards-pf --> + </div><!-- row-cards-pf --> + + +</div><!-- container-fluid -->
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.routing.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,61 @@ +/** + * 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.jvmIo', { + url: '/jvm-io', + component: 'jvmIo', + resolve: { + lazyLoad: ($q, $ocLazyLoad) => { + 'ngInject'; + return $q(resolve => { + require.ensure(['./jvm-io.component.js'], () => { + let module = require('./jvm-io.component.js'); + $ocLazyLoad.load({ name: module.default }); + resolve(module); + }); + }); + }, + jvmId: $stateParams => { + 'ngInject'; + return $stateParams.jvmId; + } + } + }); +} + +export { config }; + +export default angular + .module('jvmIo.routing', [ + 'ui.router', + 'oc.lazyLoad' + ]) + .config(config) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.routing.spec.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,84 @@ +/** + * 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('JvmIoRouting', () => { + + let module = require('./jvm-io.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.jvmIo\' state', () => { + args[0].should.equal('jvmInfo.jvmIo'); + }); + + it('should map to /jvm-io', () => { + args[1].url.should.equal('/jvm-io'); + }); + + it('resolve should load jvm-io 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-io.component.js'); + ocLazyLoad.load.should.be.calledWith({ name: mod.default }); + val.should.equal(mod); + done(); + }); + deferred(resolve); + }); + }); + + describe('resolve params', () => { + it('should resolve jvmId state param', () => { + let fn = args[1].resolve.jvmId[1]; + fn({ jvmId: 'foo-id' }).should.equal('foo-id'); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.service.js Tue Sep 12 12:53:42 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 config from 'shared/config/config.module.js'; +import urlJoin from 'url-join'; + +class JvmIoService { + constructor ($http, gatewayUrl) { + 'ngInject'; + this._http = $http; + this._gatewayUrl = gatewayUrl; + } + + getJvmIoData (jvmId) { + let params = { sort: '-timeStamp' }; + return this._http.get(urlJoin(this._gatewayUrl, 'jvm-io', '0.0.1', 'jvms', jvmId), { params: params }); + } +} + +export default angular + .module('jvmIo.service', [config]) + .service('jvmIoService', JvmIoService) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.service.spec.js Tue Sep 12 12:53:42 2017 -0400 @@ -0,0 +1,78 @@ +/** + * 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('JvmIoService', () => { + + beforeEach(() => { + angular.mock.module('configModule', $provide => { + 'ngInject'; + $provide.constant('gatewayUrl', 'http://example.com:1234'); + }); + + angular.mock.module('jvmIo.service'); + }); + + let httpBackend, scope, svc; + beforeEach(inject(($httpBackend, $rootScope, jvmIoService) => { + 'ngInject'; + httpBackend = $httpBackend; + + scope = $rootScope; + svc = jvmIoService; + })); + + afterEach(() => { + httpBackend.verifyNoOutstandingExpectation(); + httpBackend.verifyNoOutstandingRequest(); + }); + + it('should exist', () => { + should.exist(svc); + }); + + describe('getJvmIodata (jvmId)', () => { + it('should resolve mock data', done => { + let expected = { + timeStamp: { $numberLong: Date.now().toString() }, + charactersRead: { $numberLong: '100000' }, + charactersWritten: { $numberLong: '50000' }, + readSysCalls: { $numberLong: '100' }, + writeSysCalls: { $numberLong: '50' } + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?sort=-timeStamp') + .respond(expected); + svc.getJvmIoData('foo-jvmId').then(res => { + res.data.should.deepEqual(expected); + done(); + }); + httpBackend.expectGET('http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?sort=-timeStamp'); + httpBackend.flush(); + scope.$apply(); + }); + }); + +});