diff --git a/app/js/controllers/home.js b/app/js/controllers/home.js index 2ab7e5f5..63bd76cc 100644 --- a/app/js/controllers/home.js +++ b/app/js/controllers/home.js @@ -109,16 +109,19 @@ function HomeController($scope, healthService, projectService, viewService, $loc processData(response.data); vm.loaded = true; }); + healthService.getRecentFailedTests().then(function(response) { + vm.recentTests = response.data; + }); }; // ViewModel var vm = this; vm.loadData = loadData; vm.groupKey = viewService.groupKey(); - vm.searchProject = $location.search().searchProject || ''; vm.loaded = false; vm.hold = 0; + vm.recentTests = []; configurePeriods(); loadData(); diff --git a/app/js/services/health-api.js b/app/js/services/health-api.js index 4bfa50e9..485af6f0 100644 --- a/app/js/services/health-api.js +++ b/app/js/services/health-api.js @@ -129,6 +129,13 @@ function HealthService($http, config) { }); }); }; + service.getRecentFailedTests = function(options) { + return config.get().then(function(config) { + return $http.jsonp(config.apiRoot + '/tests/recent/fail', { + params: { callback: 'JSON_CALLBACK' } + }); + }); + }; return service; } diff --git a/app/views/home.html b/app/views/home.html index 184b8bf6..179e1218 100644 --- a/app/views/home.html +++ b/app/views/home.html @@ -35,6 +35,35 @@ +
+
+
+
+

Failed Tests in Last 10 Failed Runs

+
+
+ + + + + + + + + + + + + + + + + +
Test IDRun LinkStart TimeStop Time
{{ testRun.test_id | limitTo: 80 }}{{ testRun.link | limitTo: -30 }}{{ testRun.start_time }}{{ testRun.stop_time }}
+
+
+
+
diff --git a/openstack_health/api.py b/openstack_health/api.py index deba7135..2b38a5f5 100644 --- a/openstack_health/api.py +++ b/openstack_health/api.py @@ -291,6 +291,21 @@ def get_recent_runs(run_metadata_key, value): return jsonify(runs) +@app.route('/tests/recent/', methods=['GET']) +def get_recent_test_status(status): + session = get_session() + num_runs = flask.request.args.get('num_runs', 10) + failed_runs = api.get_recent_failed_runs(num_runs, session) + test_runs = api.get_test_runs_by_status_for_run_ids(status, failed_runs, + session=session) + output = [] + for run in test_runs: + run['start_time'] = run['start_time'].isoformat() + run['stop_time'] = run['stop_time'].isoformat() + output.append(run) + return jsonify(output) + + @app.route('/run//tests', methods=['GET']) def get_tests_from_run(run_id): session = get_session() diff --git a/openstack_health/tests/test_api.py b/openstack_health/tests/test_api.py index 1de64ec4..17a8a04d 100644 --- a/openstack_health/tests/test_api.py +++ b/openstack_health/tests/test_api.py @@ -732,3 +732,30 @@ class TestRestAPI(base.TestCase): u'status': 'fail' }] self.assertEqual(expected_res, response_data) + + @mock.patch('subunit2sql.db.api.get_recent_failed_runs', + return_value=['a_convincing_id']) + @mock.patch('subunit2sql.db.api.get_test_runs_by_status_for_run_ids', + return_value=[ + { + 'test_id': u'fake_test', + 'link': u'fake_url', + 'start_time': timestamp_a, + 'stop_time': timestamp_b, + } + ]) + def test_get_recent_test_failures(self, db_mock, recent_mock): + api.Session = mock.MagicMock() + res = self.app.get('/tests/recent/fail') + self.assertEqual(200, res.status_code) + db_mock.assert_called_once_with('fail', ['a_convincing_id'], + session=api.Session()) + response_data = json.loads(res.data) + expected_resp = [ + { + 'test_id': u'fake_test', + 'link': u'fake_url', + 'start_time': timestamp_a.isoformat(), + 'stop_time': timestamp_b.isoformat(), + }] + self.assertEqual(expected_resp, response_data) diff --git a/requirements.txt b/requirements.txt index 82e55545..9c7a8ed2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ # process, which may cause wedges in the gate later. pbr>=1.6 # Apache-2.0 Flask<1.0,>=0.10 # BSD -subunit2sql>=1.2.0 # Apache-2.0 +subunit2sql>=1.3.0 # Apache-2.0 SQLAlchemy<1.1.0,>=1.0.10 # MIT flask-jsonpify # MIT PyMySQL>=0.6.2 # MIT License diff --git a/test/unit/controllers/home_spec.js b/test/unit/controllers/home_spec.js index 67868f0b..0d2a56f6 100644 --- a/test/unit/controllers/home_spec.js +++ b/test/unit/controllers/home_spec.js @@ -14,6 +14,20 @@ describe('HomeController', function() { } } }; + var mockRecentFailed = [ + { + 'link': 'http://logs.openstack.org/97/280597/1/gate/gate-tempest-dsvm-ironic-pxe_ipa/61f4153', + 'start_time': '2016-02-17T11:38:43.185384', + 'stop_time': '2016-02-17T11:50:04.465870', + 'test_id': 'ironic.test_baremetal_basic_ops.BaremetalBasicOps.test_baremetal_server_ops' + }, + { + 'link': 'http://logs.openstack.org/49/277949/2/gate/gate-tempest-dsvm-ironic-pxe_ipa/8ac452c', + 'start_time': '2016-02-17T10:29:32.448360', + 'stop_time': '2016-02-17T10:44:33.880733', + 'test_id': 'ironic.test_baremetal_basic_ops.BaremetalBasicOps.test_baremetal_server_ops' + } + ]; beforeEach(inject(function($rootScope, _$controller_) { $scope = $rootScope.$new(); @@ -27,6 +41,11 @@ describe('HomeController', function() { return { then: function(callback) { callback(mockMetadataKeysResponse); } }; + }, + getRecentFailedTests: function() { + return { + then: function(callback) { callback(mockRecentFailed); } + }; } }; projectService = {