From 8a0ab1d42563fc7650b1696cfe12d28bc5058b03 Mon Sep 17 00:00:00 2001 From: Masayuki Igawa Date: Mon, 22 Feb 2016 15:53:02 -0500 Subject: [PATCH] Split tests page into list and detail page This commit splits the tests page into a list page and its detail page for improving the performance of showing the page. Previously, we rendered numerous tests list in one tests page. So it causes the performance issue. Splitting the page reduces the number of showing test lists. This is not perfect solution but it's better than before at least. Change-Id: If1a97740d09359ae17d0f0b7df8d36256ac99f47 Closes-Bug: #1548354 --- app/js/controllers/tests-detail.js | 82 ++++++++++++++++ app/js/controllers/tests.js | 35 +------ app/js/on_config.js | 11 +++ app/js/services/health-api.js | 1 + app/views/tests-detail.html | 70 ++++++++++++++ app/views/tests.html | 60 ++---------- test/unit/controllers/tests_detail_spec.js | 107 +++++++++++++++++++++ test/unit/controllers/tests_spec.js | 31 +----- 8 files changed, 288 insertions(+), 109 deletions(-) create mode 100644 app/js/controllers/tests-detail.js create mode 100644 app/views/tests-detail.html create mode 100644 test/unit/controllers/tests_detail_spec.js diff --git a/app/js/controllers/tests-detail.js b/app/js/controllers/tests-detail.js new file mode 100644 index 00000000..f7876a5f --- /dev/null +++ b/app/js/controllers/tests-detail.js @@ -0,0 +1,82 @@ +'use strict'; + +var controllersModule = require('./_index'); +var _ = require('underscore'); + +/** + * @ngInject + */ +function TestsDetailController($scope, healthService, testService, key, $location) { + + // ViewModel + var vm = this; + vm.searchTest = ''; + vm.key = decodeURIComponent(key); + + vm.processData = function(data) { + vm.chartData = {}; + + var testsByHierarchy = _.groupBy(data.tests, function(test) { + var testId = testService.removeIdNoise(test.test_id); + var keyMatcher = /^(\w*)\./g; + var matches = keyMatcher.exec(testId); + + if (matches) { + return matches[1]; + } + + return 'Others'; + }); + + var getTestFailureAvg = function(test) { + return test.failure / test.run_count; + }; + + _.each(testsByHierarchy, function(tests, hierarchy, list) { + if (!vm.chartData[hierarchy]) { + vm.chartData[hierarchy] = [{ + key: hierarchy, + values: [], + tests: [] + }]; + } + + var orderedTests = _.sortBy(tests, function(test) { + return getTestFailureAvg(test) * -1; + }); + + var topFailures = _.first(orderedTests, 10); + + topFailures.forEach(function(test) { + var failureAverage = getTestFailureAvg(test); + if (!isNaN(failureAverage) && parseFloat(failureAverage) > 0.01) { + var chartData = { + label: test.test_id, + value: failureAverage + }; + vm.chartData[hierarchy][0].values.push(chartData); + } + }); + + orderedTests.forEach(function(test) { + test.failureAverage = getTestFailureAvg(test); + vm.chartData[hierarchy][0].tests.push(test); + }); + }); + }; + + vm.loadData = function() { + healthService.getTests().then(function(response) { + vm.processData(response.data); + }); + }; + + vm.searchTest = $location.search().searchTest || ''; + + vm.loadData(); + + vm.onSearchChange = function() { + $location.search('searchTest', $scope.testsDetail.searchTest); + }; +} +controllersModule.controller('TestsDetailController', TestsDetailController); diff --git a/app/js/controllers/tests.js b/app/js/controllers/tests.js index 227fac0d..87777557 100644 --- a/app/js/controllers/tests.js +++ b/app/js/controllers/tests.js @@ -27,40 +27,15 @@ function TestsController($scope, healthService, testService, $location) { return 'Others'; }); - var getTestFailureAvg = function(test) { - return test.failure / test.run_count; - }; - - _.each(testsByHierarchy, function(tests, hierarchy, list) { - if (!vm.chartData[hierarchy]) { - vm.chartData[hierarchy] = [{ - key: hierarchy, + var sortedKeys = _.sortBy(_.keys(testsByHierarchy)); + _.each(sortedKeys, function(key) { + if (!vm.chartData[key]) { + vm.chartData[key] = [{ + key: key, values: [], tests: [] }]; } - - var orderedTests = _.sortBy(tests, function(test) { - return getTestFailureAvg(test) * -1; - }); - - var topFailures = _.first(orderedTests, 10); - - topFailures.forEach(function(test) { - var failureAverage = getTestFailureAvg(test); - if (!isNaN(failureAverage) && parseFloat(failureAverage) > 0.01) { - var chartData = { - label: test.test_id, - value: failureAverage - }; - vm.chartData[hierarchy][0].values.push(chartData); - } - }); - - orderedTests.forEach(function(test) { - test.failureAverage = getTestFailureAvg(test); - vm.chartData[hierarchy][0].tests.push(test); - }); }); }; diff --git a/app/js/on_config.js b/app/js/on_config.js index 6a3bd252..2f7b8ef9 100644 --- a/app/js/on_config.js +++ b/app/js/on_config.js @@ -31,6 +31,17 @@ function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) { templateUrl: 'tests.html', title: 'Tests' }) + .state('testsDetail', { + url: '/tests/:key', + controller: 'TestsDetailController as testsDetail', + templateUrl: 'tests-detail.html', + title: 'Tests Detail', + resolve: /*@ngInject*/ { + 'key': function($stateParams) { + return $stateParams.key; + } + } + }) .state('job', { url: '/job/:jobName', controller: 'JobController as job', diff --git a/app/js/services/health-api.js b/app/js/services/health-api.js index 4bfa50e9..44139dbe 100644 --- a/app/js/services/health-api.js +++ b/app/js/services/health-api.js @@ -100,6 +100,7 @@ function HealthService($http, config) { service.getTests = function() { return config.get().then(function(config) { return $http.jsonp(config.apiRoot + '/tests', { + cache: true, params: { callback: 'JSON_CALLBACK' } }); }); diff --git a/app/views/tests-detail.html b/app/views/tests-detail.html new file mode 100644 index 00000000..733106c2 --- /dev/null +++ b/app/views/tests-detail.html @@ -0,0 +1,70 @@ +
+
+

Tests Detail

+ +
+
+ +
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + +
+ Test ID + + Passed + + Failed + + Failure % + + Avg. Runtime (secs.) +
+ {{test.test_id | limitTo: 110}} + {{ test.success | number }}{{ test.failure | number }}{{ test.failureAverage * 100 | number: 2 }}%{{ test.run_time | number: 2 }}
+
+
+
+
+
+
+
diff --git a/app/views/tests.html b/app/views/tests.html index a016e000..4fe4a2af 100644 --- a/app/views/tests.html +++ b/app/views/tests.html @@ -13,58 +13,18 @@
- -
- -
-
-
-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - -
- Test ID - - Passed - - Failed - - Failure % - - Avg. Runtime (secs.) -
- {{test.test_id | limitTo: 110}} - {{ test.success | number }}{{ test.failure | number }}{{ test.failureAverage * 100 | number: 2 }}%{{ test.run_time | number: 2 }}
+
+
+

Details list

+
+
+ - +
-
diff --git a/test/unit/controllers/tests_detail_spec.js b/test/unit/controllers/tests_detail_spec.js new file mode 100644 index 00000000..186fb1c5 --- /dev/null +++ b/test/unit/controllers/tests_detail_spec.js @@ -0,0 +1,107 @@ +describe('TestsDetailController', function() { + beforeEach(function() { + module('app'); + module('app.controllers'); + }); + + var $scope, $httpBackend, $controller, healthService; + var API_ROOT = 'http://8.8.4.4:8080'; + var DEFAULT_START_DATE = new Date(); + + beforeEach(inject(function($rootScope, _$httpBackend_, _$controller_, _healthService_) { + $httpBackend = _$httpBackend_; + + mockConfigService(); + mockHealthService(); + + $scope = $rootScope.$new(); + $controller = _$controller_; + healthService = _healthService_; + })); + + function mockHealthService() { + var expectedResponse = { + tests: [ + { + failure: 5592, + id: '00187173-ab23-4181-9a15-e291a0d8e2d1', + run_count: 55920, + run_time: 0.608151, + success: 55920, + test_id: 'tempest.api.identity.admin.v2.test_users.one' + }, + { + failure: 0, + id: '001c6860-c966-4c0b-9928-ecccd162bed0', + run_count: 4939, + run_time: 5.97596, + success: 4939, + test_id: 'tempest.api.volume.admin.test_snapshots_actions.two' + }, + { + failure: 1, + id: '002a15e0-f6d1-472a-bd66-bb13ac4d77aa', + run_count: 32292, + run_time: 1.18864, + success: 32291, + test_id: 'tempest.api.network.test_routers.three' + } + ] + }; + + var endpoint = API_ROOT + '/tests?callback=JSON_CALLBACK'; + $httpBackend.expectJSONP(endpoint) + .respond(200, expectedResponse); + } + + function mockConfigService() { + var expectedResponse = { apiRoot: API_ROOT }; + var endpoint = 'config.json'; + $httpBackend.expectGET(endpoint).respond(200, expectedResponse); + } + + it('should process chart data correctly', function() { + var testsDetailController = $controller('TestsDetailController', { + healthService: healthService, + $scope: $scope, + key: 'tempest' + }); + $httpBackend.flush(); + + var expectedChartData = { + 'tempest': [{ + key: 'tempest', + values: [{ + label: 'tempest.api.identity.admin.v2.test_users.one', + value: 0.1 + }], + tests: [{ + failure: 5592, + id: '00187173-ab23-4181-9a15-e291a0d8e2d1', + run_count: 55920, + run_time: 0.608151, + success: 55920, + test_id: 'tempest.api.identity.admin.v2.test_users.one', + failureAverage: 0.1 + }, { + failure: 1, + id: '002a15e0-f6d1-472a-bd66-bb13ac4d77aa', + run_count: 32292, + run_time: 1.18864, + success: 32291, + test_id: 'tempest.api.network.test_routers.three', + failureAverage: 0.0000309674222717701 + }, { + failure: 0, + id: '001c6860-c966-4c0b-9928-ecccd162bed0', + run_count: 4939, + run_time: 5.97596, + success: 4939, + test_id: 'tempest.api.volume.admin.test_snapshots_actions.two', + failureAverage: 0 + }] + }] + }; + expect(testsDetailController.chartData).toEqual(expectedChartData); + }); +}); diff --git a/test/unit/controllers/tests_spec.js b/test/unit/controllers/tests_spec.js index 3988c4c2..ebfdbd23 100644 --- a/test/unit/controllers/tests_spec.js +++ b/test/unit/controllers/tests_spec.js @@ -70,35 +70,8 @@ describe('TestsController', function() { var expectedChartData = { 'tempest': [{ key: 'tempest', - values: [{ - label: 'tempest.api.identity.admin.v2.test_users.one', - value: 0.1 - }], - tests: [{ - failure: 5592, - id: '00187173-ab23-4181-9a15-e291a0d8e2d1', - run_count: 55920, - run_time: 0.608151, - success: 55920, - test_id: 'tempest.api.identity.admin.v2.test_users.one', - failureAverage: 0.1 - }, { - failure: 1, - id: '002a15e0-f6d1-472a-bd66-bb13ac4d77aa', - run_count: 32292, - run_time: 1.18864, - success: 32291, - test_id: 'tempest.api.network.test_routers.three', - failureAverage: 0.0000309674222717701 - }, { - failure: 0, - id: '001c6860-c966-4c0b-9928-ecccd162bed0', - run_count: 4939, - run_time: 5.97596, - success: 4939, - test_id: 'tempest.api.volume.admin.test_snapshots_actions.two', - failureAverage: 0 - }] + values: [], + tests: [] }] }; expect(testsController.chartData).toEqual(expectedChartData);