136 lines
5.3 KiB
Python
136 lines
5.3 KiB
Python
import operator, unittest
|
|
import json
|
|
from django.test import client
|
|
from autotest_lib.frontend.afe import frontend_test_utils, models as afe_models
|
|
|
|
class ResourceTestCase(unittest.TestCase,
|
|
frontend_test_utils.FrontendTestMixin):
|
|
URI_PREFIX = None # subclasses may override this to use partial URIs
|
|
|
|
def setUp(self):
|
|
super(ResourceTestCase, self).setUp()
|
|
self._frontend_common_setup()
|
|
self._setup_debug_user()
|
|
self.client = client.Client()
|
|
|
|
|
|
def tearDown(self):
|
|
super(ResourceTestCase, self).tearDown()
|
|
self._frontend_common_teardown()
|
|
|
|
|
|
def _setup_debug_user(self):
|
|
user = afe_models.User.objects.create(login='debug_user')
|
|
acl = afe_models.AclGroup.objects.get(name='my_acl')
|
|
user.aclgroup_set.add(acl)
|
|
|
|
|
|
def _expected_status(self, method):
|
|
if method == 'post':
|
|
return 201
|
|
if method == 'delete':
|
|
return 204
|
|
return 200
|
|
|
|
|
|
def raw_request(self, method, uri, **kwargs):
|
|
method = method.lower()
|
|
if method == 'put':
|
|
# the put() implementation in Django's test client is poorly
|
|
# implemented and only supports url-encoded keyvals for the data.
|
|
# the post() implementation is correct, though, so use that, with a
|
|
# trick to override the method.
|
|
method = 'post'
|
|
kwargs['REQUEST_METHOD'] = 'PUT'
|
|
|
|
client_method = getattr(self.client, method)
|
|
return client_method(uri, **kwargs)
|
|
|
|
|
|
def request(self, method, uri, encode_body=True, **kwargs):
|
|
expected_status = self._expected_status(method)
|
|
|
|
if 'data' in kwargs:
|
|
kwargs.setdefault('content_type', 'application/json')
|
|
if kwargs['content_type'] == 'application/json':
|
|
kwargs['data'] = json.dumps(kwargs['data'])
|
|
|
|
if uri.startswith('http://'):
|
|
full_uri = uri
|
|
else:
|
|
assert self.URI_PREFIX
|
|
full_uri = self.URI_PREFIX + '/' + uri
|
|
|
|
response = self.raw_request(method, full_uri, **kwargs)
|
|
self.assertEquals(
|
|
response.status_code, expected_status,
|
|
'Requesting %s\nExpected %s, got %s: %s (headers: %s)'
|
|
% (full_uri, expected_status, response.status_code,
|
|
response.content, response._headers))
|
|
|
|
if response['content-type'] != 'application/json':
|
|
return response.content
|
|
|
|
try:
|
|
return json.loads(response.content)
|
|
except ValueError:
|
|
self.fail('Invalid reponse body: %s' % response.content)
|
|
|
|
|
|
def sorted_by(self, collection, attribute):
|
|
return sorted(collection, key=operator.itemgetter(attribute))
|
|
|
|
|
|
def _read_attribute(self, item, attribute_or_list):
|
|
if isinstance(attribute_or_list, basestring):
|
|
attribute_or_list = [attribute_or_list]
|
|
for attribute in attribute_or_list:
|
|
item = item[attribute]
|
|
return item
|
|
|
|
|
|
def check_collection(self, collection, attribute_or_list, expected_list,
|
|
length=None, check_number=None):
|
|
"""Check the members of a collection of dicts.
|
|
|
|
@param collection: an iterable of dicts
|
|
@param attribute_or_list: an attribute or list of attributes to read.
|
|
the results will be sorted and compared with expected_list. if
|
|
a list of attributes is given, the attributes will be read
|
|
hierarchically, i.e. item[attribute1][attribute2]...
|
|
@param expected_list: list of expected values
|
|
@param check_number: if given, only check this number of entries
|
|
@param length: expected length of list, only necessary if check_number
|
|
is given
|
|
"""
|
|
actual_list = sorted(self._read_attribute(item, attribute_or_list)
|
|
for item in collection['members'])
|
|
if length is None and check_number is None:
|
|
length = len(expected_list)
|
|
if length is not None:
|
|
self.assertEquals(len(actual_list), length,
|
|
'Expected %s, got %s: %s'
|
|
% (length, len(actual_list),
|
|
', '.join(str(item) for item in actual_list)))
|
|
if check_number:
|
|
actual_list = actual_list[:check_number]
|
|
self.assertEquals(actual_list, expected_list)
|
|
|
|
|
|
def check_relationship(self, resource_uri, relationship_name,
|
|
other_entry_name, field, expected_values,
|
|
length=None, check_number=None):
|
|
"""Check the members of a relationship collection.
|
|
|
|
@param resource_uri: URI of base resource
|
|
@param relationship_name: name of relationship attribute on base
|
|
resource
|
|
@param other_entry_name: name of other entry in relationship
|
|
@param field: name of field to grab on other entry
|
|
@param expected values: list of expected values for the given field
|
|
"""
|
|
response = self.request('get', resource_uri)
|
|
relationship_uri = response[relationship_name]['href']
|
|
relationships = self.request('get', relationship_uri)
|
|
self.check_collection(relationships, [other_entry_name, field],
|
|
expected_values, length, check_number)
|