Add user-selectable date and duration picker.

This adds a new date and duration picker to the crumb menu, along with
functionality in the view service to manage window size preferences
for views and users. Each controller can now specify allowed period
sizes and a preferred default which can be overridden by the user. The
user may also request an arbitrary end date, which defaults to the
current date.

A new library, moment, was added to help with the date caluclations,
as the builtin date utilities lack a huge amount of needed
functionality for computing date differences. Note that a run of
`npm install` may be needed to update local installations to reflect
the change.

Change-Id: I64c1629e527fcf5b4a167fba50c2bb3fe80a2e96
This commit is contained in:
Tim Buckley 2016-01-13 18:02:37 -07:00
parent f95c61d0d6
commit 4473e6e6f6
17 changed files with 464 additions and 84 deletions

View File

@ -7,12 +7,12 @@ var controllersModule = require('./_index');
*/
function GroupedRunsController(
$scope, pageTitleService, healthService, viewService,
runMetadataKey, name, currentDate, $location) {
runMetadataKey, name, $location) {
// ViewModel
var vm = this;
vm.searchJob = '';
vm.searchJob = $location.search().searchJob || '';
// decodeURI is needed here because project names contains slash as part
// of the name. As this come from an URL part and URL can be encoded,
@ -20,6 +20,8 @@ function GroupedRunsController(
vm.runMetadataKey = decodeURIComponent(runMetadataKey);
vm.name = decodeURIComponent(name);
vm.recentRuns = [];
vm.loaded = false;
vm.hold = 0;
// update the global grouping key - if we arrived here directly, it will not
// be set already
@ -28,6 +30,35 @@ function GroupedRunsController(
// Updates the page title based on the selected runMetadataKey
pageTitleService.update(vm.runMetadataKey);
var configurePeriods = function() {
vm.hold += 1;
var res = viewService.resolution();
var min = null;
var max = null;
var preference = null;
if (res.key === 'sec') {
max = { hours: 6 };
preference = { hours: 1 };
} else if (res.key === 'min') {
max = { days: 1 };
preference = { hours: 12 };
} else if (res.key === 'hour') {
min = { hours: 12 };
max = { months: 3 };
preference = { weeks: 2 };
} else if (res.key === 'day') {
min = { hours: 48 };
preference = { months: 3 };
}
viewService.periods(min, max, true);
viewService.preferredDuration(preference);
vm.hold -= 1;
};
vm.processData = function(data) {
// prepare chart data
var jobs = {};
@ -106,26 +137,37 @@ function GroupedRunsController(
};
vm.loadData = function() {
if (vm.hold > 0) {
return;
}
healthService.getRunsForRunMetadataKey(vm.runMetadataKey, vm.name, {
start_date: viewService.windowStart(currentDate, 20),
stop_date: currentDate,
start_date: viewService.periodStart(),
stop_date: viewService.periodEnd(),
datetime_resolution: viewService.resolution().key
}).then(function(response) {
vm.processData(response.data);
vm.loaded = true;
});
healthService.getRecentGroupedRuns(vm.runMetadataKey, vm.name).then(function(response) {
vm.recentRuns = response.data;
});
};
vm.searchJob = $location.search().searchJob || '';
configurePeriods();
vm.loadData();
$scope.$on('view:resolution', function(event, resolution) {
configurePeriods();
vm.loadData();
});
$scope.$on('view:period', function(event, corrected) {
if (vm.loaded && !corrected) {
vm.loadData();
}
});
vm.onSearchChange = function() {
$location.search("searchJob", $scope.groupedRuns.searchJob);
};

View File

@ -5,7 +5,7 @@ var controllersModule = require('./_index');
/**
* @ngInject
*/
function HomeController($scope, healthService, startDate, projectService, viewService, $location) {
function HomeController($scope, healthService, projectService, viewService, $location) {
var byFailRateDesc = function(project1, project2) {
// To get descending order, project2 should come first
@ -16,6 +16,35 @@ function HomeController($scope, healthService, startDate, projectService, viewSe
return entryA.x - entryB.x;
};
var configurePeriods = function() {
vm.hold += 1;
var res = viewService.resolution();
var min = null;
var max = null;
var preference = null;
if (res.key === 'sec') {
max = { hours: 6 };
preference = { hours: 1 };
} else if (res.key === 'min') {
max = { days: 1 };
preference = { hours: 12 };
} else if (res.key === 'hour') {
min = { hours: 12 };
max = { months: 3 };
preference = { months: 1 };
} else if (res.key === 'day') {
min = { hours: 48 };
preference = { months: 3 };
}
viewService.periods(min, max, true);
viewService.preferredDuration(preference);
vm.hold -= 1;
};
var processData = function(data) {
var projects = projectService.createProjects(data.runs);
var blanks = projectService.findBlanks(data.runs);
@ -65,12 +94,20 @@ function HomeController($scope, healthService, startDate, projectService, viewSe
};
};
var loadData = function(runMetadataKey) {
var loadData = function() {
// don't update if configurePeriods() is in progress - it may throw an extra
// period update
if (vm.hold > 0) {
return;
}
healthService.getRunsGroupedByMetadataPerDatetime(vm.groupKey, {
start_date: viewService.windowStart(startDate, 20),
start_date: viewService.periodStart(),
stop_date: viewService.periodEnd(),
datetime_resolution: viewService.resolution().key
}).then(function(response) {
processData(response.data);
vm.loaded = true;
});
};
@ -80,18 +117,29 @@ function HomeController($scope, healthService, startDate, projectService, viewSe
vm.groupKey = viewService.groupKey();
vm.searchProject = $location.search().searchProject || '';
vm.loaded = false;
vm.hold = 0;
configurePeriods();
loadData();
$scope.$on('view:groupKey', function(event, groupKey) {
vm.groupKey = groupKey;
loadData(groupKey);
configurePeriods();
loadData();
});
$scope.$on('view:resolution', function(event, resolution) {
configurePeriods();
loadData();
});
$scope.$on('view:period', function(event, corrected) {
if (vm.loaded && !corrected) {
loadData();
}
});
vm.onSearchChange = function() {
$location.search("searchProject", $scope.home.searchProject);
};

View File

@ -5,13 +5,44 @@ var controllersModule = require('./_index');
/**
* @ngInject
*/
function JobController($scope, healthService, viewService, jobName, startDate, $location) {
function JobController($scope, healthService, viewService, jobName, $location) {
// ViewModel
var vm = this;
vm.searchTest = '';
vm.name = decodeURIComponent(jobName);
vm.recentRuns = [];
vm.loaded = false;
vm.hold = 0;
var configurePeriods = function() {
vm.hold += 1;
var res = viewService.resolution();
var min = null;
var max = null;
var preference = null;
if (res.key === 'sec') {
max = { hours: 6 };
preference = { hours: 1 };
} else if (res.key === 'min') {
max = { days: 1 };
preference = { hours: 12 };
} else if (res.key === 'hour') {
min = { hours: 12 };
max = { months: 1 };
preference = { weeks: 1 };
} else if (res.key === 'day') {
min = { hours: 48 };
preference = { months: 3 };
}
viewService.periods(min, max, true);
viewService.preferredDuration(preference);
vm.hold -= 1;
};
vm.processData = function(data) {
vm.chartData = [];
@ -131,18 +162,17 @@ function JobController($scope, healthService, viewService, jobName, startDate, $
};
vm.loadData = function() {
// Note(mtreinish): this is a hack to make periodic job graphs useful
// until we have a user selectable date window available
var dateWindow = 2;
if (vm.name.indexOf('periodic') > -1) {
dateWindow = 15;
if (vm.hold > 0) {
return;
}
healthService.getTestsFromBuildName(vm.name, {
start_date: viewService.windowStart(startDate, dateWindow),
start_date: viewService.periodStart(),
stop_date: viewService.periodEnd(),
datetime_resolution: viewService.resolution().key
}).then(function(response) {
vm.processData(response.data);
vm.loaded = true;
});
healthService.getRecentGroupedRuns('build_name', vm.name).then(function(response) {
vm.recentRuns = response.data;
@ -151,12 +181,20 @@ function JobController($scope, healthService, viewService, jobName, startDate, $
vm.searchTest = $location.search().searchTest || '';
configurePeriods();
vm.loadData();
$scope.$on('view:resolution', function(event, resolution) {
configurePeriods();
vm.loadData();
});
$scope.$on('view:period', function(event, corrected) {
if (vm.loaded && !corrected) {
vm.loadData();
}
});
vm.onSearchChange = function() {
$location.search("searchTest", $scope.job.searchTest);
};

View File

@ -5,12 +5,43 @@ var controllersModule = require('./_index');
/**
* @ngInject
*/
function TestController($scope, healthService, testService, viewService, startDate, testId) {
function TestController($scope, healthService, testService, viewService, testId) {
// ViewModel
var vm = this;
vm.testName = testId;
vm.testShortName = testService.getShortName(testId);
vm.loaded = false;
vm.hold = 0;
var configurePeriods = function() {
vm.hold += 1;
var res = viewService.resolution();
var min = null;
var max = null;
var preference = null;
if (res.key === 'sec') {
max = { hours: 6 };
preference = { hours: 1 };
} else if (res.key === 'min') {
max = { days: 1 };
preference = { hours: 12 };
} else if (res.key === 'hour') {
min = { hours: 12 };
max = { months: 3 };
preference = { months: 1 };
} else if (res.key === 'day') {
min = { hours: 48 };
preference = { months: 3 };
}
viewService.periods(min, max, true);
viewService.preferredDuration(preference);
vm.hold -= 1;
};
vm.processData = function(data) {
var dates = {};
@ -120,21 +151,32 @@ function TestController($scope, healthService, testService, viewService, startDa
};
vm.loadData = function() {
var stopDate = new Date(startDate);
if (vm.hold > 0) {
return;
}
healthService.getTestRunList(vm.testName, {
start_date: viewService.windowStart(stopDate, 30),
stop_date: stopDate,
start_date: viewService.periodStart(),
stop_date: viewService.periodEnd(),
datetime_resolution: viewService.resolution().key
}).then(function(response) {
vm.processData(response.data);
vm.loaded = true;
});
};
configurePeriods();
vm.loadData();
$scope.$on('view:resolution', function(event, resolution) {
configurePeriods();
vm.loadData();
});
$scope.$on('view:period', function(event, corrected) {
if (vm.loaded && !corrected) {
vm.loadData();
}
});
}
controllersModule.controller('TestController', TestController);

View File

@ -20,6 +20,24 @@ function crumbMenu() {
$scope.selectedResolution = viewService.resolution();
$scope.selectedGroupKey = viewService.groupKey();
$scope.groupKeys = [];
$scope.periodEnd = viewService.periodEnd();
$scope.periodOptions = viewService.periodOptions();
$scope.periods = viewService.periods();
$scope.duration = viewService.duration();
var vm = this;
this.selectedPeriodIndex = '0';
this.selectedPeriodEnd = viewService.periodEnd();
var updatePeriodIndex = function() {
$scope.periodOptions.forEach(function(period, i) {
if (period + 0 == $scope.duration + 0) {
vm.selectedPeriodIndex = i.toString();
}
});
};
updatePeriodIndex();
$scope.setResolution = function(resolution) {
viewService.resolution(resolution);
@ -39,9 +57,35 @@ function crumbMenu() {
$scope.selectedGroupKey = groupKey;
});
$scope.$on('view:periodEnd', function(event, periodEnd) {
$scope.periodEnd = periodEnd;
});
$scope.$on('view:periods', function(event, periods) {
$scope.periods = periods;
});
$scope.$on('view:duration', function(event, duration, corrected) {
$scope.duration = duration;
updatePeriodIndex();
});
healthService.getRunMetadataKeys().then(function(response) {
$scope.groupKeys = response.data;
});
$scope.$watch('menu.selectedPeriodEnd', function(val, old) {
if (val === old) {
return;
}
viewService.periodEnd(val);
});
vm.updateIndex = function() {
var period = $scope.periodOptions[parseInt(vm.selectedPeriodIndex)];
viewService.userDuration(period);
};
};
return {
@ -50,9 +94,11 @@ function crumbMenu() {
templateUrl: 'crumb-menu.html',
link: link,
controller: controller,
controllerAs: 'menu',
scope: {
'showGroupKey': '@',
'showResolution': '@'
'showResolution': '@',
'showPeriod': '@'
}
};
}

View File

@ -9,12 +9,7 @@ function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
url: '/',
controller: 'HomeController as home',
templateUrl: 'home.html',
title: 'Home',
resolve: /*@ngInject*/ {
'startDate': function() {
return new Date();
}
}
title: 'Home'
})
.state('groupedRuns', {
url: '/g/*runMetadataKey/*name',
@ -27,9 +22,6 @@ function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
},
'name': function($stateParams) {
return $stateParams.name;
},
'currentDate': function() {
return new Date();
}
}
})
@ -47,9 +39,6 @@ function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
resolve: /*@ngInject*/ {
'jobName': function($stateParams) {
return $stateParams.jobName;
},
'startDate': function() {
return new Date();
}
}
})
@ -61,9 +50,6 @@ function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
resolve: /*@ngInject*/ {
'testId': function($stateParams) {
return $stateParams.testId;
},
'startDate': function() {
return new Date();
}
}
});

View File

@ -2,15 +2,17 @@
var servicesModule = require('./_index.js');
var moment = require('moment');
/**
* @ngInject
*/
var viewService = function($rootScope, $location) {
var resolutionOptions = [
{ name: 'Second', key: 'sec', window: 0.01 },
{ name: 'Minute', key: 'min', window: 0.5 },
{ name: 'Hour', key: 'hour', window: 1 },
{ name: 'Day', key: 'day', window: 10 }
{ name: 'Second', key: 'sec' },
{ name: 'Minute', key: 'min' },
{ name: 'Hour', key: 'hour' },
{ name: 'Day', key: 'day' }
];
var resolution = resolutionOptions[2];
var groupKey = $location.search().groupKey || 'project';
@ -27,6 +29,41 @@ var viewService = function($rootScope, $location) {
$location.search('resolutionKey', resolution.key);
});
var periodEnd = new Date();
var periodOptions = [
moment.duration({ hours: 1 }),
moment.duration({ hours: 12 }),
moment.duration({ days: 1 }),
moment.duration({ weeks: 1 }),
moment.duration({ weeks: 2 }),
moment.duration({ months: 1 }),
moment.duration({ months: 3 }),
moment.duration({ months: 6 })
];
var preferredDuration = null;
var userDuration = null;
var periods = periodOptions;
var searchDuration = $location.search().duration;
if (searchDuration) {
userDuration = moment.duration(searchDuration);
}
var searchEnd = $location.search().end;
if (searchEnd) {
periodEnd = new Date(searchEnd);
}
var selectDuration = function() {
if (userDuration) {
return userDuration;
} else if (preferredDuration) {
return preferredDuration;
} else {
return periodOptions[0];
}
};
return {
resolution: function(res) {
if (arguments.length === 1) {
@ -37,14 +74,6 @@ var viewService = function($rootScope, $location) {
return resolution;
},
windowStart: function(endDate, days) {
var ret = new Date(endDate);
var diff = Math.ceil(resolution.window * days);
ret.setDate(ret.getDate() - diff);
return ret;
},
resolutionOptions: function() {
return resolutionOptions;
},
@ -56,6 +85,108 @@ var viewService = function($rootScope, $location) {
}
return groupKey;
},
duration: function() {
return selectDuration();
},
periodEnd: function(end) {
if (arguments.length === 0) {
return periodEnd;
}
$location.search('end', end.toISOString());
periodEnd = end;
$rootScope.$broadcast('view:periodEnd', end);
$rootScope.$broadcast('view:period', false);
return end;
},
periodStart: function() {
return moment(periodEnd)
.subtract(selectDuration())
.toDate();
},
periodOptions: function() {
return periodOptions;
},
periods: function(min, max, correct) {
if (arguments.length === 0) {
return periods;
}
correct = (typeof correct === 'undefined' ? false : correct);
var filtered = periodOptions.slice();
if (min) {
var d = moment.duration(min);
filtered = filtered.filter(function(period) {
return period >= d;
});
}
if (max) {
var d = moment.duration(max);
filtered = filtered.filter(function(period) {
return period <= d;
});
}
if (filtered.length === 0) {
throw new Error('Invalid period requirements');
}
periods = filtered;
$rootScope.$broadcast('view:periods', periods);
if (correct && userDuration) {
if (min && userDuration < moment.duration(min)) {
userDuration = filtered[0];
$rootScope.$broadcast('view:duration', userDuration, true);
$rootScope.$broadcast('view:period', true);
} else if (max && userDuration > moment.duration(max)) {
userDuration = filtered[filtered.length - 1];
$rootScope.$broadcast('view:duration', userDuration, true);
$rootScope.$broadcast('view:period', true);
}
}
return filtered;
},
userDuration: function(duration) {
if (arguments.length === 0) {
return userDuration;
}
userDuration = moment.duration(duration);
$rootScope.$broadcast('view:duration', duration, false);
$rootScope.$broadcast('view:period', false);
$location.search('duration', userDuration.toISOString());
return duration;
},
preferredDuration: function(duration) {
if (arguments.length === 0) {
return preferredDuration;
}
preferredDuration = moment.duration(duration);
// if no user override is active, send a notification
if (!userDuration) {
$rootScope.$broadcast('view:duration', preferredDuration, false);
$rootScope.$broadcast('view:period', false);
}
return duration;
}
};
};

View File

@ -23,6 +23,16 @@
</ul>
<div class="container-fluid">
<ul class="nav navbar-nav navbar-right">
<li dropdown ng-if="showPeriod == 'true'">
<a popover-template="'crumb-period-popover.html'"
popover-placement="bottom"
popover-animation="false"
href>
<fa name="calendar"></fa>
&nbsp;Period: {{duration.humanize()}}&nbsp;
<fa name="caret-down"></fa>
</a>
</li>
<li dropdown ng-if="showGroupKey == 'true'">
<a dropdown-toggle href title="Group By Key">
<fa name="key"></fa>

View File

@ -0,0 +1,19 @@
<div>
<label>End Date:</label>
<p class="input-group">
<span class="input-group-addon"><fa name="calendar"></fa></span>
<input ng-model="menu.selectedPeriodEnd" class="form-control" type="date">
</p>
<label>Duration:</label>
<p class="input-group">
<span class="input-group-addon"><fa name="clock-o"></fa></span>
<select class="form-control" ng-model="menu.selectedPeriodIndex" ng-change="menu.updateIndex()">
<option value="{{$index}}"
ng-repeat="period in periodOptions"
ng-disabled="periods.indexOf(period) == -1">
{{period.humanize()}}
</option>
</select>
</p>
</div>

View File

@ -1,7 +1,7 @@
<header class="bs-header">
<div class="container">
<h1 class="page-header">{{ groupedRuns.name }} jobs</h1>
<crumb-menu show-resolution="true">
<crumb-menu show-resolution="true" show-period="true">
<li>{{ groupedRuns.runMetadataKey }}: {{ groupedRuns.name }}</li>
</crumb-menu>
</div>

View File

@ -3,7 +3,9 @@
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">OpenStack Health</h1>
<crumb-menu show-group-key="true" show-resolution="true"></crumb-menu>
<crumb-menu show-group-key="true"
show-resolution="true"
show-period="true"></crumb-menu>
<loading-indicator></loading-indicator>
</div>
</div>

View File

@ -1,7 +1,7 @@
<header class="bs-header">
<div class="container">
<h1 class="page-header">{{ job.name }} tests</h1>
<crumb-menu show-resolution="true">
<crumb-menu show-resolution="true" show-period="true">
<li>Job: {{ job.name }}</li>
</crumb-menu>
</div>

View File

@ -1,7 +1,7 @@
<header class="bs-header">
<div class="container">
<h1 class="page-header">{{ testCtrl.testShortName }}</h1>
<crumb-menu show-resolution="true">
<crumb-menu show-resolution="true" show-period="true">
<li>Test: {{testCtrl.testShortName }}</li>
</crumb-menu>
</div>

View File

@ -56,6 +56,7 @@
"karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "0.2.0",
"karma-spec-reporter": "0.0.20",
"moment": "^2.11.1",
"morgan": "^1.6.1",
"phantomjs": "1.9.17",
"pretty-hrtime": "^1.0.0",

View File

@ -4,9 +4,12 @@ describe('GroupedRunsController', function() {
module('app.controllers');
});
var $scope, $httpBackend, $controller, healthService;
var $scope, $httpBackend, $controller, healthService, viewService;
var API_ROOT = 'http://8.8.4.4:8080';
var DEFAULT_CURRENT_DATE = new Date();
var DEFAULT_END_DATE = new Date();
var DEFAULT_START_DATE = new Date(
(+DEFAULT_END_DATE) -
(1000 * 60 * 60 * 24 * 7));
beforeEach(inject(function($rootScope, _$httpBackend_, _$controller_, _healthService_) {
$scope = $rootScope.$new();
@ -15,13 +18,18 @@ describe('GroupedRunsController', function() {
mockHealthService();
$controller = _$controller_;
healthService = _healthService_;
viewService = {
resolution: function() { return { name: 'Hour', key: 'hour' }; },
groupKey: function() { return 'project'; },
periods: function() {},
preferredDuration: function() {},
periodStart: function() { return DEFAULT_START_DATE; },
periodEnd: function() { return DEFAULT_END_DATE; }
};
}));
function mockHealthService() {
var startDate = new Date(DEFAULT_CURRENT_DATE);
startDate.setDate(startDate.getDate() - 20);
var stopDate = new Date(DEFAULT_CURRENT_DATE);
var expectedResponse = {
timedelta: [
{
@ -63,12 +71,12 @@ describe('GroupedRunsController', function() {
};
var endpoint = API_ROOT +
'/runs/key/project/openstack/cinder?callback=JSON_CALLBACK&' +
'datetime_resolution=hour&' +
'start_date=' + startDate.toISOString() + '&' +
'stop_date=' + stopDate.toISOString();
$httpBackend.expectJSONP(endpoint)
.respond(200, expectedResponse);
'/runs/key/project/openstack/cinder?callback=JSON_CALLBACK&' +
'datetime_resolution=hour&' +
'start_date=' + DEFAULT_START_DATE.toISOString() + '&' +
'stop_date=' + DEFAULT_END_DATE.toISOString();
$httpBackend.expectJSONP(endpoint).respond(200, expectedResponse);
var recentResponse = [
{
@ -119,7 +127,7 @@ describe('GroupedRunsController', function() {
healthService: healthService,
runMetadataKey: 'project',
name: 'openstack/cinder',
currentDate: DEFAULT_CURRENT_DATE
viewService: viewService
});
$httpBackend.flush();
@ -146,7 +154,7 @@ describe('GroupedRunsController', function() {
healthService: healthService,
runMetadataKey: 'project',
name: 'openstack/cinder',
currentDate: DEFAULT_CURRENT_DATE
viewService: viewService
});
$httpBackend.flush();

View File

@ -19,7 +19,6 @@ describe('HomeController', function() {
$scope = $rootScope.$new();
$controller = _$controller_;
var defaultStartDate = new Date();
var healthService = {
getRunsGroupedByMetadataPerDatetime: function(key, options) {
return { then: function(callback) { callback(mockResponse); } };
@ -39,7 +38,6 @@ describe('HomeController', function() {
homeController = $controller('HomeController', {
$scope: $scope,
healthService: healthService,
startDate: defaultStartDate,
projectService: projectService
});
}));

View File

@ -4,9 +4,12 @@ describe('JobController', function() {
module('app.controllers');
});
var $scope, $httpBackend, $controller, healthService;
var $scope, $httpBackend, $controller, healthService, viewService;
var API_ROOT = 'http://8.8.4.4:8080';
var DEFAULT_START_DATE = new Date();
var DEFAULT_END_DATE = new Date();
var DEFAULT_START_DATE = new Date(
(+DEFAULT_END_DATE) -
(1000 * 60 * 60 * 24 * 7));
beforeEach(inject(function($rootScope, _$httpBackend_, _$controller_, _healthService_) {
$httpBackend = _$httpBackend_;
@ -16,12 +19,17 @@ describe('JobController', function() {
$scope = $rootScope.$new();
$controller = _$controller_;
healthService = _healthService_;
viewService = {
resolution: function() { return { name: 'Hour', key: 'hour' }; },
periods: function() {},
preferredDuration: function() {},
periodStart: function() { return DEFAULT_START_DATE; },
periodEnd: function() { return DEFAULT_END_DATE; }
};
}));
function mockHealthService() {
var startDate = new Date(DEFAULT_START_DATE);
startDate.setDate(startDate.getDate() - 2);
var expectedResponse = {
tests: {
"2014-11-19T01:00:00": {
@ -47,13 +55,13 @@ describe('JobController', function() {
}
};
var endpoint = API_ROOT +
'/build_name/gate-tempest-dsvm-neutron-full/test_runs?' +
'callback=JSON_CALLBACK&' +
'datetime_resolution=hour&' +
'start_date=' +
startDate.toISOString();
$httpBackend.expectJSONP(endpoint)
.respond(200, expectedResponse);
'/build_name/gate-tempest-dsvm-neutron-full/test_runs?' +
'callback=JSON_CALLBACK&' +
'datetime_resolution=hour&' +
'start_date=' + DEFAULT_START_DATE.toISOString() + '&' +
'stop_date=' + DEFAULT_END_DATE.toISOString();
$httpBackend.expectJSONP(endpoint).respond(200, expectedResponse);
var recentResponse = [
{
@ -103,7 +111,8 @@ describe('JobController', function() {
$scope: $scope,
healthService: healthService,
jobName: 'gate-tempest-dsvm-neutron-full',
startDate: DEFAULT_START_DATE
startDate: DEFAULT_START_DATE,
viewService: viewService
});
$httpBackend.flush();
@ -137,7 +146,7 @@ describe('JobController', function() {
$scope: $scope,
healthService: healthService,
jobName: 'gate-tempest-dsvm-neutron-full',
startDate: DEFAULT_START_DATE
viewService: viewService
});
$httpBackend.flush();
@ -156,7 +165,7 @@ describe('JobController', function() {
$scope: $scope,
healthService: healthService,
jobName: 'gate-tempest-dsvm-neutron-full',
startDate: DEFAULT_START_DATE
viewService: viewService
});
$httpBackend.flush();