changeset 180:53de35e22716

Convert jvm-gc module into component Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024867.html
author Andrew Azores <aazores@redhat.com>
date Thu, 07 Sep 2017 08:06:46 -0400
parents 8f116d9b0130
children 8d3c8addabad
files src/app/components/jvm-info/jvm-gc/jvm-gc.component.js src/app/components/jvm-info/jvm-gc/jvm-gc.controller.js src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js src/app/components/jvm-info/jvm-gc/jvm-gc.html src/app/components/jvm-info/jvm-gc/jvm-gc.module.js src/app/components/jvm-info/jvm-gc/jvm-gc.routing.js src/app/components/jvm-info/jvm-gc/jvm-gc.routing.spec.js
diffstat 7 files changed, 142 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.component.js	Thu Sep 07 08:06:46 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 JvmGcController from './jvm-gc.controller.js';
+import service from './jvm-gc.service.js';
+
+export default angular
+  .module('jvmGc', [
+    JvmGcController,
+    service
+  ])
+  .component('jvmGc', {
+    controller: 'JvmGcController',
+    template: require('./jvm-gc.html')
+  })
+  .name;
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.js	Wed Sep 06 10:17:05 2017 -0400
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.js	Thu Sep 07 08:06:46 2017 -0400
@@ -30,26 +30,19 @@
 import service from './jvm-gc.service.js';
 
 class JvmGcController {
-  constructor (jvmId, $scope, $interval, dateFilter, DATE_FORMAT,
+  constructor ($stateParams, $scope, $interval, dateFilter, DATE_FORMAT,
     metricToNumberFilter, jvmGcService, sanitizeService, $translate) {
     'ngInject';
-    this.jvmId = jvmId;
-    this.scope = $scope;
+    this.jvmId = $stateParams.jvmId;
     this.interval = $interval;
     this.dateFilter = dateFilter;
     this.dateFormat = DATE_FORMAT;
     this.metricToNumberFilter = metricToNumberFilter;
     this.jvmGcService = jvmGcService;
-    this.scope.sanitize = sanitizeService.sanitize;
+    this.sanitizeService = sanitizeService;
     this.translate = $translate;
 
-    this.scope.refreshRate = '1000';
-    this.scope.dataAgeLimit = '30000';
-
-    this.scope.$watch('refreshRate', (cur, prev) => this.setRefreshRate(cur));
-    this.scope.$watch('dataAgeLimit', () => this.trimData());
-
-    this.scope.$on('$destroy', () => this.stop());
+    $scope.$on('$destroy', () => this.stop());
 
     this.collectors = [];
     this.chartConfigs = {};
@@ -57,20 +50,43 @@
     this.collectorData = new Map();
     this.constructChartData();
 
-    this.update(parseInt($scope.dataAgeLimit) / parseInt($scope.refreshRate));
+    this.refreshRate = '1000';
+    this.dataAgeLimit = '30000';
   }
 
   start () {
-    this.setRefreshRate(this.scope.refreshRate);
+    this.refreshRate = this._refreshRate.toString();
   }
 
   stop () {
-    if (angular.isDefined(this.refresh)) {
-      this.interval.cancel(this.refresh);
-      delete this.refresh;
+    if (angular.isDefined(this._refresh)) {
+      this.interval.cancel(this._refresh);
+      delete this._refresh;
+    }
+  }
+
+  set refreshRate (val) {
+    this.stop();
+    this._refreshRate = parseInt(val);
+    if (this._refreshRate > 0) {
+      this._refresh = this.interval(() => this.update(), this._refreshRate);
+      this.update();
     }
   }
 
+  get refreshRate () {
+    return this._refreshRate.toString();
+  }
+
+  set dataAgeLimit (val) {
+    this._dataAgeLimit = val;
+    this.trimData();
+  }
+
+  get dataAgeLimit () {
+    return this._dataAgeLimit.toString();
+  }
+
   makeConfig (collector) {
     if (_.includes(this.collectors, collector)) {
       return;
@@ -121,21 +137,13 @@
     });
   }
 
-  setRefreshRate (val) {
-    this.stop();
-    if (val > 0) {
-      this.refresh = this.interval(() => this.update(), val);
-      this.update();
-    }
-  }
-
   trimData() {
     for (let entry of this.collectorData) {
       let collector = entry[0];
       let samples = entry[1];
 
       let now = Date.now();
-      let oldestLimit = now - parseInt(this.scope.dataAgeLimit);
+      let oldestLimit = now - parseInt(this.dataAgeLimit);
 
       while (true) {
         let oldest = samples[0];
@@ -169,8 +177,8 @@
     }
   }
 
-  update (limit = 1) {
-    this.jvmGcService.getJvmGcData(this.jvmId, limit)
+  update () {
+    this.jvmGcService.getJvmGcData(this.jvmId)
       .then(resp => this.processData(resp), angular.noop);
   }
 
@@ -226,6 +234,10 @@
     this.constructChartData();
   }
 
+  sanitize (input) {
+    return this.sanitizeService.sanitize(input);
+  }
+
   multichartFn (collector) {
     return new Promise(resolve => {
       this.jvmGcService.getJvmGcData(this.jvmId, 1, collector).then(resp => {
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js	Wed Sep 06 10:17:05 2017 -0400
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js	Thu Sep 07 08:06:46 2017 -0400
@@ -30,7 +30,7 @@
   beforeEach(angular.mock.module('app.filters'));
   beforeEach(angular.mock.module('jvmGc.controller'));
 
-  let scope, interval, dateFilterStub, dateFormatSpy, svc, promise, ctrl, translate;
+  let scope, interval, dateFilterStub, dateFormatSpy, svc, promise, ctrl, translate, sanitizeService;
   beforeEach(inject(($controller) => {
     'ngInject';
 
@@ -41,20 +41,15 @@
       }
     };
 
-    scope = {
-      $on: sinon.spy(),
-      $watch: sinon.spy()
-    };
+    scope = { $on: sinon.spy() };
 
     interval = sinon.stub().returns('interval-sentinel');
     interval.cancel = sinon.spy();
 
-    promise = {
-      then: sinon.spy()
-    };
-    svc = {
-      getJvmGcData: sinon.stub().returns(promise)
-    };
+    promise = { then: sinon.spy() };
+    svc = { getJvmGcData: sinon.stub().returns(promise) };
+
+    sanitizeService = { sanitize: sinon.spy() };
 
     translate = sinon.stub().returns({
       then: sinon.stub().yields({
@@ -65,12 +60,13 @@
     });
 
     ctrl = $controller('JvmGcController', {
-      jvmId: 'foo-jvmId',
+      $stateParams: { jvmId: 'foo-jvmId' },
       $scope: scope,
       $interval: interval,
       dateFilter: dateFilterStub,
       DATE_FORMAT: dateFormatSpy,
       jvmGcService: svc,
+      sanitizeService: sanitizeService,
       $translate: translate
     });
   }));
@@ -80,7 +76,7 @@
   });
 
   it('should update on init', () => {
-    svc.getJvmGcData.should.be.calledWith('foo-jvmId', 30);
+    svc.getJvmGcData.should.be.calledWith('foo-jvmId');
   });
 
   it('should call to service on update', () => {
@@ -112,20 +108,24 @@
   });
 
   it('should reset interval on refreshRate change', () => {
-    ctrl.should.not.have.ownProperty('refresh');
-    ctrl.setRefreshRate(1);
+    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.should.have.ownProperty('_refresh');
+    ctrl._refresh.should.equal('interval-sentinel');
+    ctrl.refreshRate.should.equal('1');
   });
 
   it('should trim data on dataAgeLimit change', () => {
-    scope.$watch.should.be.calledWith('dataAgeLimit');
-    scope.$watch.args[1][0].should.equal('dataAgeLimit');
-    let fn = scope.$watch.args[1][1];
-    fn.should.be.a.Function();
+    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 = {
       micros: 100,
@@ -138,7 +138,7 @@
     };
 
     ctrl.collectorData.set('fooCollector', [oldSample, futureSample]);
-    scope.$watch.args[1][1]();
+    ctrl.dataAgeLimit = '30000';
 
     let expected = new Map();
     expected.set('fooCollector', [futureSample]);
@@ -147,35 +147,28 @@
   });
 
   it('should set interval on start', () => {
-    interval.should.not.be.called();
+    interval.should.be.calledOnce();
+    interval.should.be.calledWith(sinon.match.func, 1000);
     interval.cancel.should.not.be.called();
-
-    ctrl.start();
-
-    interval.cancel.should.not.be.called();
-    interval.should.be.calledWith(sinon.match.func, '1000');
   });
 
-  it('should disable when setRefreshRate is called with a non-positive value', () => {
+  it('should disable when set refreshRate is called with a non-positive value', () => {
     interval.cancel.should.not.be.called();
-    ctrl.setRefreshRate.should.not.be.called();
     ctrl.update.should.not.be.called();
 
-    ctrl.setRefreshRate(1);
-
-    interval.cancel.should.not.be.called();
-    ctrl.should.have.ownProperty('refresh');
-
-    ctrl.setRefreshRate(-1);
+    ctrl.refreshRate = '1';
 
     interval.cancel.should.be.calledOnce();
-    ctrl.should.not.have.ownProperty('refresh');
+    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', () => {
-    scope.$watch.should.be.calledWith(sinon.match('refreshRate'), sinon.match.func);
-    let f = scope.$watch.args[0][1];
-    f(1);
+    ctrl.refreshRate = 1;
     let func = interval.args[0][0];
     let callCount = svc.getJvmGcData.callCount;
     func();
@@ -233,18 +226,18 @@
       ctrl.start();
       let fn = cfg.onmouseover;
       fn.should.be.a.Function();
-      interval.cancel.should.not.be.called();
+      interval.cancel.should.be.calledOnce();
       fn();
-      interval.cancel.should.be.calledOnce();
+      interval.cancel.should.be.calledTwice();
     });
 
     it('should start on mouseout', () => {
       ctrl.stop();
       let fn = cfg.onmouseout;
       fn.should.be.a.Function();
-      interval.should.not.be.called();
+      interval.should.be.calledOnce();
       fn();
-      interval.should.be.calledOnce();
+      interval.should.be.calledTwice();
     });
   });
 
@@ -422,20 +415,29 @@
     });
 
     it('should cancel refresh', () => {
-      ctrl.refresh = 'interval-sentinel';
+      ctrl._refresh = 'interval-sentinel';
       let func = scope.$on.args[0][1];
       func();
       interval.cancel.should.be.calledWith('interval-sentinel');
     });
 
     it('should do nothing if refresh is undefined', () => {
-      ctrl.refresh = undefined;
+      delete ctrl._refresh;
       let func = scope.$on.args[0][1];
       func();
       interval.cancel.should.not.be.called();
     });
   });
 
+  describe('sanitize()', () => {
+    it('should delegate to sanitizeService', () => {
+      sanitizeService.sanitize.should.not.be.called();
+      ctrl.sanitize('foo');
+      sanitizeService.sanitize.should.be.calledOnce();
+      sanitizeService.sanitize.should.be.calledWith('foo');
+    });
+  });
+
   describe('multichartFn', () => {
     it('should return a promise', () => {
       let res = ctrl.multichartFn();
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.html	Wed Sep 06 10:17:05 2017 -0400
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.html	Thu Sep 07 08:06:46 2017 -0400
@@ -3,7 +3,7 @@
   <div class="row" style="margin-top:2vh">
     <div class="col-xs-12 col-md-3">
       <label for="refreshCombo" class="label label-info" translate>jvmGc.REFRESH_RATE_LABEL</label>
-      <select name="refreshCombo" class="combobox form-control" ng-model="refreshRate">
+      <select name="refreshCombo" class="combobox form-control" ng-model="$ctrl.refreshRate">
         <option value="-1" translate>jvmGc.refresh.DISABLED</option>
         <option value="1000" selected translate="jvmGc.refresh.SECONDS" translate-values="{ SECONDS: 1, DEFAULT: true }" translate-interpolation="messageformat"></option>
         <option value="2000" translate="jvmGc.refresh.SECONDS" translate-values="{ SECONDS: 2 }" translate-interpolation="messageformat"></option>
@@ -15,7 +15,7 @@
 
     <div class="col-xs-12 col-md-3">
       <label for="dataAgeCombo" class="label label-info" translate>jvmGc.MAX_DATA_AGE_LABEL</label>
-      <select name="dataAgeCombo" class="combobox form-control" ng-model="dataAgeLimit">
+      <select name="dataAgeCombo" class="combobox form-control" ng-model="$ctrl.dataAgeLimit">
         <option value="10000" translate="jvmGc.dataAge.SECONDS" translate-values="{ SECONDS: 10 }" translate-interpolation="messageformat"></option>
         <option value="30000" selected translate="jvmGc.dataAge.SECONDS" translate-values="{ SECONDS: 30, DEFAULT: true }" translate-interpolation="messageformat"></option>
         <option value="60000" translate="jvmGc.dataAge.MINUTES" translate-values="{ MINUTES: 1 }" translate-interpolation="messageformat"></option>
@@ -33,11 +33,11 @@
           <div class="card-pf-heading">
             <label class="card-pf-title" translate>jvmGc.CARD_TITLE</label>
           </div>
-          <div ng-repeat="collector in ctrl.collectors">
+          <div ng-repeat="collector in $ctrl.collectors">
             <div class="card-pf-body text-center">
-              <mc-add class="pull-right" svc-name="{{ctrl.jvmId}}-{{sanitize(collector)}}-gc" get-fn="ctrl.multichartFn(collector)"></mc-add>
-              <pf-line-chart id="chart-{{collector}}" config="ctrl.chartConfigs[collector]"
-                                                          chart-data="ctrl.chartData[collector]"
+              <mc-add class="pull-right" svc-name="{{$ctrl.jvmId}}-{{$ctrl.sanitize(collector)}}-gc" get-fn="$ctrl.multichartFn(collector)"></mc-add>
+              <pf-line-chart id="chart-{{collector}}" config="$ctrl.chartConfigs[collector]"
+                                                          chart-data="$ctrl.chartData[collector]"
                                                           show-x-axis="true"
                                                           show-y-axis="true"
                                                           ></pf-line-chart>
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.module.js	Wed Sep 06 10:17:05 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/**
- * 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 JvmGcController from './jvm-gc.controller.js';
-import service from './jvm-gc.service.js';
-
-export default angular
-  .module('jvmGc', [
-    JvmGcController,
-    service
-  ])
-  .name;
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.routing.js	Wed Sep 06 10:17:05 2017 -0400
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.routing.js	Thu Sep 07 08:06:46 2017 -0400
@@ -30,20 +30,13 @@
 
   $stateProvider.state('jvmInfo.jvmGc', {
     url: '/garbage-collection',
-    controller: 'JvmGcController as ctrl',
-    templateProvider: $q => {
-      'ngInject';
-      return $q(resolve =>
-        require.ensure([], () => resolve(require('./jvm-gc.html'))
-        )
-      );
-    },
+    component: 'jvmGc',
     resolve: {
-      loadJvmGc: (loadJvmInfo, $q, $ocLazyLoad) => {
+      lazyLoad: ($q, $ocLazyLoad) => {
         'ngInject';
         return $q(resolve => {
-          require.ensure(['./jvm-gc.module.js'], () => {
-            let module = require('./jvm-gc.module.js');
+          require.ensure(['./jvm-gc.component.js'], () => {
+            let module = require('./jvm-gc.component.js');
             $ocLazyLoad.load({ name: module.default });
             resolve(module);
           });
--- a/src/app/components/jvm-info/jvm-gc/jvm-gc.routing.spec.js	Wed Sep 06 10:17:05 2017 -0400
+++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.routing.spec.js	Thu Sep 07 08:06:46 2017 -0400
@@ -55,33 +55,17 @@
       args[1].url.should.equal('/garbage-collection');
     });
 
-    it('template provider should return jvm-gc.html', done => {
-      let providerFn = args[1].templateProvider[1];
-      providerFn.should.be.a.Function();
-      providerFn(q);
+    it('resolve should load jvm-gc 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 => {
-        val.should.equal(require('./jvm-gc.html'));
-        done();
-      });
-      deferred(resolve);
-    });
-
-    it('resolve should load jvm-gc module', done => {
-      let resolveFn = args[1].resolve.loadJvmGc[3];
-      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-gc.module.js');
+        let mod = require('./jvm-gc.component.js');
         ocLazyLoad.load.should.be.calledWith({ name: mod.default });
         val.should.equal(mod);
         done();