Add filter for signed test results and related UI

With this patch users can list their own test results.

Change-Id: Ie2d944924f6ae966a13d0ca9908810c315ade5ab
This commit is contained in:
sslypushenko 2015-07-22 20:22:53 +03:00
parent 217cadd608
commit 2b89f65ad4
21 changed files with 178 additions and 136 deletions

View File

@ -26,8 +26,13 @@ refstackApp.config([
templateUrl: '/components/capabilities/capabilities.html', templateUrl: '/components/capabilities/capabilities.html',
controller: 'capabilitiesController' controller: 'capabilitiesController'
}). }).
state('results', { state('community_results', {
url: '/results', url: '/community_results',
templateUrl: '/components/results/results.html',
controller: 'resultsController'
}).
state('user_results', {
url: '/user_results',
templateUrl: '/components/results/results.html', templateUrl: '/components/results/results.html',
controller: 'resultsController' controller: 'resultsController'
}). }).
@ -45,19 +50,46 @@ refstackApp.config([
]); ]);
/** /**
* Try to authenticate user * Injections in $rootscope
*/ */
refstackApp.run(['$http', '$rootScope', 'refstackApiUrl', refstackApp.run(['$http', '$rootScope', '$window', 'refstackApiUrl',
function($http, $rootScope, refstackApiUrl) { function($http, $rootScope, $window, refstackApiUrl) {
'use strict'; 'use strict';
/**
* This function injects sign in function in all scopes
*/
$rootScope.auth = {};
var sign_in_url = refstackApiUrl + '/auth/signin';
$rootScope.auth.doSignIn = function () {
$window.location.href = sign_in_url;
};
/**
* This function injects sign out function in all scopes
*/
var sign_out_url = refstackApiUrl + '/auth/signout';
$rootScope.auth.doSignOut = function () {
$rootScope.currentUser = null;
$rootScope.isAuthenticated = false;
$window.location.href = sign_out_url;
};
/**
* This block tries to authenticate user
*/
var profile_url = refstackApiUrl + '/profile'; var profile_url = refstackApiUrl + '/profile';
$http.get(profile_url, {withCredentials: true}). $http.get(profile_url, {withCredentials: true}).
success(function(data) { success(function(data) {
$rootScope.currentUser = data; $rootScope.auth.currentUser = data;
$rootScope.auth.isAuthenticated = true;
}). }).
error(function() { error(function() {
$rootScope.currentUser = null; $rootScope.auth.currentUser = null;
$rootScope.auth.isAuthenticated = false;
}); });
} }
]); ]);

View File

@ -1,29 +0,0 @@
var refstackApp = angular.module('refstackApp');
/**
* Refstack Auth Controller
* This controller handles account authentication for users.
*/
refstackApp.controller('authController',
['$scope', '$window', '$rootScope', 'refstackApiUrl',
function($scope, $window, $rootScope, refstackApiUrl){
'use strict';
var sign_in_url = refstackApiUrl + '/auth/signin';
$scope.doSignIn = function () {
$window.location.href = sign_in_url;
};
var sign_out_url = refstackApiUrl + '/auth/signout';
$scope.doSignOut = function () {
$rootScope.currentUser = null;
$window.location.href = sign_out_url;
};
$scope.isAuthenticated = function () {
if ($scope.currentUser) {
return !!$scope.currentUser.openid;
}
return false;
};
}]);

View File

@ -58,7 +58,7 @@
<div cg-busy="{promise:capsRequest,message:'Loading capabilities'}"></div> <div cg-busy="{promise:capsRequest,message:'Loading capabilities'}"></div>
<!-- Get the version-specific template --> <!-- Get the version-specific template -->
<div ng-include src="detailsTemplate"></header> <div ng-include src="detailsTemplate"></div>
<div ng-show="showError" class="alert alert-danger" role="alert"> <div ng-show="showError" class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>

View File

@ -1,11 +1,11 @@
<h3>User profile</h3> <h3>User profile</h3>
<div ng-show="user"> <div>
<table ng-show="user" class="table table-striped table-hover"> <table class="table table-striped table-hover">
<tbody> <tbody>
<tr> <td>User name</td> <td>{{user.fullname}}</td> </tr> <tr> <td>User name</td> <td>{{auth.currentUser.fullname}}</td> </tr>
<tr> <td>User OpenId</td> <td>{{user.openid}}</td> </tr> <tr> <td>User OpenId</td> <td>{{auth.currentUser.openid}}</td> </tr>
<tr> <td>Email</td> <td>{{user.email}}</td> </tr> <tr> <td>Email</td> <td>{{auth.currentUser.email}}</td> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -22,8 +22,8 @@
</div> </div>
</div> </div>
<div ng-show="pubkeys"> <div>
<table ng-show="pubkeys" class="table table-striped table-hover"> <table class="table table-striped table-hover">
<tbody> <tbody>
<tr ng-repeat="pubKey in pubkeys" ng-click="openShowPubKeyModal(pubKey)"> <tr ng-repeat="pubKey in pubkeys" ng-click="openShowPubKeyModal(pubKey)">
<td>{{pubKey.format}}</td> <td>{{pubKey.format}}</td>
@ -33,4 +33,3 @@
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -19,16 +19,6 @@ refstackApp.controller('profileController',
function($scope, $http, refstackApiUrl, $state, function($scope, $http, refstackApiUrl, $state,
PubKeys, $modal, raiseAlert) { PubKeys, $modal, raiseAlert) {
'use strict'; 'use strict';
$scope.updateProfile = function () {
var profile_url = refstackApiUrl + '/profile';
$http.get(profile_url, {withCredentials: true}).
success(function(data) {
$scope.user = data;
}).
error(function() {
$state.go('home');
});
};
$scope.updatePubKeys = function (){ $scope.updatePubKeys = function (){
var keys = PubKeys.query(function(){ var keys = PubKeys.query(function(){
@ -77,7 +67,6 @@ refstackApp.controller('profileController',
$scope.showRes = function(pubKey){ $scope.showRes = function(pubKey){
raiseAlert('success', '', pubKey.key); raiseAlert('success', '', pubKey.key);
}; };
$scope.updateProfile();
$scope.updatePubKeys(); $scope.updatePubKeys();
} }
]); ]);

View File

@ -1,4 +1,4 @@
<h3>Community Results</h3> <h3>{{pageHeader}}</h3>
<p>The most recently uploaded community test results are listed here. Currently, these results are anonymous.</p> <p>The most recently uploaded community test results are listed here. Currently, these results are anonymous.</p>
<div class="result-filters"> <div class="result-filters">

View File

@ -6,8 +6,8 @@ var refstackApp = angular.module('refstackApp');
* a listing of community uploaded results. * a listing of community uploaded results.
*/ */
refstackApp.controller('resultsController', refstackApp.controller('resultsController',
['$scope', '$http', '$filter', 'refstackApiUrl', ['$scope', '$http', '$filter', '$state', 'refstackApiUrl',
function ($scope, $http, $filter, refstackApiUrl) { function ($scope, $http, $filter, $state, refstackApiUrl) {
'use strict'; 'use strict';
/** Initial page to be on. */ /** Initial page to be on. */
@ -33,6 +33,9 @@ refstackApp.controller('resultsController',
/** The upload date upper limit to be used in filtering results. */ /** The upload date upper limit to be used in filtering results. */
$scope.endDate = ''; $scope.endDate = '';
$scope.isUserResults = $state.current.name === 'user_results';
$scope.pageHeader = $scope.isUserResults ?
'Private test results' : 'Community test results';
/** /**
* This will contact the Refstack API to get a listing of test run * This will contact the Refstack API to get a listing of test run
* results. * results.
@ -51,7 +54,9 @@ refstackApp.controller('resultsController',
if (end) { if (end) {
content_url = content_url + '&end_date=' + end + ' 23:59:59'; content_url = content_url + '&end_date=' + end + ' 23:59:59';
} }
if ($scope.isUserResults) {
content_url = content_url + '&signed';
}
$scope.resultsRequest = $scope.resultsRequest =
$http.get(content_url).success(function (data) { $http.get(content_url).success(function (data) {
$scope.data = data; $scope.data = data;

View File

@ -38,12 +38,11 @@
<!-- Controllers --> <!-- Controllers -->
<script src="shared/header/headerController.js"></script> <script src="shared/header/headerController.js"></script>
<script src="shared/alerts/alertModalFactory.js"></script>
<script src="components/capabilities/capabilitiesController.js"></script> <script src="components/capabilities/capabilitiesController.js"></script>
<script src="components/results/resultsController.js"></script> <script src="components/results/resultsController.js"></script>
<script src="components/results-report/resultsReportController.js"></script> <script src="components/results-report/resultsReportController.js"></script>
<script src="components/profile/profileController.js"></script> <script src="components/profile/profileController.js"></script>
<script src="components/auth/authController.js"></script>
<script src="components/alerts/alertModalFactory.js"></script>
<!-- Filters --> <!-- Filters -->
<script src="shared/filters.js"></script> <script src="shared/filters.js"></script>

View File

@ -5,7 +5,7 @@ refstackApp.factory('raiseAlert',
'use strict'; 'use strict';
return function(mode, title, text) { return function(mode, title, text) {
$modal.open({ $modal.open({
templateUrl: '/components/alerts/alertModal.html', templateUrl: '/shared/alerts/alertModal.html',
controller: 'raiseAlertModalController', controller: 'raiseAlertModalController',
backdrop: true, backdrop: true,
keyboard: true, keyboard: true,

View File

@ -18,14 +18,14 @@ Refstack
<li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li> <li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li>
<li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li> <li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li>
<li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li> <li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li>
<li ng-class="{ active: isActive('/results')}"><a ui-sref="results">Community Results</a></li> <li ng-class="{ active: isActive('/community_results')}"><a ui-sref="community_results">Community Results</a></li>
</ul> </ul>
<ul ng-controller="authController" class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li ng-class="{ active: isActive('/profile')}" ng-if="isAuthenticated()"><a ui-sref="profile">{{currentUser.fullname}}</a></li> <li ng-class="{ active: isActive('/user_results')}" ng-if="auth.isAuthenticated"><a ui-sref="user_results">My Results</a></li>
<li ng-if="isAuthenticated()"><a href="" ng-click="doSignOut()">Sign Out</a></li> <li ng-class="{ active: isActive('/profile')}" ng-if="auth.isAuthenticated"><a ui-sref="profile">Profile</a></li>
<li ng-if="!isAuthenticated()"><a href="" ng-click="doSignIn()">Sign In / Sign Up</a></li> <li ng-if="auth.isAuthenticated"><a href="" ng-click="auth.doSignOut()">Sign Out</a></li>
<li ng-if="!auth.isAuthenticated"><a href="" ng-click="auth.doSignIn()">Sign In / Sign Up</a></li>
</ul> </ul>
</div> </div>
</div> </div>
</nav> </nav>

View File

@ -0,0 +1,40 @@
describe('Auth', function () {
'use strict';
var fakeApiUrl = 'http://foo.bar/v1';
var $window;
beforeEach(function () {
$window = {location: { href: jasmine.createSpy()} };
module(function ($provide) {
$provide.constant('refstackApiUrl', fakeApiUrl);
$provide.value('$window', $window);
});
module('refstackApp');
});
var $rootScope, $httpBackend;
beforeEach(inject(function (_$httpBackend_, _$rootScope_) {
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
}));
it('should show signin url for signed user', function () {
$httpBackend.expectGET(fakeApiUrl +
'/profile').respond({'openid': 'foo@bar.com',
'email': 'foo@bar.com',
'fullname': 'foo' });
$httpBackend.flush();
$rootScope.auth.doSignIn();
expect($window.location.href).toBe(fakeApiUrl + '/auth/signin');
expect($rootScope.auth.isAuthenticated).toBe(true);
});
it('should show signout url for not signed user', function () {
$httpBackend.expectGET(fakeApiUrl +
'/profile').respond(401);
$httpBackend.flush();
$rootScope.auth.doSignOut();
expect($window.location.href).toBe(fakeApiUrl + '/auth/signout');
expect($rootScope.auth.isAuthenticated).toBe(false);
});
});

View File

@ -3,11 +3,18 @@ describe('Refstack controllers', function () {
'use strict'; 'use strict';
var fakeApiUrl = 'http://foo.bar/v1'; var fakeApiUrl = 'http://foo.bar/v1';
var $httpBackend;
beforeEach(function () { beforeEach(function () {
module(function ($provide) { module(function ($provide) {
$provide.constant('refstackApiUrl', fakeApiUrl); $provide.constant('refstackApiUrl', fakeApiUrl);
}); });
module('refstackApp'); module('refstackApp');
inject(function(_$httpBackend_){
$httpBackend = _$httpBackend_;
});
$httpBackend.whenGET(fakeApiUrl + '/profile').respond(401);
$httpBackend.whenGET('/components/home/home.html')
.respond('<div>mock template</div>');
}); });
describe('headerController', function () { describe('headerController', function () {
@ -36,42 +43,10 @@ describe('Refstack controllers', function () {
}); });
}); });
describe('authController', function () {
var scope, $httpBackend, $window;
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
$window = {location: { href: jasmine.createSpy()} };
$controller('authController', {$scope: scope, $window: $window});
}));
it('should show signin url for signed user', function () {
$httpBackend.expectGET(fakeApiUrl +
'/profile').respond({'openid': 'foo@bar.com',
'email': 'foo@bar.com',
'fullname': 'foo' });
$httpBackend.flush();
scope.doSignIn();
expect($window.location.href).toBe(fakeApiUrl + '/auth/signin');
expect(scope.isAuthenticated()).toBe(true);
});
it('should show signout url for not signed user', function () {
$httpBackend.expectGET(fakeApiUrl +
'/profile').respond(401);
$httpBackend.flush();
scope.doSignOut();
expect($window.location.href).toBe(fakeApiUrl + '/auth/signout');
expect(scope.isAuthenticated()).toBe(false);
});
});
describe('capabilitiesController', function () { describe('capabilitiesController', function () {
var scope, $httpBackend; var scope;
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { beforeEach(inject(function ($rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new(); scope = $rootScope.$new();
$controller('capabilitiesController', {$scope: scope}); $controller('capabilitiesController', {$scope: scope});
})); }));
@ -102,8 +77,6 @@ describe('Refstack controllers', function () {
} }
}; };
$httpBackend.expectGET(fakeApiUrl +
'/profile').respond(401);
$httpBackend.expectGET(fakeApiUrl + $httpBackend.expectGET(fakeApiUrl +
'/capabilities').respond(['2015.03.json', '2015.04.json']); '/capabilities').respond(['2015.03.json', '2015.04.json']);
// Should call request with latest version. // Should call request with latest version.
@ -170,7 +143,7 @@ describe('Refstack controllers', function () {
}); });
describe('resultsController', function () { describe('resultsController', function () {
var scope, $httpBackend; var scope;
var fakeResponse = { var fakeResponse = {
'pagination': {'current_page': 1, 'total_pages': 2}, 'pagination': {'current_page': 1, 'total_pages': 2},
'results': [{ 'results': [{
@ -180,8 +153,7 @@ describe('Refstack controllers', function () {
}] }]
}; };
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { beforeEach(inject(function ($rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new(); scope = $rootScope.$new();
$controller('resultsController', {$scope: scope}); $controller('resultsController', {$scope: scope});
})); }));
@ -189,9 +161,8 @@ describe('Refstack controllers', function () {
it('should fetch the first page of results with proper URL args', it('should fetch the first page of results with proper URL args',
function () { function () {
// Initial results should be page 1 of all results. // Initial results should be page 1 of all results.
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401); $httpBackend.expectGET(fakeApiUrl + '/results?page=1')
$httpBackend.expectGET(fakeApiUrl + .respond(fakeResponse);
'/results?page=1').respond(fakeResponse);
$httpBackend.flush(); $httpBackend.flush();
expect(scope.data).toEqual(fakeResponse); expect(scope.data).toEqual(fakeResponse);
expect(scope.currentPage).toBe(1); expect(scope.currentPage).toBe(1);
@ -211,7 +182,6 @@ describe('Refstack controllers', function () {
}); });
it('should set an error when results cannot be retrieved', function () { it('should set an error when results cannot be retrieved', function () {
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
$httpBackend.expectGET(fakeApiUrl + '/results?page=1').respond(404, $httpBackend.expectGET(fakeApiUrl + '/results?page=1').respond(404,
{'detail': 'Not Found'}); {'detail': 'Not Found'});
$httpBackend.flush(); $httpBackend.flush();
@ -224,23 +194,16 @@ describe('Refstack controllers', function () {
it('should have an function to clear filters and update the view', it('should have an function to clear filters and update the view',
function () { function () {
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
$httpBackend.expectGET(fakeApiUrl +
'/results?page=1').respond(fakeResponse);
scope.startDate = 'some date'; scope.startDate = 'some date';
scope.endDate = 'some other date'; scope.endDate = 'some other date';
scope.clearFilters(); scope.clearFilters();
expect(scope.startDate).toBe(null); expect(scope.startDate).toBe(null);
expect(scope.endDate).toBe(null); expect(scope.endDate).toBe(null);
$httpBackend.expectGET(fakeApiUrl +
'/results?page=1').respond(fakeResponse);
$httpBackend.flush();
expect(scope.data).toEqual(fakeResponse);
}); });
}); });
describe('resultsReportController', function () { describe('resultsReportController', function () {
var scope, $httpBackend, stateparams; var scope, stateparams;
var fakeResultResponse = {'results': ['test_id_1']}; var fakeResultResponse = {'results': ['test_id_1']};
var fakeCapabilityResponse = { var fakeCapabilityResponse = {
'platform': {'required': ['compute']}, 'platform': {'required': ['compute']},
@ -261,8 +224,7 @@ describe('Refstack controllers', function () {
} }
}; };
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { beforeEach(inject(function ($rootScope, $controller) {
$httpBackend = _$httpBackend_;
stateparams = {testID: 1234}; stateparams = {testID: 1234};
scope = $rootScope.$new(); scope = $rootScope.$new();
$controller('resultsReportController', $controller('resultsReportController',
@ -272,7 +234,6 @@ describe('Refstack controllers', function () {
it('should make all necessary API requests to get results ' + it('should make all necessary API requests to get results ' +
'and capabilities', 'and capabilities',
function () { function () {
$httpBackend.expectGET(fakeApiUrl + '/profile').respond(401);
$httpBackend.expectGET(fakeApiUrl + $httpBackend.expectGET(fakeApiUrl +
'/results/1234').respond(fakeResultResponse); '/results/1234').respond(fakeResultResponse);
$httpBackend.expectGET(fakeApiUrl + $httpBackend.expectGET(fakeApiUrl +

View File

@ -19,6 +19,7 @@ START_DATE = 'start_date'
END_DATE = 'end_date' END_DATE = 'end_date'
CPID = 'cpid' CPID = 'cpid'
PAGE = 'page' PAGE = 'page'
SIGNED = 'signed'
# OpenID parameters # OpenID parameters
OPENID_MODE = 'openid.mode' OPENID_MODE = 'openid.mode'
@ -36,3 +37,6 @@ OPENID_ERROR = 'openid.error'
# User session parameters # User session parameters
CSRF_TOKEN = 'csrf_token' CSRF_TOKEN = 'csrf_token'
USER_OPENID = 'user_openid' USER_OPENID = 'user_openid'
# Test metadata fields
PUBLIC_KEY = 'public_key'

View File

@ -55,7 +55,7 @@ class ResultsController(validation.BaseRestControllerWithValidation):
if pecan.request.headers.get('X-Public-Key'): if pecan.request.headers.get('X-Public-Key'):
if 'metadata' not in item: if 'metadata' not in item:
item['metadata'] = {} item['metadata'] = {}
item['metadata']['public_key'] = \ item['metadata'][const.PUBLIC_KEY] = \
pecan.request.headers.get('X-Public-Key') pecan.request.headers.get('X-Public-Key')
test_id = db.store_results(item) test_id = db.store_results(item)
LOG.debug(item) LOG.debug(item)
@ -79,6 +79,7 @@ class ResultsController(validation.BaseRestControllerWithValidation):
const.START_DATE, const.START_DATE,
const.END_DATE, const.END_DATE,
const.CPID, const.CPID,
const.SIGNED
] ]
try: try:
@ -88,9 +89,6 @@ class ResultsController(validation.BaseRestControllerWithValidation):
api_utils.get_page_number(records_count) api_utils.get_page_number(records_count)
except api_utils.ParseInputsError as ex: except api_utils.ParseInputsError as ex:
pecan.abort(400, 'Reason: %s' % ex) pecan.abort(400, 'Reason: %s' % ex)
except Exception as ex:
LOG.debug('An error occurred: %s' % ex)
pecan.abort(500)
try: try:
per_page = CONF.api.results_per_page per_page = CONF.api.results_per_page
@ -102,7 +100,8 @@ class ResultsController(validation.BaseRestControllerWithValidation):
'test_id': r.id, 'test_id': r.id,
'created_at': r.created_at, 'created_at': r.created_at,
'cpid': r.cpid, 'cpid': r.cpid,
'url': CONF.api.test_results_url % r.id 'url': parse.urljoin(CONF.ui_url,
CONF.api.test_results_url) % r.id
}) })
page = {'results': results, page = {'results': results,

View File

@ -86,6 +86,16 @@ def parse_input_params(expected_input_params):
'start': const.START_DATE, 'start': const.START_DATE,
'end': const.END_DATE 'end': const.END_DATE
}) })
if const.SIGNED in filters:
if is_authenticated():
filters['openid'] = get_user_id()
filters['pubkeys'] = [
' '.join((pk['format'], pk['key']))
for pk in db.get_user_pubkeys(filters['openid'])
]
else:
raise ParseInputsError('To see signed test '
'results you need to authenticate')
return filters return filters
@ -176,6 +186,11 @@ def get_user():
return db.user_get(get_user_id()) return db.user_get(get_user_id())
def get_user_public_keys():
"""Return db record for authenticated user."""
return db.get_user_pubkeys(get_user_id())
def is_authenticated(): def is_authenticated():
"""Return True if user is authenticated.""" """Return True if user is authenticated."""
if get_user_id(): if get_user_id():

View File

@ -34,6 +34,7 @@ def upgrade():
sa.ForeignKeyConstraint(['openid'], ['user.openid'], ), sa.ForeignKeyConstraint(['openid'], ['user.openid'], ),
mysql_charset=MYSQL_CHARSET mysql_charset=MYSQL_CHARSET
) )
op.create_index('indx_meta_value', 'meta', ['value'], mysql_length=32)
def downgrade(): def downgrade():

View File

@ -117,6 +117,19 @@ def _apply_filters_for_query(query, filters):
if cpid: if cpid:
query = query.filter(models.Test.cpid == cpid) query = query.filter(models.Test.cpid == cpid)
signed = api_const.SIGNED in filters
if signed:
query = (query
.join(models.Test.meta)
.filter(models.TestMeta.meta_key == api_const.PUBLIC_KEY)
.filter(models.TestMeta.value.in_(filters['pubkeys']))
)
else:
signed_results = (query.session
.query(models.TestMeta.test_id)
.filter_by(meta_key=api_const.PUBLIC_KEY))
query = query.filter(models.Test.id.notin_(signed_results))
return query return query

View File

@ -134,7 +134,7 @@ class ResultsControllerTestCase(base.BaseTestCase):
'url': self.test_results_url % 'fake_test_id'}) 'url': self.test_results_url % 'fake_test_id'})
self.assertEqual(mock_response.status, 201) self.assertEqual(mock_response.status, 201)
mock_store_results.assert_called_once_with( mock_store_results.assert_called_once_with(
{'answer': 42, 'metadata': {'public_key': 'fake-key'}} {'answer': 42, 'metadata': {const.PUBLIC_KEY: 'fake-key'}}
) )
@mock.patch('pecan.abort') @mock.patch('pecan.abort')
@ -216,6 +216,7 @@ class ResultsControllerTestCase(base.BaseTestCase):
const.START_DATE, const.START_DATE,
const.END_DATE, const.END_DATE,
const.CPID, const.CPID,
const.SIGNED
] ]
page_number = 1 page_number = 1
total_pages_number = 10 total_pages_number = 10

View File

@ -193,9 +193,12 @@ class DBBackendTestCase(base.BaseTestCase):
self.assertEqual(expected_result, actual_result) self.assertEqual(expected_result, actual_result)
@mock.patch('refstack.db.sqlalchemy.models.Test') @mock.patch('refstack.db.sqlalchemy.models.Test')
def test_apply_filters_for_query(self, mock_model): @mock.patch('refstack.db.sqlalchemy.models.TestMeta')
def test_apply_filters_for_query_unsigned(self, mock_meta,
mock_test):
query = mock.Mock() query = mock.Mock()
mock_model.created_at = six.text_type() mock_test.created_at = six.text_type()
mock_meta.test_id = six.text_type()
filters = { filters = {
api_const.START_DATE: 'fake1', api_const.START_DATE: 'fake1',
@ -205,19 +208,30 @@ class DBBackendTestCase(base.BaseTestCase):
result = api._apply_filters_for_query(query, filters) result = api._apply_filters_for_query(query, filters)
query.filter.assert_called_once_with(mock_model.created_at >= query.filter.assert_called_once_with(mock_test.created_at >=
filters[api_const.START_DATE]) filters[api_const.START_DATE])
query = query.filter.return_value query = query.filter.return_value
query.filter.assert_called_once_with(mock_model.created_at <= query.filter.assert_called_once_with(mock_test.created_at <=
filters[api_const.END_DATE]) filters[api_const.END_DATE])
query = query.filter.return_value query = query.filter.return_value
query.filter.assert_called_once_with(mock_model.cpid == query.filter.assert_called_once_with(mock_test.cpid ==
filters[api_const.CPID]) filters[api_const.CPID])
query = query.filter.return_value query = query.filter.return_value
self.assertEqual(result, query)
query.session.query.assert_called_once_with(mock_meta.test_id)
meta_query = query.session.query.return_value
meta_query.filter_by.\
assert_called_once_with(meta_key=api_const.PUBLIC_KEY)
unsigned_test_id_query = meta_query.filter_by.return_value
mock_test.id.notin_.assert_called_once_with(unsigned_test_id_query)
query.filter.assert_called_once_with(mock_test.id.notin_.return_value)
filtered_query = query.filter.return_value
self.assertEqual(result, filtered_query)
@mock.patch.object(api, '_apply_filters_for_query') @mock.patch.object(api, '_apply_filters_for_query')
@mock.patch.object(api, 'get_session') @mock.patch.object(api, 'get_session')

View File

@ -8,6 +8,5 @@ oslotest>=1.2.0 # Apache-2.0
python-subunit>=0.0.18 python-subunit>=0.0.18
testrepository>=0.0.18 testrepository>=0.0.18
testtools>=0.9.34 testtools>=0.9.34
mysqlclient
six>=1.7.0 six>=1.7.0
pep257>=0.5.0 pep257>=0.5.0