Mercurial > hg > thermostat-ng > web-client
changeset 230:eebc90a53b7f
jvm-io loads historical data
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025222.html
author | Andrew Azores <aazores@redhat.com> |
---|---|
date | Thu, 28 Sep 2017 14:20:44 -0400 |
parents | 1887aaa6d7a5 |
children | ba401daa2732 |
files | mock-api/endpoints/jvm-io.endpoint.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.service.js src/app/components/jvm-info/jvm-io/jvm-io.service.spec.js |
diffstat | 6 files changed, 215 insertions(+), 93 deletions(-) [+] |
line wrap: on
line diff
--- a/mock-api/endpoints/jvm-io.endpoint.js Thu Sep 28 10:07:13 2017 -0400 +++ b/mock-api/endpoints/jvm-io.endpoint.js Thu Sep 28 14:20:44 2017 -0400 @@ -5,19 +5,33 @@ server.app.get('/jvm-io/0.0.1/jvms/:jvmId', function (req, res) { server.logRequest('jvm-io', req); + var limit = req.query.limit; var jvmId = req.params.jvmId; - var response = [ - { + var count; + if (limit == 0) { + count = 60; + } else if (limit == 1) { + count = 0; + } else { + count = 0; + } + + var response = []; + for (var i = count; i >= 0; i--) { + let date = Date.now() - (i * 10000); + let data = { 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() } - } - ]; + timeStamp: { $numberLong: date.toString() }, + charactersRead: { $numberLong: _.floor(date / 10000000).toString() }, + charactersWritten: { $numberLong: _.floor((date / 12000000)).toString() }, + readSysCalls: { $numberLong: _.floor(date / 20000000).toString() }, + writeSysCalls: { $numberLong: _.floor(date / 30000000).toString() } + }; + response.push(data); + } + console.log(response); res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(
--- a/src/app/components/jvm-info/jvm-io/jvm-io.controller.js Thu Sep 28 10:07:13 2017 -0400 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.controller.js Thu Sep 28 14:20:44 2017 -0400 @@ -40,9 +40,15 @@ this._dateFormat = DATE_FORMAT; this._metricToNumber = metricToNumberFilter; - this._refreshRate = 1000; - this._dataAgeLimit = 30000; - this._makeChartConfig().then(() => this._start()); + this._refreshRate = 10000; + this._dataAgeLimit = 600000; + + this._makeChartConfig(); + } + + $onInit() { + this._loadHistoricalData(); + this._start(); } $onDestroy () { @@ -50,7 +56,7 @@ } _makeChartConfig () { - return this._translate([ + this._translate([ 'jvmIo.chart.X_LABEL', 'jvmIo.chart.Y1_LABEL', 'jvmIo.chart.Y2_LABEL', @@ -133,8 +139,9 @@ } set dataAgeLimit (val) { + this._clearData(); this._dataAgeLimit = val; - this._trimData(); + this._loadHistoricalData(); } get dataAgeLimit () { @@ -144,7 +151,6 @@ _start () { this._stop(); this._refresh = this._interval(() => this._update(), this._refreshRate); - this._update(); } _stop () { @@ -154,6 +160,11 @@ } } + _clearData () { + let firstRow = this.config.data.rows[0]; + this.config.data.rows = [firstRow]; + } + _trimData () { let now = Date.now(); let limit = now - this._dataAgeLimit; @@ -162,22 +173,27 @@ } } + _loadHistoricalData () { + this._svc.getHistoricalData(this.jvmId, Date.now() - this._dataAgeLimit).then(updates => + updates.forEach(update => this._processUpdateRow(update))); + } + _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._svc.getJvmIoData(this.jvmId).then(update => { + this._processUpdateRow(update); this._trimData(); }); } + + _processUpdateRow (update) { + 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), + ]); + } } export default angular
--- a/src/app/components/jvm-info/jvm-io/jvm-io.controller.spec.js Thu Sep 28 10:07:13 2017 -0400 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.controller.spec.js Thu Sep 28 14:20:44 2017 -0400 @@ -40,6 +40,9 @@ getJvmIoData: sinon.stub().returns({ then: svcPromise }), + getHistoricalData: sinon.stub().returns({ + then: svcPromise + }), promise: svcPromise }; interval = sinon.stub().returns('intervalMock'); @@ -83,13 +86,13 @@ should.exist(ctrl); }); - describe('init', () => { - it('should set refresh rate to 1 second', () => { - ctrl.refreshRate.should.equal('1000'); + describe('properties', () => { + it('should set refresh rate to 10 seconds', () => { + ctrl.refreshRate.should.equal('10000'); }); - it('should set data age limit to 30 seconds', () => { - ctrl.dataAgeLimit.should.equal('30000'); + it('should set data age limit to 10 minutes', () => { + ctrl.dataAgeLimit.should.equal('600000'); }); it('should use translations', () => { @@ -107,6 +110,20 @@ }); }); + describe('$onInit ()', () => { + beforeEach(() => { + ctrl.$onInit(); + }); + + it('should load historical data', () => { + svc.getHistoricalData.should.be.calledOnce(); + }); + + it('should start periodic live updates', () => { + interval.should.be.calledOnce(); + }); + }); + describe('chart config', () => { it('should format x-axis ticks', () => { let fn = ctrl.config.axis.x.tick.format; @@ -137,50 +154,57 @@ describe('$onDestroy', () => { it('should do nothing if controller is not started', () => { - ctrl._stop(); - interval.cancel.should.be.calledOnce(); + interval.cancel.should.not.be.called(); ctrl.$onDestroy(); - interval.cancel.should.be.calledOnce(); + interval.cancel.should.not.be.called(); }); it('should stop the controller if already started', () => { ctrl._start(); - interval.cancel.should.be.calledOnce(); + interval.cancel.should.not.be.called(); ctrl.$onDestroy(); - interval.cancel.should.be.calledTwice(); + interval.cancel.should.be.calledOnce(); }); }); describe('refreshRate', () => { it('should set interval and disable if <= 0', () => { + interval.should.not.be.called(); + ctrl.refreshRate = 10000; + interval.cancel.should.not.be.called(); interval.should.be.calledOnce(); - ctrl.refreshRate = 10000; + interval.should.be.calledWith(sinon.match.func, 10000); + ctrl.refreshRate = -1; 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(); + interval.should.be.calledOnce(); }); it('should reflect changes in getter', () => { - ctrl.refreshRate.should.equal('1000'); + ctrl.refreshRate.should.equal('10000'); 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; + it('should cause a data clear on change', () => { + sinon.spy(ctrl, '_clearData'); + ctrl._clearData.should.not.be.called; ctrl.dataAgeLimit = 10000; - ctrl._trimData.should.be.calledOnce(); - ctrl._trimData.restore(); + ctrl._clearData.should.be.calledOnce(); + ctrl._clearData.restore(); + }); + + it('should cause a historical data load on change', () => { + sinon.spy(ctrl, '_loadHistoricalData'); + ctrl._loadHistoricalData.should.not.be.called; + ctrl.dataAgeLimit = 10000; + ctrl._loadHistoricalData.should.be.calledOnce(); + ctrl._loadHistoricalData.restore(); }); it('should reflect changes in getter', () => { - ctrl.dataAgeLimit.should.equal('30000'); + ctrl.dataAgeLimit.should.equal('600000'); ctrl.dataAgeLimit = 10000; ctrl.dataAgeLimit.should.equal('10000'); }); @@ -188,15 +212,15 @@ describe('_start', () => { it('should perform updates on an interval', () => { - interval.should.be.calledOnce(); + interval.should.not.be.called(); ctrl._start(); - interval.should.be.calledTwice(); - interval.secondCall.should.be.calledWith(sinon.match.func, 1000); + interval.should.be.calledOnce(); + interval.should.be.calledWith(sinon.match.func, 10000); - let func = interval.args[1][0]; + let func = interval.args[0][0]; + svc.getJvmIoData.should.not.be.called(); + func(); svc.getJvmIoData.should.be.calledOnce(); - func(); - svc.getJvmIoData.should.be.calledTwice(); }); }); @@ -204,37 +228,57 @@ 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(); + interval.cancel.should.not.be.called(); + }); + }); + + describe('_loadHistoricaldata', () => { + it('should add update data to chart data', () => { + ctrl._loadHistoricalData(); + svc.promise.should.be.calledOnce(); + svc.promise.should.be.calledWith(sinon.match.func); + let stamp = Date.now(); + svc.promise.args[0][0]( + [ + { + timeStamp: { $numberLong: (stamp - 10000).toString() }, + charactersRead: { $numberLong: '1000000' }, + charactersWritten: { $numberLong: '500000' }, + readSysCalls: { $numberLong: '100' }, + writeSysCalls: { $numberLong: '50' } + }, + { + timeStamp: { $numberLong: stamp.toString() }, + charactersRead: { $numberLong: '1000001' }, + charactersWritten: { $numberLong: '500001' }, + readSysCalls: { $numberLong: '101' }, + writeSysCalls: { $numberLong: '51' } + } + ] + ); + ctrl.config.data.rows.should.deepEqual([ + ['date', 'characters read', 'characters written', 'read sys calls', 'write sys calls'], + [(stamp - 10000), 1000000, 500000, 100, 50], + [stamp, 1000001, 500001, 101, 51] + ]); }); }); 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' } - }] + svc.promise.args[0][0]( + { + 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] @@ -245,7 +289,7 @@ describe('_trimData', () => { it('should remove datasets older than dataAgeLimit', () => { let now = Date.now(); - let expired = now - 60000; + let expired = now - ctrl._dataAgeLimit - 1; ctrl.config.data.rows.push([ expired, 1, 1, 1, 1 ]);
--- a/src/app/components/jvm-info/jvm-io/jvm-io.html Thu Sep 28 10:07:13 2017 -0400 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.html Thu Sep 28 14:20:44 2017 -0400 @@ -5,22 +5,22 @@ <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="10000" selected translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 10, DEFAULT: true }" translate-interpolation="messageformat"></option> <option value="30000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 30 }" translate-interpolation="messageformat"></option> + <option value="60000" translate="jvmIo.refresh.SECONDS" translate-values="{ SECONDS: 60 }" 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="30000" translate="jvmIo.dataAge.SECONDS" translate-values="{ SECONDS: 30 }" 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="600000" selected translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 10, DEFAULT: true }" translate-interpolation="messageformat"></option> <option value="900000" translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 15 }" translate-interpolation="messageformat"></option> + <option value="1800000" translate="jvmIo.dataAge.MINUTES" translate-values="{ MINUTES: 30 }" translate-interpolation="messageformat"></option> </select> </div> </div><!-- row -->
--- a/src/app/components/jvm-info/jvm-io/jvm-io.service.js Thu Sep 28 10:07:13 2017 -0400 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.service.js Thu Sep 28 14:20:44 2017 -0400 @@ -35,9 +35,23 @@ this._gatewayUrl = gatewayUrl; } + getHistoricalData (jvmId, since) { + let params = { + sort: '-timeStamp', + limit: 0, + query: `timeStamp>=${since}` + }; + return this._http.get(urlJoin(this._gatewayUrl, 'jvm-io', '0.0.1', 'jvms', jvmId), { params: params }) + .then(res => res.data.response); + } + getJvmIoData (jvmId) { - let params = { sort: '-timeStamp' }; - return this._http.get(urlJoin(this._gatewayUrl, 'jvm-io', '0.0.1', 'jvms', jvmId), { params: params }); + let params = { + sort: '-timeStamp', + limit: 1 + }; + return this._http.get(urlJoin(this._gatewayUrl, 'jvm-io', '0.0.1', 'jvms', jvmId), { params: params }) + .then(res => res.data.response[0]); } }
--- a/src/app/components/jvm-info/jvm-io/jvm-io.service.spec.js Thu Sep 28 10:07:13 2017 -0400 +++ b/src/app/components/jvm-info/jvm-io/jvm-io.service.spec.js Thu Sep 28 14:20:44 2017 -0400 @@ -57,19 +57,53 @@ 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' } + response: [{ + 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') + httpBackend.when('GET', 'http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?limit=1&sort=-timeStamp') .respond(expected); svc.getJvmIoData('foo-jvmId').then(res => { - res.data.should.deepEqual(expected); + res.should.deepEqual(expected.response[0]); done(); }); - httpBackend.expectGET('http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?sort=-timeStamp'); + httpBackend.expectGET('http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?limit=1&sort=-timeStamp'); + httpBackend.flush(); + scope.$apply(); + }); + }); + + describe('getHistoricalData (jvmId, since)', () => { + it('should resolve mock data', done => { + let expected = { + response: [ + { + timeStamp: { $numberLong: (Date.now() - 10000).toString() }, + charactersRead: { $numberLong: '100000' }, + charactersWritten: { $numberLong: '50000' }, + readSysCalls: { $numberLong: '100' }, + writeSysCalls: { $numberLong: '50' } + }, + { + timeStamp: { $numberLong: Date.now().toString() }, + charactersRead: { $numberLong: '200000' }, + charactersWritten: { $numberLong: '60000' }, + readSysCalls: { $numberLong: '200' }, + writeSysCalls: { $numberLong: '60' } + }, + ] + }; + httpBackend.when('GET', 'http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?limit=0&query=timeStamp%3E%3D150000&sort=-timeStamp') + .respond(expected); + svc.getHistoricalData('foo-jvmId', 150000).then(res => { + res.should.deepEqual(expected.response); + done(); + }); + httpBackend.expectGET('http://example.com:1234/jvm-io/0.0.1/jvms/foo-jvmId?limit=0&query=timeStamp%3E%3D150000&sort=-timeStamp'); httpBackend.flush(); scope.$apply(); });