[ckan-changes] commit/ckan: 5 new changesets
Bitbucket
commits-noreply at bitbucket.org
Thu Jul 7 21:01:53 UTC 2011
5 new changesets in ckan:
http://bitbucket.org/okfn/ckan/changeset/34cab6558001/
changeset: 34cab6558001
branch: defect-1214-api-improvements
user: dread
date: 2011-07-07 21:33:11
summary: [model,logic][xs]: Little tidy-ups to do with relationships.
affected #: 3 files (1.7 KB)
--- a/ckan/logic/action/create.py Thu Jul 07 20:03:18 2011 +0100
+++ b/ckan/logic/action/create.py Thu Jul 07 20:33:11 2011 +0100
@@ -91,7 +91,7 @@
user = context['user']
id = context["id"]
id2 = context["id2"]
- rel = context["rel"]
+ rel_type = context["rel"]
api = context.get('api_version') or '1'
ref_package_by = 'id' if api == '2' else 'name'
@@ -112,14 +112,14 @@
##FIXME should have schema
comment = data_dict.get('comment', u'')
- existing_rels = pkg1.get_relationships_with(pkg2, rel)
+ existing_rels = pkg1.get_relationships_with(pkg2, rel_type)
if existing_rels:
return _update_package_relationship(existing_rels[0],
comment, context)
rev = model.repo.new_revision()
rev.author = user
- rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel, pkg2)
- rel = pkg1.add_relationship(rel, pkg2, comment=comment)
+ rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel_type, pkg2)
+ rel = pkg1.add_relationship(rel_type, pkg2, comment=comment)
model.repo.commit_and_remove()
relationship_dicts = rel.as_dict(ref_package_by=ref_package_by)
return relationship_dicts
--- a/ckan/model/package.py Thu Jul 07 20:03:18 2011 +0100
+++ b/ckan/model/package.py Thu Jul 07 20:33:11 2011 +0100
@@ -225,7 +225,7 @@
subject = related_package
object_ = self
else:
- raise NotImplementedError, 'Package relationship type: %r' % type_
+ raise KeyError, 'Package relationship type: %r' % type_
rels = self.get_relationships(with_package=related_package,
type=type_, active=False, direction="forward")
--- a/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 20:03:18 2011 +0100
+++ b/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 20:33:11 2011 +0100
@@ -1,4 +1,5 @@
from nose.tools import assert_equal
+from nose.plugins.skip import SkipTest
from ckan import model
@@ -116,6 +117,21 @@
expected = []
self.check_relationships_rest('warandpeace', 'annakarenina', expected)
+ def test_create_relationship_unknown(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'unheard_of_type', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':self.comment})
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
+ def test_create_relationship_incorrectly(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'relationships', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'type':'parent_of'})
+ # type should do in the URL offset, not the params.
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
def create_annakarenina_parent_of_war_and_peace(self):
# Create package relationship.
# Todo: Redesign this in a RESTful style, so that a relationship is
@@ -124,6 +140,12 @@
postparams = '%s=1' % self.dumps({'comment':self.comment})
res = self.app.post(offset, params=postparams, status=[201],
extra_environ=self.extra_environ)
+ # Check the response
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
# Check the model, directly.
rels = self.anna.get_relationships()
assert len(rels) == 1, rels
@@ -135,12 +157,25 @@
offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
postparams = '%s=1' % self.dumps({'comment':comment})
res = self.app.post(offset, params=postparams, status=[201], extra_environ=self.extra_environ)
+ # Check the response (normalised to 'child_of')
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ import pdb; pdb.set_trace()
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
+ # Check the model, directly (normalised to 'child_of')
+ rels = self.anna.get_relationships()
+ assert len(rels) == 1, rels
+ assert rels[0].type == 'child_of'
+ assert rels[0].subject.name == 'warandpeace'
+ assert rels[0].object.name == 'annakarenina'
return res
def delete_annakarenina_parent_of_war_and_peace(self):
offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
res = self.app.delete(offset, status=[200], extra_environ=self.extra_environ)
- return res
+ assert not res.body
def get_relationships(self, package1_name=u'annakarenina', type='relationships', package2_name=None):
offset = self.relationship_offset(package1_name, type, package2_name)
http://bitbucket.org/okfn/ckan/changeset/b6c7760aea49/
changeset: b6c7760aea49
branch: defect-1214-api-improvements
user: dread
date: 2011-07-07 21:35:25
summary: [tests][xs]: Remove stray pdb.
affected #: 1 file (36 bytes)
--- a/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 20:33:11 2011 +0100
+++ b/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 20:35:25 2011 +0100
@@ -160,7 +160,6 @@
# Check the response (normalised to 'child_of')
rel = self.loads(res.body)
assert_equal(rel['type'], 'child_of')
- import pdb; pdb.set_trace()
assert_equal(rel['subject'], self.ref_package(self.war))
assert_equal(rel['object'], self.ref_package(self.anna))
http://bitbucket.org/okfn/ckan/changeset/fc09267587fc/
changeset: fc09267587fc
branch: defect-1214-api-improvements
user: dread
date: 2011-07-07 21:46:21
summary: [branch] close.
affected #: 0 files (0 bytes)
http://bitbucket.org/okfn/ckan/changeset/be2be28660b1/
changeset: be2be28660b1
user: dread
date: 2011-07-07 21:46:38
summary: [merge] from defect-1214-api-improvements.
affected #: 22 files (37.4 KB)
--- a/ckan/controllers/api.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/controllers/api.py Thu Jul 07 20:46:38 2011 +0100
@@ -30,10 +30,6 @@
}
class ApiController(BaseController):
- content_type_text = 'text/;charset=utf-8'
- content_type_html = 'text/html;charset=utf-8'
- content_type_json = 'application/json;charset=utf-8'
-
def __call__(self, environ, start_response):
self._identify_user()
if not self.authorizer.am_authorized(c, model.Action.SITE_READ, model.System):
@@ -45,6 +41,8 @@
start_response(body, response.headers.items())
return [response_msg]
else:
+ # avoid status_code_redirect intercepting error responses
+ environ['pylons.status_code_redirect'] = True
return BaseController.__call__(self, environ, start_response)
def _finish(self, status_int, response_data=None,
@@ -106,6 +104,14 @@
response_data=response_data,
content_type='json')
+ def _finish_bad_request(self, extra_msg=None):
+ response_data = _('Bad request')
+ if extra_msg:
+ response_data = '%s - %s' % (response_data, extra_msg)
+ return self._finish(status_int=400,
+ response_data=response_data,
+ content_type='json')
+
def _wrap_jsonp(self, callback, response_msg):
return '%s(%s);' % (callback, response_msg)
@@ -140,8 +146,8 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot list entity of this type: %s') % register
+ return self._finish_bad_request(
+ gettext('Cannot list entity of this type: %s') % register)
try:
return self._finish_ok(action(context))
except NotFound, e:
@@ -151,7 +157,6 @@
return self._finish_not_authz()
def show(self, ver=None, register=None, subregister=None, id=None, id2=None):
-
action_map = {
'revision': get.revision_show,
'group': get.group_show_rest,
@@ -171,8 +176,8 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot read entity of this type: %s') % register
+ return self._finish_bad_request(
+ gettext('Cannot read entity of this type: %s') % register)
try:
return self._finish_ok(action(context))
@@ -205,15 +210,16 @@
try:
request_data = self._get_request_data()
except ValueError, inst:
- response.status_int = 400
- return gettext('JSON Error: %s') % str(inst)
+ return self._finish_bad_request(
+ gettext('JSON Error: %s') % str(inst))
action = action_map.get((register, subregister))
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot create new entity of this type: %s %s') % (register, subregister)
+ return self._finish_bad_request(
+ gettext('Cannot create new entity of this type: %s %s') % \
+ (register, subregister))
try:
response_data = action(request_data, context)
location = None
@@ -251,15 +257,15 @@
try:
request_data = self._get_request_data()
except ValueError, inst:
- response.status_int = 400
- return gettext('JSON Error: %s') % str(inst)
+ return self._finish_bad_request(
+ gettext('JSON Error: %s') % str(inst))
action = action_map.get((register, subregister))
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot update entity of this type: %s') % \
- register.encode('utf-8')
+ return self._finish_bad_request(
+ gettext('Cannot update entity of this type: %s') % \
+ register.encode('utf-8'))
try:
response_data = action(request_data, context)
return self._finish_ok(response_data)
@@ -294,8 +300,9 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot delete entity of this type: %s %s') % (register, subregister or '')
+ return self._finish_bad_request(
+ gettext('Cannot delete entity of this type: %s %s') %\
+ (register, subregister or ''))
try:
response_data = action(context)
return self._finish_ok(response_data)
@@ -315,29 +322,31 @@
since_time = None
if request.params.has_key('since_id'):
id = request.params['since_id']
+ if not id:
+ return self._finish_bad_request(
+ gettext(u'No revision specified'))
rev = model.Session.query(model.Revision).get(id)
if rev is None:
- response.status_int = 400
- return gettext(u'There is no revision with id: %s') % id
+ return self._finish_not_found(
+ gettext(u'There is no revision with id: %s') % id)
since_time = rev.timestamp
elif request.params.has_key('since_time'):
since_time_str = request.params['since_time']
try:
since_time = model.strptimestamp(since_time_str)
except ValueError, inst:
- response.status_int = 400
- return 'ValueError: %s' % inst
+ return self._finish_bad_request('ValueError: %s' % inst)
else:
- response.status_int = 400
- return gettext("Missing search term ('since_id=UUID' or 'since_time=TIMESTAMP')")
+ return self._finish_bad_request(
+ gettext("Missing search term ('since_id=UUID' or 'since_time=TIMESTAMP')"))
revs = model.Session.query(model.Revision).filter(model.Revision.timestamp>since_time)
return self._finish_ok([rev.id for rev in revs])
elif register == 'package' or register == 'resource':
try:
params = self._get_search_params(request.params)
except ValueError, e:
- response.status_int = 400
- return gettext('Could not read parameters: %r' % e)
+ return self._finish_bad_request(
+ gettext('Could not read parameters: %r' % e))
options = QueryOptions()
for k, v in params.items():
if (k in DEFAULT_OPTIONS.keys()):
@@ -373,11 +382,11 @@
return self._finish_ok(results)
except SearchError, e:
log.exception(e)
- response.status_int = 400
- return gettext('Bad search option: %s') % e
+ return self._finish_bad_request(
+ gettext('Bad search option: %s') % e)
else:
- response.status_int = 404
- return gettext('Unknown register: %s') % register
+ return self._finish_not_found(
+ gettext('Unknown register: %s') % register)
@classmethod
def _get_search_params(cls, request_params):
--- a/ckan/lib/base.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/lib/base.py Thu Jul 07 20:46:38 2011 +0100
@@ -146,22 +146,25 @@
'''
cls.log.debug('Retrieving request params: %r' % request.params)
cls.log.debug('Retrieving request POST: %r' % request.POST)
-
+ request_data = None
if request.POST:
try:
- request_data = request.POST.keys() or request.body
+ request_data = request.POST.keys()
except Exception, inst:
msg = _("Could not find the POST data: %r : %s") % \
(request.POST, inst)
raise ValueError, msg
request_data = request_data[0]
- elif request.body:
- cls.log.debug('Retrieving request POST body: %r' % request.body)
+ else:
try:
request_data = request.body
except Exception, inst:
- msg = _("Could not find the POST data: %r : %s") % \
- (request.POST, inst)
+ msg = _("Could not extract request body data: %s") % \
+ (inst)
+ raise ValueError, msg
+ cls.log.debug('Retrieved request body: %r' % request.body)
+ if not request_data:
+ msg = _("No request body data")
raise ValueError, msg
if request_data:
request_data = json.loads(request_data, encoding='utf8')
--- a/ckan/lib/dictization/model_save.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/lib/dictization/model_save.py Thu Jul 07 20:46:38 2011 +0100
@@ -67,9 +67,6 @@
def package_extras_save(extra_dicts, obj, context):
- allow_partial_update = context.get("allow_partial_update", False)
- if not extra_dicts and allow_partial_update:
- return
model = context["model"]
session = context["session"]
@@ -81,7 +78,10 @@
for extra_dict in extra_dicts:
if extra_dict.get("deleted"):
continue
- if extras_as_string:
+
+ if extra_dict['value'] is None:
+ pass
+ elif extras_as_string:
new_extras[extra_dict["key"]] = extra_dict["value"]
else:
new_extras[extra_dict["key"]] = json.loads(extra_dict["value"])
@@ -318,10 +318,15 @@
updated_extras.update(value)
new_value = []
+
for extras_key, extras_value in updated_extras.iteritems():
if extras_value is not None:
new_value.append({"key": extras_key,
"value": json.dumps(extras_value)})
+ else:
+ new_value.append({"key": extras_key,
+ "value": None})
+
dictized[key] = new_value
groups = dictized.pop('groups', None)
--- a/ckan/logic/action/create.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/logic/action/create.py Thu Jul 07 20:46:38 2011 +0100
@@ -91,7 +91,7 @@
user = context['user']
id = context["id"]
id2 = context["id2"]
- rel = context["rel"]
+ rel_type = context["rel"]
api = context.get('api_version') or '1'
ref_package_by = 'id' if api == '2' else 'name'
@@ -112,14 +112,14 @@
##FIXME should have schema
comment = data_dict.get('comment', u'')
- existing_rels = pkg1.get_relationships_with(pkg2, rel)
+ existing_rels = pkg1.get_relationships_with(pkg2, rel_type)
if existing_rels:
return _update_package_relationship(existing_rels[0],
comment, context)
rev = model.repo.new_revision()
rev.author = user
- rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel, pkg2)
- rel = pkg1.add_relationship(rel, pkg2, comment=comment)
+ rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel_type, pkg2)
+ rel = pkg1.add_relationship(rel_type, pkg2, comment=comment)
model.repo.commit_and_remove()
relationship_dicts = rel.as_dict(ref_package_by=ref_package_by)
return relationship_dicts
--- a/ckan/logic/action/get.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/logic/action/get.py Thu Jul 07 20:46:38 2011 +0100
@@ -212,7 +212,7 @@
def tag_show(context):
model = context['model']
- api = context.get('api') or '1'
+ api = context.get('api_version') or '1'
id = context['id']
ref_package_by = 'id' if api == '2' else 'name'
obj = model.Tag.get(id) #TODO tags
--- a/ckan/logic/action/update.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/logic/action/update.py Thu Jul 07 20:46:38 2011 +0100
@@ -6,7 +6,12 @@
from ckan.plugins import PluginImplementations, IGroupController, IPackageController
from ckan.logic import NotFound, check_access, NotAuthorized, ValidationError
from ckan.lib.base import _
-from ckan.lib.dictization.model_dictize import group_dictize, package_dictize
+from ckan.lib.dictization.model_dictize import (package_dictize,
+ package_to_api1,
+ package_to_api2,
+ group_dictize,
+ group_to_api1,
+ group_to_api2)
from ckan.lib.dictization.model_save import (group_api_to_dict,
package_api_to_dict,
group_dict_save,
@@ -171,7 +176,7 @@
if 'message' in context:
rev.message = context['message']
else:
- rev.message = _(u'REST API: Create object %s') % data.get("name")
+ rev.message = _(u'REST API: Update object %s') % data.get("name")
pkg = package_dict_save(data, context)
@@ -255,7 +260,7 @@
if 'message' in context:
rev.message = context['message']
else:
- rev.message = _(u'REST API: Create object %s') % data.get("name")
+ rev.message = _(u'REST API: Update object %s') % data.get("name")
group = group_dict_save(data, context)
@@ -274,19 +279,38 @@
model = context['model']
id = context["id"]
+ api = context.get('api_version') or '1'
pkg = model.Package.get(id)
context["package"] = pkg
context["allow_partial_update"] = True
dictized_package = package_api_to_dict(data_dict, context)
- return package_update(dictized_package, context)
+ dictized_after = package_update(dictized_package, context)
+
+ pkg = context['package']
+
+ if api == '1':
+ package_dict = package_to_api1(pkg, context)
+ else:
+ package_dict = package_to_api2(pkg, context)
+
+ return package_dict
def group_update_rest(data_dict, context):
model = context['model']
id = context["id"]
+ api = context.get('api_version') or '1'
group = model.Group.get(id)
context["group"] = group
context["allow_partial_update"] = True
dictized_package = group_api_to_dict(data_dict, context)
- return group_update(dictized_package, context)
+ dictized_after = group_update(dictized_package, context)
+ group = context['group']
+
+ if api == '1':
+ group_dict = group_to_api1(group, context)
+ else:
+ group_dict = group_to_api2(group, context)
+
+ return group_dict
--- a/ckan/logic/schema.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/logic/schema.py Thu Jul 07 20:46:38 2011 +0100
@@ -167,7 +167,7 @@
schema = {
'id': [ignore],
'key': [not_empty, unicode],
- 'value': [not_missing, unicode],
+ 'value': [not_missing],
'state': [ignore],
'deleted': [ignore_missing],
'revision_timestamp': [ignore],
--- a/ckan/model/package.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/model/package.py Thu Jul 07 20:46:38 2011 +0100
@@ -225,7 +225,7 @@
subject = related_package
object_ = self
else:
- raise NotImplementedError, 'Package relationship type: %r' % type_
+ raise KeyError, 'Package relationship type: %r' % type_
rels = self.get_relationships(with_package=related_package,
type=type_, active=False, direction="forward")
--- a/ckan/tests/functional/api/base.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/base.py Thu Jul 07 20:46:38 2011 +0100
@@ -69,7 +69,7 @@
return '%s%s' % (base, path)
def package_offset(self, package_name=None):
- if package_name == None:
+ if package_name is None:
# Package Register
return self.offset('/rest/package')
else:
@@ -79,14 +79,14 @@
def package_ref_from_name(self, package_name):
package = self.get_package_by_name(unicode(package_name))
- if package == None:
+ if package is None:
return package_name
else:
return self.ref_package(package)
def package_id_from_ref(self, package_name):
package = self.get_package_by_name(unicode(package_name))
- if package == None:
+ if package is None:
return package_name
else:
return self.ref_package(package)
@@ -96,7 +96,7 @@
return getattr(package, self.ref_package_by)
def group_offset(self, group_name=None):
- if group_name == None:
+ if group_name is None:
# Group Register
return self.offset('/rest/group')
else:
@@ -106,7 +106,7 @@
def group_ref_from_name(self, group_name):
group = self.get_group_by_name(unicode(group_name))
- if group == None:
+ if group is None:
return group_name
else:
return self.ref_group(group)
@@ -115,11 +115,52 @@
assert self.ref_group_by in ['id', 'name']
return getattr(group, self.ref_group_by)
+ def revision_offset(self, revision_id=None):
+ if revision_id is None:
+ # Revision Register
+ return self.offset('/rest/revision')
+ else:
+ # Revision Entity
+ return self.offset('/rest/revision/%s' % revision_id)
+
+ def rating_offset(self, package_name=None):
+ if package_name is None:
+ # Revision Register
+ return self.offset('/rest/rating')
+ else:
+ # Revision Entity
+ package_ref = self.package_ref_from_name(package_name)
+ return self.offset('/rest/rating/%s' % package_ref)
+
+ def relationship_offset(self, package_1_name=None,
+ relationship_type=None,
+ package_2_name=None,
+ ):
+ assert package_1_name
+ package_1_ref = self.package_ref_from_name(package_1_name)
+ if package_2_name is None:
+ if not relationship_type:
+ return self.offset('/rest/package/%s/relationships' % \
+ package_1_ref)
+ else:
+ return self.offset('/rest/package/%s/%s' %
+ (package_1_ref, relationship_type))
+ else:
+ package_2_ref = self.package_ref_from_name(package_2_name)
+ if not relationship_type:
+ return self.offset('/rest/package/%s/relationships/%s' % \
+ (package_1_ref, package_2_ref))
+ else:
+ return self.offset('/rest/package/%s/%s/%s' % \
+ (package_1_ref,
+ relationship_type,
+ package_2_ref))
+
def anna_offset(self, postfix=''):
return self.package_offset('annakarenina') + postfix
def tag_offset(self, tag_name=None):
- if tag_name == None:
+ if tag_name is None:
# Tag Register
return self.offset('/rest/tag')
else:
@@ -129,7 +170,7 @@
def tag_ref_from_name(self, tag_name):
tag = self.get_tag_by_name(unicode(tag_name))
- if tag == None:
+ if tag is None:
return tag_name
else:
return self.ref_tag(tag)
@@ -199,9 +240,10 @@
def assert_msg_represents_russian(self, msg):
data = self.loads(msg)
pkgs = set(data)
- expected_pkgs = set(['annakarenina', 'warandpeace'])
- missing_pkgs = expected_pkgs - pkgs
- assert not missing_pkgs, missing_pkgs
+ expected_pkgs = set([self.package_ref_from_name('annakarenina'),
+ self.package_ref_from_name('warandpeace')])
+ differences = expected_pkgs ^ pkgs
+ assert not differences, '%r != %r' % (pkgs, expected_pkgs)
def data_from_res(self, res):
return self.loads(res.body)
@@ -218,6 +260,16 @@
except ValueError, inst:
raise Exception, "Couldn't loads string '%s': %s" % (chars, inst)
+ def assert_json_response(self, res, expected_in_body=None):
+ content_type = res.header_dict['Content-Type']
+ assert 'application/json' in content_type, content_type
+ res_json = self.loads(res.body)
+ if expected_in_body:
+ assert expected_in_body in res_json or \
+ expected_in_body in str(res_json), \
+ 'Expected to find %r in JSON response %r' % \
+ (expected_in_body, res_json)
+
# Todo: Rename to Version1TestCase.
class Api1TestCase(ApiTestCase):
@@ -297,8 +349,6 @@
def teardown(self):
model.Session.remove()
model.repo.rebuild_db()
- #self.delete_common_fixtures()
- #self.commit_remove()
super(BaseModelApiTestCase, self).teardown()
def init_extra_environ(self):
@@ -312,10 +362,38 @@
application/x-www-form-urlencoded)
'''
+ return self.http_request(offset, data, content_type='application/json',
+ request_method='POST',
+ content_length=len(data),
+ status=status, extra_environ=extra_environ)
+
+ def delete_request(self, offset, status=None, extra_environ=None):
+ ''' Sends a delete request. Similar to the paste.delete but it
+ does not send the content type or content length.
+ '''
+ return self.http_request(offset, data='', content_type=None,
+ request_method='DELETE',
+ content_length=None,
+ status=status,
+ extra_environ=extra_environ)
+
+ def http_request(self, offset, data,
+ content_type='application/json',
+ request_method='POST',
+ content_length=None,
+ status=None,
+ extra_environ=None):
+ ''' Posts data in the body in a user-specified format.
+ (rather than Paste Fixture\'s default Content-Type of
+ application/x-www-form-urlencoded)
+
+ '''
environ = self.app._make_environ()
- environ['CONTENT_TYPE'] = 'application/json'
- environ['CONTENT_LENGTH'] = str(len(data))
- environ['REQUEST_METHOD'] = 'POST'
+ if content_type:
+ environ['CONTENT_TYPE'] = content_type
+ if content_length is not None:
+ environ['CONTENT_LENGTH'] = str(content_length)
+ environ['REQUEST_METHOD'] = request_method
environ['wsgi.input'] = StringIO(data)
if extra_environ:
environ.update(extra_environ)
--- a/ckan/tests/functional/api/model/test_group.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/model/test_group.py Thu Jul 07 20:46:38 2011 +0100
@@ -1,5 +1,7 @@
import copy
+from ckan import model
+
from nose.tools import assert_equal
from ckan.tests.functional.api.base import BaseModelApiTestCase
@@ -29,6 +31,10 @@
# check group object
group = self.get_group_by_name(self.testgroupvalues['name'])
assert group
+ assert group.title == self.testgroupvalues['title'], group
+ assert group.description == self.testgroupvalues['description'], group
+ pkg_names = [pkg.name for pkg in group.packages]
+ assert set(pkg_names) == set(('annakarenina', 'warandpeace')), pkg_names
# check register updated
res = self.app.get(offset, status=self.STATUS_200_OK)
@@ -53,11 +59,15 @@
res = self.app.post(offset, params=postparams,
status=self.STATUS_409_CONFLICT,
extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'Group name already exists')
def test_entity_get_ok(self):
offset = self.group_offset(self.roger.name)
res = self.app.get(offset, status=self.STATUS_200_OK)
self.assert_msg_represents_roger(msg=res.body)
+ assert self.package_ref_from_name('annakarenina') in res, res
+ assert self.group_ref_from_name('roger') in res, res
+ assert not self.package_ref_from_name('warandpeace') in res, res
def test_entity_get_then_post(self):
# (ticket 662) Ensure an entity you 'get' from a register can be
@@ -70,6 +80,123 @@
status=self.STATUS_200_OK,
extra_environ=self.extra_environ)
+ def test_05_get_group_entity_not_found(self):
+ offset = self.offset('/rest/group/22222')
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+ def test_10_edit_group(self):
+ # create a group with testgroupvalues
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ if not group:
+ offset = self.offset('/rest/group')
+ postparams = '%s=1' % self.dumps(self.testgroupvalues)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ assert group
+ assert len(group.packages) == 2, group.packages
+ user = model.User.by_name(self.user_name)
+ model.setup_default_user_roles(group, [user])
+
+ # edit it
+ group_vals = {'name':u'somethingnew', 'title':u'newtesttitle',
+ 'packages':[u'annakarenina']}
+ offset = self.group_offset(self.testgroupvalues['name'])
+ postparams = '%s=1' % self.dumps(group_vals)
+ res = self.app.post(offset, params=postparams, status=[200],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ group = model.Session.query(model.Group).filter_by(name=group_vals['name']).one()
+ assert group.name == group_vals['name']
+ assert group.title == group_vals['title']
+ assert len(group.packages) == 1, group.packages
+ assert group.packages[0].name == group_vals['packages'][0]
+
+ def test_10_edit_group_name_duplicate(self):
+ # create a group with testgroupvalues
+ if not model.Group.by_name(self.testgroupvalues['name']):
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = self.testgroupvalues['name']
+ model.Session.commit()
+
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ model.setup_default_user_roles(group, [self.user])
+ rev = model.repo.new_revision()
+ model.repo.commit_and_remove()
+ assert model.Group.by_name(self.testgroupvalues['name'])
+
+ # create a group with name 'dupname'
+ dupname = u'dupname'
+ if not model.Group.by_name(dupname):
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = dupname
+ model.Session.commit()
+ assert model.Group.by_name(dupname)
+
+ # edit first group to have dupname
+ group_vals = {'name':dupname}
+ offset = self.group_offset(self.testgroupvalues['name'])
+ postparams = '%s=1' % self.dumps(group_vals)
+ res = self.app.post(offset, params=postparams, status=[409],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'Group name already exists')
+
+ def test_11_delete_group(self):
+ # Test Groups Entity Delete 200.
+
+ # create a group with testgroupvalues
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ if not group:
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = self.testgroupvalues['name']
+ model.repo.commit_and_remove()
+
+ rev = model.repo.new_revision()
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ model.setup_default_user_roles(group, [self.user])
+ model.repo.commit_and_remove()
+ assert group
+ user = model.User.by_name(self.user_name)
+ model.setup_default_user_roles(group, [user])
+
+ # delete it
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.delete(offset, status=[200],
+ extra_environ=self.extra_environ)
+
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ assert group
+ assert group.state == 'deleted', group.state
+
+ res = self.app.get(offset, status=[403])
+ self.assert_json_response(res, 'Access denied')
+ res = self.app.get(offset, status=[200],
+ extra_environ=self.extra_environ)
+
+ def test_12_get_group_404(self):
+ # Test Package Entity Get 404.
+ assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+ def test_13_delete_group_404(self):
+ # Test Packages Entity Delete 404.
+ assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.delete(offset, status=[404],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'not found')
+
+
class TestGroupsVersion1(Version1TestCase, GroupsTestCase): pass
class TestGroupsVersion2(Version2TestCase, GroupsTestCase): pass
class TestGroupsUnversioned(UnversionedTestCase, GroupsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_licenses.py Thu Jul 07 20:46:38 2011 +0100
@@ -0,0 +1,32 @@
+from nose.tools import assert_equal
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class LicensesTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = False
+
+ def test_register_get_ok(self):
+ from ckan.model.license import LicenseRegister
+ register = LicenseRegister()
+ assert len(register), "No changesets found in model."
+ offset = self.offset('/rest/licenses')
+ res = self.app.get(offset, status=[200])
+ licenses_data = self.data_from_res(res)
+ assert len(licenses_data) == len(register), (len(licenses_data), len(register))
+ for license_data in licenses_data:
+ id = license_data['id']
+ license = register[id]
+ assert license['title'] == license.title
+ assert license['url'] == license.url
+
+
+class TestLicensesVersion1(Version1TestCase, LicensesTestCase): pass
+class TestLicensesVersion2(Version2TestCase, LicensesTestCase): pass
+class TestLicensesUnversioned(UnversionedTestCase, LicensesTestCase): pass
--- a/ckan/tests/functional/api/model/test_package.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py Thu Jul 07 20:46:38 2011 +0100
@@ -1,3 +1,5 @@
+import copy
+
from nose.tools import assert_equal
from ckan.tests.functional.api.base import BaseModelApiTestCase
@@ -35,6 +37,15 @@
res = self.app.post(offset, params=postparams,
status=self.STATUS_201_CREATED,
extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], self.package_fixture_data['name'])
+ assert_equal(pkg['title'], self.package_fixture_data['title'])
+ assert_equal(set(pkg['tags']), set(self.package_fixture_data['tags']))
+ assert_equal(len(pkg['resources']), len(self.package_fixture_data['resources']))
+ assert_equal(pkg['extras'], self.package_fixture_data['extras'])
+
# Check the value of the Location header.
location = res.header('Location')
assert offset in location
@@ -102,8 +113,19 @@
package = self.get_package_by_name(self.package_fixture_data['name'])
assert package
self.assert_equal(package.title, self.package_fixture_data['title'])
+
+ def test_register_post_json(self):
+ assert not self.get_package_by_name(self.package_fixture_data['name'])
+ offset = self.package_offset()
+ data = self.dumps(self.package_fixture_data)
+ res = self.post_json(offset, data, status=self.STATUS_201_CREATED,
+ extra_environ=self.extra_environ)
+ # Check the database record.
+ self.remove()
+ package = self.get_package_by_name(self.package_fixture_data['name'])
+ assert package
+ self.assert_equal(package.title, self.package_fixture_data['title'])
-
def test_register_post_bad_request(self):
test_params = {
'name':u'testpackage06_400',
@@ -200,7 +222,8 @@
def create_package_roles_revision(self, package_data):
self.create_package(admins=[self.user], data=package_data)
- def assert_package_update_ok(self, package_ref_attribute):
+ def assert_package_update_ok(self, package_ref_attribute,
+ method_str):
old_fixture_data = {
'name': self.package_fixture_data['name'],
'url': self.package_fixture_data['url'],
@@ -237,10 +260,28 @@
'tags': [u'tag1', u'tag2', u'tag4', u'tag5'],
}
self.create_package_roles_revision(old_fixture_data)
- offset = self.package_offset(old_fixture_data['name'])
+ pkg = self.get_package_by_name(old_fixture_data['name'])
+ # This is the one occasion where we reference package explicitly
+ # by name or ID, rather than use the value from self.ref_package_by
+ # because you should be able to specify the package both ways round
+ # for both versions of the API.
+ package_ref = getattr(pkg, package_ref_attribute)
+ offset = self.offset('/rest/package/%s' % package_ref)
params = '%s=1' % self.dumps(new_fixture_data)
- res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
- extra_environ=self.extra_environ)
+ method_func = getattr(self.app, method_str)
+ res = method_func(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ assert_equal(pkg['title'], new_fixture_data['title'])
+ assert_equal(set(pkg['tags']), set(new_fixture_data['tags']))
+ assert_equal(len(pkg['resources']), len(new_fixture_data['resources']))
+ expected_extras = copy.deepcopy(new_fixture_data['extras'])
+ del expected_extras['key2']
+ expected_extras['key1'] = old_fixture_data['extras']['key1']
+ assert_equal(pkg['extras'], expected_extras)
# Check submitted field have changed.
self.remove()
@@ -285,10 +326,78 @@
assert not package.extras.has_key('key2')
def test_package_update_ok_by_id(self):
- self.assert_package_update_ok('id')
+ self.assert_package_update_ok('id', 'post')
def test_entity_update_ok_by_name(self):
- self.assert_package_update_ok('name')
+ self.assert_package_update_ok('name', 'post')
+
+ def test_package_update_ok_by_id_by_put(self):
+ self.assert_package_update_ok('id', 'put')
+
+ def test_entity_update_ok_by_name_by_put(self):
+ self.assert_package_update_ok('name', 'put')
+
+ def test_package_update_delete_last_extra(self):
+ old_fixture_data = {
+ 'name': self.package_fixture_data['name'],
+ 'extras': {
+ u'key1': u'val1',
+ },
+ }
+ new_fixture_data = {
+ 'name':u'somethingnew',
+ 'extras': {
+ u'key1': None,
+ },
+ }
+ self.create_package_roles_revision(old_fixture_data)
+ offset = self.package_offset(old_fixture_data['name'])
+ params = '%s=1' % self.dumps(new_fixture_data)
+ res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ expected_extras = copy.deepcopy(new_fixture_data['extras'])
+ del expected_extras['key1']
+ assert_equal(pkg['extras'], expected_extras)
+
+ # Check extra was deleted
+ self.remove()
+ package = self.get_package_by_name(new_fixture_data['name'])
+ # - title
+ self.assert_equal(package.extras, {})
+
+ def test_package_update_do_not_delete_last_extra(self):
+ old_fixture_data = {
+ 'name': self.package_fixture_data['name'],
+ 'extras': {
+ u'key1': u'val1',
+ },
+ }
+ new_fixture_data = {
+ 'name':u'somethingnew',
+ 'extras': {}, # no extras specified, but existing
+ # ones should be left alone
+ }
+ self.create_package_roles_revision(old_fixture_data)
+ offset = self.package_offset(old_fixture_data['name'])
+ params = '%s=1' % self.dumps(new_fixture_data)
+ res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ expected_extras = {u'key1': u'val1'} # should not be deleted
+ assert_equal(pkg['extras'], expected_extras)
+
+ # Check extra was not deleted
+ self.remove()
+ package = self.get_package_by_name(new_fixture_data['name'])
+ # - title
+ assert len(package.extras) == 1, package.extras
def test_entity_update_conflict(self):
package1_name = self.package_fixture_data['name']
@@ -300,18 +409,19 @@
package1_offset = self.package_offset(package1_name)
self.post(package1_offset, package2_data, self.STATUS_409_CONFLICT)
+ def test_entity_update_empty(self):
+ package1_name = self.package_fixture_data['name']
+ package1_data = {'name': package1_name}
+ package1 = self.create_package_roles_revision(package1_data)
+ package2_data = '' # this is the error
+ package1_offset = self.package_offset(package1_name)
+ self.app.put(package1_offset, package2_data,
+ status=self.STATUS_400_BAD_REQUEST)
+
def test_entity_delete_ok(self):
# create a package with package_fixture_data
if not self.get_package_by_name(self.package_fixture_data['name']):
- rev = model.repo.new_revision()
- package = model.Package()
- model.Session.add(package)
- package.name = self.package_fixture_data['name']
- model.repo.commit_and_remove()
- rev = model.repo.new_revision()
- package = self.get_package_by_name(self.package_fixture_data['name'])
- model.setup_default_user_roles(package, [self.user])
- model.repo.commit_and_remove()
+ self.create_package(admins=[self.user], name=self.package_fixture_data['name'])
assert self.get_package_by_name(self.package_fixture_data['name'])
# delete it
offset = self.package_offset(self.package_fixture_data['name'])
@@ -321,6 +431,19 @@
self.assert_equal(package.state, 'deleted')
model.Session.remove()
+ def test_entity_delete_ok_without_request_headers(self):
+ # create a package with package_fixture_data
+ if not self.get_package_by_name(self.package_fixture_data['name']):
+ self.create_package(admins=[self.user], name=self.package_fixture_data['name'])
+ assert self.get_package_by_name(self.package_fixture_data['name'])
+ # delete it
+ offset = self.package_offset(self.package_fixture_data['name'])
+ res = self.delete_request(offset, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+ package = self.get_package_by_name(self.package_fixture_data['name'])
+ self.assert_equal(package.state, 'deleted')
+ model.Session.remove()
+
def test_entity_delete_not_found(self):
package_name = u'random_one'
assert not model.Session.query(model.Package).filter_by(name=package_name).count()
@@ -363,7 +486,52 @@
assert len(revisions) == 3, len(revisions)
-class TestPackagesVersion1(Version1TestCase, PackagesTestCase): pass
+class TestPackagesVersion1(Version1TestCase, PackagesTestCase):
+ def test_06_create_pkg_using_download_url(self):
+ test_params = {
+ 'name':u'testpkg06',
+ 'download_url':u'ftp://ftp.monash.edu.au/pub/nihongo/JMdict.gz',
+ }
+ offset = self.package_offset()
+ postparams = '%s=1' % self.dumps(test_params)
+ res = self.app.post(offset, params=postparams,
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(test_params['name'])
+ assert pkg
+ assert pkg.name == test_params['name'], pkg
+ assert len(pkg.resources) == 1, pkg.resources
+ assert pkg.resources[0].url == test_params['download_url'], pkg.resources[0]
+
+ def test_10_edit_pkg_with_download_url(self):
+ test_params = {
+ 'name':u'testpkg10',
+ 'download_url':u'testurl',
+ }
+ rev = model.repo.new_revision()
+ pkg = model.Package()
+ model.Session.add(pkg)
+ pkg.name = test_params['name']
+ pkg.download_url = test_params['download_url']
+ model.Session.commit()
+
+ pkg = self.get_package_by_name(test_params['name'])
+ model.setup_default_user_roles(pkg, [self.user])
+ rev = model.repo.new_revision()
+ model.repo.commit_and_remove()
+ assert self.get_package_by_name(test_params['name'])
+
+ # edit it
+ pkg_vals = {'download_url':u'newurl'}
+ offset = self.package_offset(test_params['name'])
+ postparams = '%s=1' % self.dumps(pkg_vals)
+ res = self.app.post(offset, params=postparams, status=[200],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = model.Session.query(model.Package).filter_by(name=test_params['name']).one()
+ assert len(pkg.resources) == 1, pkg.resources
+ assert pkg.resources[0].url == pkg_vals['download_url']
+
class TestPackagesVersion2(Version2TestCase, PackagesTestCase): pass
class TestPackagesUnversioned(UnversionedTestCase, PackagesTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_ratings.py Thu Jul 07 20:46:38 2011 +0100
@@ -0,0 +1,94 @@
+from nose.tools import assert_equal
+from nose.plugins.skip import SkipTest
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RatingsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ def test_register_get(self):
+ raise SkipTest('"Rating register get" functionality is not implemented')
+ rating1 = model.Rating(user_ip_address='1.2.3.4',
+ package=self.anna,
+ rating=4.0)
+ rating2 = model.Rating(user=model.User.by_name(u'annafan'),
+ package=self.anna,
+ rating=2.0)
+ model.Session.add_all((rating1, rating2))
+ model.repo.commit_and_remove()
+
+ offset = self.rating_offset()
+ res = self.app.get(offset, status=[200])
+
+ def test_entity_get(self):
+ raise SkipTest('"Rating entity get" functionality is not implemented')
+ rating = model.Rating(user_ip_address='1.2.3.4',
+ package=self.anna,
+ rating=4.0)
+ model.Session.add(rating)
+ model.repo.commit_and_remove()
+
+ offset = self.rating_offset(self.anna.name)
+ res = self.app.get(offset, status=[200])
+ assert_equal(res, rating_opts['rating'])
+
+ def test_register_post(self):
+ # Test Rating Register Post 200.
+ self.clear_all_tst_ratings()
+ offset = self.rating_offset()
+ rating_opts = {'package':u'warandpeace',
+ 'rating':5}
+ pkg_name = rating_opts['package']
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(pkg_name)
+ assert pkg
+ assert len(pkg.ratings) == 1
+ assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
+
+ # Get package to see rating
+ offset = self.package_offset(pkg_name)
+ res = self.app.get(offset, status=[200])
+ assert pkg_name in res, res
+ assert '"ratings_average": %s.0' % rating_opts['rating'] in res, res
+ assert '"ratings_count": 1' in res, res
+
+ model.Session.remove()
+
+ # Rerate package
+ offset = self.rating_offset()
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(pkg_name)
+ assert pkg
+ assert len(pkg.ratings) == 1
+ assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
+
+ def test_entity_post_invalid(self):
+ self.clear_all_tst_ratings()
+ offset = self.rating_offset()
+ rating_opts = {'package':u'warandpeace',
+ 'rating':0}
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[409],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'rating')
+ model.Session.remove()
+ pkg = self.get_package_by_name(rating_opts['package'])
+ assert pkg
+ assert len(pkg.ratings) == 0
+
+class TestRatingsVersion1(Version1TestCase, RatingsTestCase): pass
+class TestRatingsVersion2(Version2TestCase, RatingsTestCase): pass
+class TestRatingsUnversioned(UnversionedTestCase, RatingsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 20:46:38 2011 +0100
@@ -0,0 +1,242 @@
+from nose.tools import assert_equal
+from nose.plugins.skip import SkipTest
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RelationshipsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ @classmethod
+ def setup_class(cls):
+# super(RelationshipsTestCase, cls).setup_class()
+ cls.testsysadmin = model.User.by_name(u'testsysadmin')
+ cls.comment = u'Comment umlaut: \xfc.'
+
+ def test_01_create_and_read_relationship(self):
+ # check anna has no existing relationships
+ assert not self.anna.get_relationships()
+ assert self.get_relationships(package1_name='annakarenina') == [], self.get_relationships(package1_name='annakarenina')
+ assert self.get_relationships(package1_name='annakarenina',
+ package2_name='warandpeace') == []
+ assert self.get_relationships(package1_name='annakarenina',
+ type='child_of',
+ package2_name='warandpeace') == 404
+ assert self.get_relationships_via_package('annakarenina') == []
+
+ # Create a relationship.
+ self.create_annakarenina_parent_of_war_and_peace()
+
+ # Check package relationship register.
+ rels = self.get_relationships(package1_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # Todo: Name this?
+ # Check '/api/VER/rest/package/annakarenina/relationships/warandpeace'
+ rels = self.get_relationships(package1_name='annakarenina',
+ package2_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # Todo: Name this?
+ # check '/api/VER/rest/package/annakarenina/parent_of/warandpeace'
+ rels = self.get_relationships(package1_name='annakarenina',
+ type='parent_of',
+ package2_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # same checks in reverse direction
+ rels = self.get_relationships(package1_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ rels = self.get_relationships(package1_name='warandpeace',
+ package2_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ rels = self.get_relationships(package1_name='warandpeace',
+ type='child_of',
+ package2_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ # Check package entity relationships.
+ rels = self.get_relationships_via_package('annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ def test_03_update_relationship(self):
+ # Create a relationship.
+ self.create_annakarenina_parent_of_war_and_peace()
+
+ # Check the relationship before update.
+ self.check_relationships_rest('warandpeace', 'annakarenina',
+ [{'type': 'child_of',
+ 'comment': self.comment}])
+
+ # Update the relationship.
+ new_comment = u'New comment.'
+ self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
+
+ # Check the relationship after update.
+ self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
+
+ # Repeat update with same values, to check it remains the same?
+
+ # Update the relationship.
+ new_comment = u'New comment.'
+ self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
+
+ # Check the relationship after update.
+ self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
+
+ def test_05_delete_relationship(self):
+ self.create_annakarenina_parent_of_war_and_peace()
+ self.update_annakarenina_parent_of_war_and_peace()
+ expected = [ {'type': 'child_of', 'comment': u'New comment.'} ]
+ self.check_relationships_rest('warandpeace', 'annakarenina', expected)
+
+ self.delete_annakarenina_parent_of_war_and_peace()
+
+ expected = []
+ self.check_relationships_rest('warandpeace', 'annakarenina', expected)
+
+ def test_create_relationship_unknown(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'unheard_of_type', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':self.comment})
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
+ def test_create_relationship_incorrectly(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'relationships', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'type':'parent_of'})
+ # type should do in the URL offset, not the params.
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
+ def create_annakarenina_parent_of_war_and_peace(self):
+ # Create package relationship.
+ # Todo: Redesign this in a RESTful style, so that a relationship is
+ # created by posting a relationship to a relationship **register**.
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':self.comment})
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ # Check the response
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
+ # Check the model, directly.
+ rels = self.anna.get_relationships()
+ assert len(rels) == 1, rels
+ assert rels[0].type == 'child_of'
+ assert rels[0].subject.name == 'warandpeace'
+ assert rels[0].object.name == 'annakarenina'
+
+ def update_annakarenina_parent_of_war_and_peace(self, comment=u'New comment.'):
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':comment})
+ res = self.app.post(offset, params=postparams, status=[201], extra_environ=self.extra_environ)
+ # Check the response (normalised to 'child_of')
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
+ # Check the model, directly (normalised to 'child_of')
+ rels = self.anna.get_relationships()
+ assert len(rels) == 1, rels
+ assert rels[0].type == 'child_of'
+ assert rels[0].subject.name == 'warandpeace'
+ assert rels[0].object.name == 'annakarenina'
+ return res
+
+ def delete_annakarenina_parent_of_war_and_peace(self):
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ res = self.app.delete(offset, status=[200], extra_environ=self.extra_environ)
+ assert not res.body
+
+ def get_relationships(self, package1_name=u'annakarenina', type='relationships', package2_name=None):
+ offset = self.relationship_offset(package1_name, type, package2_name)
+ allowable_statuses = [200]
+ if type:
+ allowable_statuses.append(404)
+ res = self.app.get(offset, status=allowable_statuses)
+ if res.status == 200:
+ res_dict = self.data_from_res(res) if res.body else []
+ return res_dict
+ else:
+ return 404
+
+ def get_relationships_via_package(self, package1_name):
+ offset = self.package_offset(package1_name)
+ res = self.app.get(offset, status=200)
+ res_dict = self.data_from_res(res)
+ return res_dict['relationships']
+
+ def assert_len_relationships(self, relationships, expected_relationships):
+ len_relationships = len(relationships)
+ len_expected_relationships = len(expected_relationships)
+ if len_relationships != len_expected_relationships:
+ msg = 'Found %i relationships, ' % len_relationships
+ msg += 'but expected %i.' % len_expected_relationships
+ if len_relationships:
+ msg += ' Found: '
+ for r in relationships:
+ msg += '%s %s %s; ' % (r['subject'], r['type'], r['object'])
+ msg += '.'
+ raise Exception, msg
+
+ def check_relationships_rest(self, pkg1_name, pkg2_name=None,
+ expected_relationships=[]):
+ rels = self.get_relationships(package1_name=pkg1_name,
+ package2_name=pkg2_name)
+ self.assert_len_relationships(rels, expected_relationships)
+ for rel in rels:
+ the_expected_rel = None
+ for expected_rel in expected_relationships:
+ if expected_rel['type'] == rel['type'] and \
+ (pkg2_name or expected_rel['object'] == pkg2_name):
+ the_expected_rel = expected_rel
+ break
+ if not the_expected_rel:
+ raise Exception('Unexpected relationship: %s %s %s' %
+ (rel['subject'], rel['type'], rel['object']))
+ for field in ('subject', 'object', 'type', 'comment'):
+ if the_expected_rel.has_key(field):
+ value = rel[field]
+ expected = the_expected_rel[field]
+ assert value == expected, (value, expected, field, rel)
+
+ def check_relationship_dict(self, rel_dict, subject_name, type, object_name, comment):
+ subject_ref = self.package_ref_from_name(subject_name)
+ object_ref = self.package_ref_from_name(object_name)
+
+ assert rel_dict['subject'] == subject_ref, (rel_dict, subject_ref)
+ assert rel_dict['object'] == object_ref, (rel_dict, object_ref)
+ assert rel_dict['type'] == type, (rel_dict, type)
+ assert rel_dict['comment'] == comment, (rel_dict, comment)
+
+class TestRelationshipsVersion1(Version1TestCase, RelationshipsTestCase): pass
+class TestRelationshipsVersion2(Version2TestCase, RelationshipsTestCase): pass
+class TestRelationshipsUnversioned(UnversionedTestCase, RelationshipsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_revisions.py Thu Jul 07 20:46:38 2011 +0100
@@ -0,0 +1,49 @@
+from nose.tools import assert_equal
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RevisionsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ def test_register_get_ok(self):
+ # Check mock register behaviour.
+ offset = self.revision_offset()
+ res = self.app.get(offset, status=200)
+ revs = model.Session.query(model.Revision).all()
+ assert revs, 'There are no revisions in the model.'
+ res_dict = self.data_from_res(res)
+ for rev in revs:
+ assert rev.id in res_dict, (rev.id, res_dict)
+
+ def test_entity_get_ok(self):
+ rev = model.repo.history().all()[-2] # 2nd revision is the creation of pkgs
+ assert rev.id
+ assert rev.timestamp.isoformat()
+ offset = self.revision_offset(rev.id)
+ response = self.app.get(offset, status=[200])
+ response_data = self.data_from_res(response)
+ assert_equal(rev.id, response_data['id'])
+ assert_equal(rev.timestamp.isoformat(), response_data['timestamp'])
+ assert 'packages' in response_data
+ packages = response_data['packages']
+ assert isinstance(packages, list)
+ #assert len(packages) != 0, "Revision packages is empty: %s" % packages
+ assert self.ref_package(self.anna) in packages, packages
+ assert self.ref_package(self.war) in packages, packages
+
+ def test_entity_get_404(self):
+ revision_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
+ offset = self.revision_offset(revision_id)
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+class TestRevisionsVersion1(Version1TestCase, RevisionsTestCase): pass
+class TestRevisionsVersion2(Version2TestCase, RevisionsTestCase): pass
+class TestRevisionsUnversioned(UnversionedTestCase, RevisionsTestCase): pass
--- a/ckan/tests/functional/api/model/test_tag.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/model/test_tag.py Thu Jul 07 20:46:38 2011 +0100
@@ -23,6 +23,10 @@
res = self.app.get(offset, status=self.STATUS_200_OK)
self.assert_msg_represents_russian(msg=res.body)
+ def test_entity_get_not_found(self):
+ offset = self.tag_offset('doesntexist')
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
class TestTagsVersion1(Version1TestCase, TagsTestCase): pass
class TestTagsVersion2(Version2TestCase, TagsTestCase): pass
--- a/ckan/tests/functional/api/test_model.py Tue Jul 05 17:16:08 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-from ckan.tests.functional.api.base import *
-from ckan.lib.create_test_data import CreateTestData
-from ckan.tests import TestController as ControllerTestCase
-
-class ModelApiTestCase(BaseModelApiTestCase):
-
- def setup(self):
- self.create_common_fixtures()
- self.init_extra_environ()
- self.source = None
- self.source1 = None
- self.source2 = None
- self.source3 = None
- self.source4 = None
- self.source5 = None
- self.job = None
- self.job1 = None
- self.job2 = None
- self.job3 = None
-
- def teardown(self):
- model.repo.rebuild_db()
-
- def test_02_get_tag_register_ok(self):
- # Test Packages Register Get 200.
- offset = self.offset('/rest/tag')
- res = self.app.get(offset, status=[200])
- assert 'russian' in res, res
- assert 'tolstoy' in res, res
-
- def test_02_get_group_register_ok(self):
- offset = self.offset('/rest/group')
- res = self.app.get(offset, status=[200])
- assert self.group_ref_from_name('david') in res, res
- assert self.group_ref_from_name('roger') in res, res
-
- def test_04_get_tag(self):
- offset = self.offset('/rest/tag/tolstoy')
- res = self.app.get(offset, status=[200])
- assert 'annakarenina' in res, res
- assert not 'warandpeace' in res, res
-
- def test_04_get_group(self):
- offset = self.offset('/rest/group/roger')
- res = self.app.get(offset, status=[200])
- assert self.package_ref_from_name('annakarenina') in res, res
- assert self.group_ref_from_name('roger') in res, res
- assert not self.package_ref_from_name('warandpeace') in res, res
-
- def test_05_get_group_entity_not_found(self):
- offset = self.offset('/rest/group/22222')
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_05_get_tag_entity_not_found(self):
- offset = self.offset('/rest/tag/doesntexist')
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_06_create_group_entity_ok(self):
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=201,
- extra_environ=self.extra_environ)
- model.Session.remove()
- rev = model.repo.new_revision()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- model.setup_default_user_roles(group, [self.user])
- model.repo.commit_and_remove()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert group.title == self.testgroupvalues['title'], group
- assert group.description == self.testgroupvalues['description'], group
- assert len(group.packages) == 2, len(group.packages)
- anna = self.anna
- warandpeace = self.war
- assert anna in group.packages
- assert warandpeace in group.packages
-
- # Check group packages.
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.get(offset, status=[200])
- assert self.testgroupvalues['name'] in res, res
- assert self.package_ref_from_name(self.testgroupvalues['packages'][0]) in res, res
- ref = self.package_ref_from_name(self.testgroupvalues['packages'][0])
- assert ref in res, res
- ref = self.package_ref_from_name(self.testgroupvalues['packages'][1])
- assert ref in res, res
- model.Session.remove()
-
- # Check create group entity conflict.
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
-
- def test_06_rate_package(self):
- # Test Rating Register Post 200.
- self.clear_all_tst_ratings()
- offset = self.offset('/rest/rating')
- rating_opts = {'package':u'warandpeace',
- 'rating':5}
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 1
- assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
-
- # Get package to see rating
- offset = self.offset('/rest/package/%s' % rating_opts['package'])
- res = self.app.get(offset, status=[200])
- assert rating_opts['package'] in res, res
- assert '"ratings_average": %s.0' % rating_opts['rating'] in res, res
- assert '"ratings_count": 1' in res, res
-
- model.Session.remove()
-
- # Rerate package
- offset = self.offset('/rest/rating')
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 1
- assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
-
- def test_06_rate_package_out_of_range(self):
- self.clear_all_tst_ratings()
- offset = self.offset('/rest/rating')
- rating_opts = {'package':u'warandpeace',
- 'rating':0}
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 0
-
- def test_10_edit_group(self):
- # create a group with testgroupvalues
- group = model.Group.by_name(self.testgroupvalues['name'])
- if not group:
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert len(group.packages) == 2, group.packages
- user = model.User.by_name(self.user_name)
- model.setup_default_user_roles(group, [user])
-
- # edit it
- group_vals = {'name':u'somethingnew', 'title':u'newtesttitle',
- 'packages':[u'annakarenina']}
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- postparams = '%s=1' % self.dumps(group_vals)
- res = self.app.post(offset, params=postparams, status=[200],
- extra_environ=self.extra_environ)
- model.Session.remove()
- group = model.Session.query(model.Group).filter_by(name=group_vals['name']).one()
- assert group.name == group_vals['name']
- assert group.title == group_vals['title']
- assert len(group.packages) == 1, group.packages
- assert group.packages[0].name == group_vals['packages'][0]
-
- def test_10_edit_group_name_duplicate(self):
- # create a group with testgroupvalues
- if not model.Group.by_name(self.testgroupvalues['name']):
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = self.testgroupvalues['name']
- model.Session.commit()
-
- group = model.Group.by_name(self.testgroupvalues['name'])
- model.setup_default_user_roles(group, [self.user])
- rev = model.repo.new_revision()
- model.repo.commit_and_remove()
- assert model.Group.by_name(self.testgroupvalues['name'])
-
- # create a group with name 'dupname'
- dupname = u'dupname'
- if not model.Group.by_name(dupname):
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = dupname
- model.Session.commit()
- assert model.Group.by_name(dupname)
-
- # edit first group to have dupname
- group_vals = {'name':dupname}
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- postparams = '%s=1' % self.dumps(group_vals)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
-
- def test_11_delete_group(self):
- # Test Groups Entity Delete 200.
-
- # create a group with testgroupvalues
- group = model.Group.by_name(self.testgroupvalues['name'])
- if not group:
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = self.testgroupvalues['name']
- model.repo.commit_and_remove()
-
- rev = model.repo.new_revision()
- group = model.Group.by_name(self.testgroupvalues['name'])
- model.setup_default_user_roles(group, [self.user])
- model.repo.commit_and_remove()
- assert group
- user = model.User.by_name(self.user_name)
- model.setup_default_user_roles(group, [user])
-
- # delete it
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.delete(offset, status=[200],
- extra_environ=self.extra_environ)
-
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert group.state == 'deleted', group.state
-
- res = self.app.get(offset, status=[403])
- res = self.app.get(offset, status=[200],
- extra_environ=self.extra_environ)
-
- model.Session.remove()
-
- def test_12_get_group_404(self):
- # Test Package Entity Get 404.
- assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_13_delete_group_404(self):
- # Test Packages Entity Delete 404.
- assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.delete(offset, status=[404],
- extra_environ=self.extra_environ)
-
- def test_14_list_revisions(self):
- # Check mock register behaviour.
- offset = self.offset('/rest/revision')
- res = self.app.get(offset, status=200)
- revs = model.Session.query(model.Revision).all()
- assert revs, "There are no revisions in the model."
- res_dict = self.data_from_res(res)
- for rev in revs:
- assert rev.id in res_dict, (rev.id, res_dict)
-
- def test_14_get_revision(self):
- rev = model.repo.history().all()[-2] # 2nd revision is the creation of pkgs
- assert rev.id
- assert rev.timestamp.isoformat()
- offset = self.offset('/rest/revision/%s' % rev.id)
- response = self.app.get(offset, status=[200])
- response_data = self.data_from_res(response)
- assert rev.id == response_data['id']
- assert rev.timestamp.isoformat() == response_data['timestamp'], (rev.timestamp.isoformat(), response_data['timestamp'])
- assert 'packages' in response_data
- packages = response_data['packages']
- assert isinstance(packages, list)
- #assert len(packages) != 0, "Revision packages is empty: %s" % packages
- assert self.ref_package(self.anna) in packages, packages
- assert self.ref_package(self.war) in packages, packages
-
- def test_14_get_revision_404(self):
- revision_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
- offset = self.offset('/rest/revision/%s' % revision_id)
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_16_list_licenses(self):
- from ckan.model.license import LicenseRegister
- register = LicenseRegister()
- assert len(register), "No changesets found in model."
- offset = self.offset('/rest/licenses')
- res = self.app.get(offset, status=[200])
- licenses_data = self.data_from_res(res)
- assert len(licenses_data) == len(register), (len(licenses_data), len(register))
- for license_data in licenses_data:
- id = license_data['id']
- license = register[id]
- assert license['title'] == license.title
- assert license['url'] == license.url
-
-
-class RelationshipsApiTestCase(ApiTestCase, ControllerTestCase):
-
- @classmethod
- def setup_class(self):
- CreateTestData.create()
- self.user = self.create_user(name=u'barry')
- self.testsysadmin = model.User.by_name(u'testsysadmin')
- self.extra_environ={ 'Authorization' : str(self.user.apikey) }
- self.comment = u'Comment umlaut: \xfc.'
-
- @classmethod
- def teardown_class(self):
- model.Session.remove()
- model.repo.rebuild_db()
- model.Session.remove()
-
- def teardown(self):
- for relationship in self.anna.get_relationships():
- relationship.purge()
- model.Session.commit()
- relationships = self.anna.get_relationships()
- assert relationships == [], "There are still some relationships: %s" % relationships
-
- def test_01_create_and_read_relationship(self):
- # check anna has no existing relationships
- assert not self.anna.get_relationships()
- assert self.get_relationships(package1_name='annakarenina') == [], self.get_relationships(package1_name='annakarenina')
- assert self.get_relationships(package1_name='annakarenina',
- package2_name='warandpeace') == []
- assert self.get_relationships(package1_name='annakarenina',
- type='child_of',
- package2_name='warandpeace') == 404
- assert self.get_relationships_via_package('annakarenina') == []
-
- # Create a relationship.
- self.create_annakarenina_parent_of_war_and_peace()
-
- # Check package relationship register.
- rels = self.get_relationships(package1_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # Todo: Name this?
- # Check '/api/VER/rest/package/annakarenina/relationships/warandpeace'
- rels = self.get_relationships(package1_name='annakarenina',
- package2_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # Todo: Name this?
- # check '/api/VER/rest/package/annakarenina/parent_of/warandpeace'
- rels = self.get_relationships(package1_name='annakarenina',
- type='parent_of',
- package2_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # same checks in reverse direction
- rels = self.get_relationships(package1_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- rels = self.get_relationships(package1_name='warandpeace',
- package2_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- rels = self.get_relationships(package1_name='warandpeace',
- type='child_of',
- package2_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- # Check package entity relationships.
- rels = self.get_relationships_via_package('annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- def test_03_update_relationship(self):
- # Create a relationship.
- self.create_annakarenina_parent_of_war_and_peace()
-
- # Check the relationship before update.
- self.check_relationships_rest('warandpeace', 'annakarenina',
- [{'type': 'child_of',
- 'comment': self.comment}])
-
- # Update the relationship.
- new_comment = u'New comment.'
- self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
-
- # Check the relationship after update.
- self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
-
- # Repeat update with same values, to check it remains the same?
-
- # Update the relationship.
- new_comment = u'New comment.'
- self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
-
- # Check the relationship after update.
- self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
-
- def test_05_delete_relationship(self):
- self.create_annakarenina_parent_of_war_and_peace()
- self.update_annakarenina_parent_of_war_and_peace()
- expected = [ {'type': 'child_of', 'comment': u'New comment.'} ]
- self.check_relationships_rest('warandpeace', 'annakarenina', expected)
-
- self.delete_annakarenina_parent_of_war_and_peace()
-
- expected = []
- self.check_relationships_rest('warandpeace', 'annakarenina', expected)
-
- def create_annakarenina_parent_of_war_and_peace(self):
- # Create package relationship.
- # Todo: Redesign this in a RESTful style, so that a relationship is
- # created by posting a relationship to a relationship **register**.
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- postparams = '%s=1' % self.dumps({'comment':self.comment})
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- # Check the model, directly.
- rels = self.anna.get_relationships()
- assert len(rels) == 1, rels
- assert rels[0].type == 'child_of'
- assert rels[0].subject.name == 'warandpeace'
- assert rels[0].object.name == 'annakarenina'
-
- def update_annakarenina_parent_of_war_and_peace(self, comment=u'New comment.'):
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- postparams = '%s=1' % self.dumps({'comment':comment})
- res = self.app.post(offset, params=postparams, status=[201], extra_environ=self.extra_environ)
- return res
-
- def delete_annakarenina_parent_of_war_and_peace(self):
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- res = self.app.delete(offset, status=[200], extra_environ=self.extra_environ)
- return res
-
- def get_relationships(self, package1_name=u'annakarenina', type='relationships', package2_name=None):
- package1_ref = self.package_ref_from_name(package1_name)
- if not package2_name:
- offset = self.offset('/rest/package/%s/%s' % (package1_ref, type))
- else:
- package2_ref = self.package_ref_from_name(package2_name)
- offset = self.offset('/rest/package/%s/%s/%s' % (
- str(package1_ref), type, str(package2_ref)))
- allowable_statuses = [200]
- if type:
- allowable_statuses.append(404)
- res = self.app.get(offset, status=allowable_statuses)
- if res.status == 200:
- res_dict = self.data_from_res(res) if res.body else []
- return res_dict
- else:
- return 404
-
- def get_relationships_via_package(self, package1_name):
- offset = self.offset('/rest/package/%s' % (str(package1_name)))
- res = self.app.get(offset, status=200)
- res_dict = self.data_from_res(res)
- return res_dict['relationships']
-
- def assert_len_relationships(self, relationships, expected_relationships):
- len_relationships = len(relationships)
- len_expected_relationships = len(expected_relationships)
- if len_relationships != len_expected_relationships:
- msg = 'Found %i relationships, ' % len_relationships
- msg += 'but expected %i.' % len_expected_relationships
- if len_relationships:
- msg += ' Found: '
- for r in relationships:
- msg += '%s %s %s; ' % (r['subject'], r['type'], r['object'])
- msg += '.'
- raise Exception, msg
-
- def check_relationships_rest(self, pkg1_name, pkg2_name=None,
- expected_relationships=[]):
- rels = self.get_relationships(package1_name=pkg1_name,
- package2_name=pkg2_name)
- self.assert_len_relationships(rels, expected_relationships)
- for rel in rels:
- the_expected_rel = None
- for expected_rel in expected_relationships:
- if expected_rel['type'] == rel['type'] and \
- (pkg2_name or expected_rel['object'] == pkg2_name):
- the_expected_rel = expected_rel
- break
- if not the_expected_rel:
- raise Exception('Unexpected relationship: %s %s %s' %
- (rel['subject'], rel['type'], rel['object']))
- for field in ('subject', 'object', 'type', 'comment'):
- if the_expected_rel.has_key(field):
- value = rel[field]
- expected = the_expected_rel[field]
- assert value == expected, (value, expected, field, rel)
-
- def check_relationship_dict(self, rel_dict, subject_name, type, object_name, comment):
- subject_ref = self.package_ref_from_name(subject_name)
- object_ref = self.package_ref_from_name(object_name)
-
- assert rel_dict['subject'] == subject_ref, (rel_dict, subject_ref)
- assert rel_dict['object'] == object_ref, (rel_dict, object_ref)
- assert rel_dict['type'] == type, (rel_dict, type)
- assert rel_dict['comment'] == comment, (rel_dict, comment)
-
-
-# Tests for Version 1 of the API.
-class TestModelApi1(Api1TestCase, ModelApiTestCase):
-
- def test_06_create_pkg_using_download_url(self):
- test_params = {
- 'name':u'testpkg06',
- 'download_url':u'ftp://ftp.monash.edu.au/pub/nihongo/JMdict.gz',
- }
- offset = self.package_offset()
- postparams = '%s=1' % self.dumps(test_params)
- res = self.app.post(offset, params=postparams,
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(test_params['name'])
- assert pkg
- assert pkg.name == test_params['name'], pkg
- assert len(pkg.resources) == 1, pkg.resources
- assert pkg.resources[0].url == test_params['download_url'], pkg.resources[0]
-
- def test_10_edit_pkg_with_download_url(self):
- test_params = {
- 'name':u'testpkg10',
- 'download_url':u'testurl',
- }
- rev = model.repo.new_revision()
- pkg = model.Package()
- model.Session.add(pkg)
- pkg.name = test_params['name']
- pkg.download_url = test_params['download_url']
- model.Session.commit()
-
- pkg = self.get_package_by_name(test_params['name'])
- model.setup_default_user_roles(pkg, [self.user])
- rev = model.repo.new_revision()
- model.repo.commit_and_remove()
- assert self.get_package_by_name(test_params['name'])
-
- # edit it
- pkg_vals = {'download_url':u'newurl'}
- offset = self.package_offset(test_params['name'])
- postparams = '%s=1' % self.dumps(pkg_vals)
- res = self.app.post(offset, params=postparams, status=[200],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = model.Session.query(model.Package).filter_by(name=test_params['name']).one()
- assert len(pkg.resources) == 1, pkg.resources
- assert pkg.resources[0].url == pkg_vals['download_url']
-
-
-class TestRelationshipsApi1(Api1TestCase, RelationshipsApiTestCase): pass
-
-# Tests for Version 2 of the API.
-class TestModelApi2(Api2TestCase, ModelApiTestCase): pass
-class TestRelationshipsApi2(Api2TestCase, RelationshipsApiTestCase): pass
-
-# Tests for unversioned API.
-class TestModelApiUnversioned(ApiUnversionedTestCase, ModelApiTestCase): pass
-class TestRelationshipsApiUnversioned(RelationshipsApiTestCase, ApiUnversionedTestCase): pass
-
--- a/ckan/tests/functional/api/test_package_search.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/test_package_search.py Thu Jul 07 20:46:38 2011 +0100
@@ -179,6 +179,7 @@
def test_08_uri_qjson_malformed(self):
offset = self.base_url + '?qjson="q":""' # user forgot the curly braces
res = self.app.get(offset, status=400)
+ self.assert_json_response(res, 'Bad request - Could not read parameters')
def test_08_all_fields(self):
rating = model.Rating(user_ip_address=u'123.1.2.3',
@@ -211,6 +212,7 @@
res = self.app.get(offset, status=400)
assert('boolean' in res.body)
assert('all_fields' in res.body)
+ self.assert_json_response(res, 'boolean')
def test_09_just_tags(self):
offset = self.base_url + '?tags=russian&all_fields=1'
@@ -257,6 +259,7 @@
res = self.app.get(offset, status=400)
assert('integer' in res.body)
assert('offset' in res.body)
+ self.assert_json_response(res, 'integer')
def test_12_all_packages_qjson(self):
query = {'q': ''}
--- a/ckan/tests/functional/api/test_resource_search.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/test_resource_search.py Thu Jul 07 20:46:38 2011 +0100
@@ -70,6 +70,7 @@
def test_04_bad_option(self):
offset = self.base_url + '?random=option'
result = self.app.get(offset, status=400)
+ self.assert_json_response(result, 'Bad request - Bad search option')
def test_05_options(self):
offset = self.base_url + '?url=site&all_fields=1&callback=mycallback'
--- a/ckan/tests/functional/api/test_revision_search.py Tue Jul 05 17:16:08 2011 +0100
+++ b/ckan/tests/functional/api/test_revision_search.py Thu Jul 07 20:46:38 2011 +0100
@@ -11,13 +11,19 @@
def teardown_class(self):
model.repo.rebuild_db()
- def test_12_search_revision_basic(self):
+ def test_12_search_revision_bad_requests(self):
offset = self.offset('/search/revision')
# Check bad request.
- self.app.get(offset, status=400)
- self.app.get(offset+'?since_rev=2010-01-01T00:00:00', status=400)
- self.app.get(offset+'?since_revision=2010-01-01T00:00:00', status=400)
- self.app.get(offset+'?since_id=', status=400)
+ res = self.app.get(offset, status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_rev=2010-01-01T00:00:00', status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_revision=2010-01-01T00:00:00', status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_id=', status=400)
+ self.assert_json_response(res, 'Bad request - No revision specified')
+ res = self.app.get(offset+'?since_id=1234', status=404)
+ self.assert_json_response(res, 'Not found - There is no revision')
def test_12_search_revision_since_rev(self):
offset = self.offset('/search/revision')
@@ -54,8 +60,9 @@
assert res_list == [], res_list
# Check bad format.
params = "?since_time=2010-04-31T23:45"
- self.app.get(offset+params, status=400)
+ res = self.app.get(offset+params, status=400)
+ self.assert_json_response(res, 'Bad request - ValueError: day is out of range for month')
-class TestPackageSearchApi1(Api1TestCase, RevisionSearchApiTestCase): pass
-class TestPackageSearchApi2(Api2TestCase, RevisionSearchApiTestCase): pass
+class TestRevisionSearchApi1(Api1TestCase, RevisionSearchApiTestCase): pass
+class TestRevisionSearchApi2(Api2TestCase, RevisionSearchApiTestCase): pass
--- a/doc/api/model_formats.rst.inc Tue Jul 05 17:16:08 2011 +0100
+++ b/doc/api/model_formats.rst.inc Thu Jul 07 20:46:38 2011 +0100
@@ -26,6 +26,6 @@
* When you update an object, fields that you don't supply will remain as they were before.
- * To delete an 'extra' key-value pair, supply the key with a None value.
+ * To delete an 'extra' key-value pair, supply the key with JSON value: ``null``
* When you read a package then some additional information is supplied that cannot current be adjusted throught the CKAN API. This includes info on Package Relationship ('relationships'), Group membership ('groups'), ratings ('ratings_average' and 'ratings_count'), full URL of the package in CKAN ('ckan_url') and Package ID ('id'). This is purely a convenience for clients, and only forms part of the Package on GET.
--- a/doc/api/model_resources_table.rst.inc Tue Jul 05 17:16:08 2011 +0100
+++ b/doc/api/model_resources_table.rst.inc Thu Jul 07 20:46:38 2011 +0100
@@ -8,7 +8,7 @@
+--------------------------------+-------------------------------------------------------------------+
| Group Register | ``/rest/group`` |
+--------------------------------+-------------------------------------------------------------------+
-| Group Entity | ``/rest/group/GROUP-NAME`` |
+| Group Entity | ``/rest/group/GROUP-REF`` |
+--------------------------------+-------------------------------------------------------------------+
| Tag Register | ``/rest/tag`` |
+--------------------------------+-------------------------------------------------------------------+
@@ -16,9 +16,9 @@
+--------------------------------+-------------------------------------------------------------------+
| Rating Register | ``/rest/rating`` |
+--------------------------------+-------------------------------------------------------------------+
-| Rating Entity | ``/rest/rating/PACKAGE-REF`` |
+| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships`` |
+--------------------------------+-------------------------------------------------------------------+
-| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships`` |
+| Package Relationships Register | ``/rest/package/PACKAGE-REF/RELATIONSHIP-TYPE`` |
+--------------------------------+-------------------------------------------------------------------+
| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships/PACKAGE-REF`` |
+--------------------------------+-------------------------------------------------------------------+
http://bitbucket.org/okfn/ckan/changeset/27a8c0e546da/
changeset: 27a8c0e546da
branch: feature-1141-moderated-edits-ajax
user: dread
date: 2011-07-07 23:01:30
summary: [lib,logic][l]: Transplant of defect-1214-api-improvements branch (cset:be2be28660b1).
affected #: 21 files (36.7 KB)
--- a/ckan/controllers/api.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/controllers/api.py Thu Jul 07 22:01:30 2011 +0100
@@ -30,10 +30,6 @@
}
class ApiController(BaseController):
- content_type_text = 'text/;charset=utf-8'
- content_type_html = 'text/html;charset=utf-8'
- content_type_json = 'application/json;charset=utf-8'
-
def __call__(self, environ, start_response):
self._identify_user()
if not self.authorizer.am_authorized(c, model.Action.SITE_READ, model.System):
@@ -45,6 +41,8 @@
start_response(body, response.headers.items())
return [response_msg]
else:
+ # avoid status_code_redirect intercepting error responses
+ environ['pylons.status_code_redirect'] = True
return BaseController.__call__(self, environ, start_response)
def _finish(self, status_int, response_data=None,
@@ -106,6 +104,14 @@
response_data=response_data,
content_type='json')
+ def _finish_bad_request(self, extra_msg=None):
+ response_data = _('Bad request')
+ if extra_msg:
+ response_data = '%s - %s' % (response_data, extra_msg)
+ return self._finish(status_int=400,
+ response_data=response_data,
+ content_type='json')
+
def _wrap_jsonp(self, callback, response_msg):
return '%s(%s);' % (callback, response_msg)
@@ -140,8 +146,8 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot list entity of this type: %s') % register
+ return self._finish_bad_request(
+ gettext('Cannot list entity of this type: %s') % register)
try:
return self._finish_ok(action(context))
except NotFound, e:
@@ -151,7 +157,6 @@
return self._finish_not_authz()
def show(self, ver=None, register=None, subregister=None, id=None, id2=None):
-
action_map = {
'revision': get.revision_show,
'group': get.group_show_rest,
@@ -171,8 +176,8 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot read entity of this type: %s') % register
+ return self._finish_bad_request(
+ gettext('Cannot read entity of this type: %s') % register)
try:
return self._finish_ok(action(context))
@@ -205,15 +210,16 @@
try:
request_data = self._get_request_data()
except ValueError, inst:
- response.status_int = 400
- return gettext('JSON Error: %s') % str(inst)
+ return self._finish_bad_request(
+ gettext('JSON Error: %s') % str(inst))
action = action_map.get((register, subregister))
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot create new entity of this type: %s %s') % (register, subregister)
+ return self._finish_bad_request(
+ gettext('Cannot create new entity of this type: %s %s') % \
+ (register, subregister))
try:
response_data = action(request_data, context)
location = None
@@ -251,15 +257,15 @@
try:
request_data = self._get_request_data()
except ValueError, inst:
- response.status_int = 400
- return gettext('JSON Error: %s') % str(inst)
+ return self._finish_bad_request(
+ gettext('JSON Error: %s') % str(inst))
action = action_map.get((register, subregister))
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot update entity of this type: %s') % \
- register.encode('utf-8')
+ return self._finish_bad_request(
+ gettext('Cannot update entity of this type: %s') % \
+ register.encode('utf-8'))
try:
response_data = action(request_data, context)
return self._finish_ok(response_data)
@@ -294,8 +300,9 @@
if not action:
action = action_map.get(register)
if not action:
- response.status_int = 400
- return gettext('Cannot delete entity of this type: %s %s') % (register, subregister or '')
+ return self._finish_bad_request(
+ gettext('Cannot delete entity of this type: %s %s') %\
+ (register, subregister or ''))
try:
response_data = action(context)
return self._finish_ok(response_data)
@@ -315,29 +322,31 @@
since_time = None
if request.params.has_key('since_id'):
id = request.params['since_id']
+ if not id:
+ return self._finish_bad_request(
+ gettext(u'No revision specified'))
rev = model.Session.query(model.Revision).get(id)
if rev is None:
- response.status_int = 400
- return gettext(u'There is no revision with id: %s') % id
+ return self._finish_not_found(
+ gettext(u'There is no revision with id: %s') % id)
since_time = rev.timestamp
elif request.params.has_key('since_time'):
since_time_str = request.params['since_time']
try:
since_time = model.strptimestamp(since_time_str)
except ValueError, inst:
- response.status_int = 400
- return 'ValueError: %s' % inst
+ return self._finish_bad_request('ValueError: %s' % inst)
else:
- response.status_int = 400
- return gettext("Missing search term ('since_id=UUID' or 'since_time=TIMESTAMP')")
+ return self._finish_bad_request(
+ gettext("Missing search term ('since_id=UUID' or 'since_time=TIMESTAMP')"))
revs = model.Session.query(model.Revision).filter(model.Revision.timestamp>since_time)
return self._finish_ok([rev.id for rev in revs])
elif register == 'package' or register == 'resource':
try:
params = self._get_search_params(request.params)
except ValueError, e:
- response.status_int = 400
- return gettext('Could not read parameters: %r' % e)
+ return self._finish_bad_request(
+ gettext('Could not read parameters: %r' % e))
options = QueryOptions()
for k, v in params.items():
if (k in DEFAULT_OPTIONS.keys()):
@@ -373,11 +382,11 @@
return self._finish_ok(results)
except SearchError, e:
log.exception(e)
- response.status_int = 400
- return gettext('Bad search option: %s') % e
+ return self._finish_bad_request(
+ gettext('Bad search option: %s') % e)
else:
- response.status_int = 404
- return gettext('Unknown register: %s') % register
+ return self._finish_not_found(
+ gettext('Unknown register: %s') % register)
@classmethod
def _get_search_params(cls, request_params):
--- a/ckan/lib/dictization/model_save.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/lib/dictization/model_save.py Thu Jul 07 22:01:30 2011 +0100
@@ -67,9 +67,6 @@
def package_extras_save(extra_dicts, obj, context):
- allow_partial_update = context.get("allow_partial_update", False)
- if not extra_dicts and allow_partial_update:
- return
model = context["model"]
session = context["session"]
@@ -81,7 +78,10 @@
for extra_dict in extra_dicts:
if extra_dict.get("deleted"):
continue
- if extras_as_string:
+
+ if extra_dict['value'] is None:
+ pass
+ elif extras_as_string:
new_extras[extra_dict["key"]] = extra_dict["value"]
else:
new_extras[extra_dict["key"]] = json.loads(extra_dict["value"])
@@ -318,10 +318,15 @@
updated_extras.update(value)
new_value = []
+
for extras_key, extras_value in updated_extras.iteritems():
if extras_value is not None:
new_value.append({"key": extras_key,
"value": json.dumps(extras_value)})
+ else:
+ new_value.append({"key": extras_key,
+ "value": None})
+
dictized[key] = new_value
groups = dictized.pop('groups', None)
--- a/ckan/logic/action/create.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/logic/action/create.py Thu Jul 07 22:01:30 2011 +0100
@@ -91,7 +91,7 @@
user = context['user']
id = context["id"]
id2 = context["id2"]
- rel = context["rel"]
+ rel_type = context["rel"]
api = context.get('api_version') or '1'
ref_package_by = 'id' if api == '2' else 'name'
@@ -112,14 +112,14 @@
##FIXME should have schema
comment = data_dict.get('comment', u'')
- existing_rels = pkg1.get_relationships_with(pkg2, rel)
+ existing_rels = pkg1.get_relationships_with(pkg2, rel_type)
if existing_rels:
return _update_package_relationship(existing_rels[0],
comment, context)
rev = model.repo.new_revision()
rev.author = user
- rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel, pkg2)
- rel = pkg1.add_relationship(rel, pkg2, comment=comment)
+ rev.message = _(u'REST API: Create package relationship: %s %s %s') % (pkg1, rel_type, pkg2)
+ rel = pkg1.add_relationship(rel_type, pkg2, comment=comment)
model.repo.commit_and_remove()
relationship_dicts = rel.as_dict(ref_package_by=ref_package_by)
return relationship_dicts
--- a/ckan/logic/action/get.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/logic/action/get.py Thu Jul 07 22:01:30 2011 +0100
@@ -215,7 +215,7 @@
def tag_show(context):
model = context['model']
- api = context.get('api') or '1'
+ api = context.get('api_version') or '1'
id = context['id']
ref_package_by = 'id' if api == '2' else 'name'
obj = model.Tag.get(id) #TODO tags
--- a/ckan/logic/action/update.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/logic/action/update.py Thu Jul 07 22:01:30 2011 +0100
@@ -6,7 +6,12 @@
from ckan.plugins import PluginImplementations, IGroupController, IPackageController
from ckan.logic import NotFound, check_access, NotAuthorized, ValidationError
from ckan.lib.base import _
-from ckan.lib.dictization.model_dictize import group_dictize, package_dictize
+from ckan.lib.dictization.model_dictize import (package_dictize,
+ package_to_api1,
+ package_to_api2,
+ group_dictize,
+ group_to_api1,
+ group_to_api2)
from ckan.lib.dictization.model_save import (group_api_to_dict,
package_api_to_dict,
group_dict_save,
@@ -172,7 +177,7 @@
if 'message' in context:
rev.message = context['message']
else:
- rev.message = _(u'REST API: Create object %s') % data.get("name")
+ rev.message = _(u'REST API: Update object %s') % data.get("name")
pkg = package_dict_save(data, context)
@@ -256,7 +261,7 @@
if 'message' in context:
rev.message = context['message']
else:
- rev.message = _(u'REST API: Create object %s') % data.get("name")
+ rev.message = _(u'REST API: Update object %s') % data.get("name")
group = group_dict_save(data, context)
@@ -275,19 +280,38 @@
model = context['model']
id = context["id"]
+ api = context.get('api_version') or '1'
pkg = model.Package.get(id)
context["package"] = pkg
context["allow_partial_update"] = True
dictized_package = package_api_to_dict(data_dict, context)
- return package_update(dictized_package, context)
+ dictized_after = package_update(dictized_package, context)
+
+ pkg = context['package']
+
+ if api == '1':
+ package_dict = package_to_api1(pkg, context)
+ else:
+ package_dict = package_to_api2(pkg, context)
+
+ return package_dict
def group_update_rest(data_dict, context):
model = context['model']
id = context["id"]
+ api = context.get('api_version') or '1'
group = model.Group.get(id)
context["group"] = group
context["allow_partial_update"] = True
dictized_package = group_api_to_dict(data_dict, context)
- return group_update(dictized_package, context)
+ dictized_after = group_update(dictized_package, context)
+ group = context['group']
+
+ if api == '1':
+ group_dict = group_to_api1(group, context)
+ else:
+ group_dict = group_to_api2(group, context)
+
+ return group_dict
--- a/ckan/logic/schema.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/logic/schema.py Thu Jul 07 22:01:30 2011 +0100
@@ -167,7 +167,7 @@
schema = {
'id': [ignore],
'key': [not_empty, unicode],
- 'value': [not_missing, unicode],
+ 'value': [not_missing],
'state': [ignore],
'deleted': [ignore_missing],
'revision_timestamp': [ignore],
--- a/ckan/model/package.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/model/package.py Thu Jul 07 22:01:30 2011 +0100
@@ -225,7 +225,7 @@
subject = related_package
object_ = self
else:
- raise NotImplementedError, 'Package relationship type: %r' % type_
+ raise KeyError, 'Package relationship type: %r' % type_
rels = self.get_relationships(with_package=related_package,
type=type_, active=False, direction="forward")
--- a/ckan/tests/functional/api/base.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/base.py Thu Jul 07 22:01:30 2011 +0100
@@ -69,7 +69,7 @@
return '%s%s' % (base, path)
def package_offset(self, package_name=None):
- if package_name == None:
+ if package_name is None:
# Package Register
return self.offset('/rest/package')
else:
@@ -79,14 +79,14 @@
def package_ref_from_name(self, package_name):
package = self.get_package_by_name(unicode(package_name))
- if package == None:
+ if package is None:
return package_name
else:
return self.ref_package(package)
def package_id_from_ref(self, package_name):
package = self.get_package_by_name(unicode(package_name))
- if package == None:
+ if package is None:
return package_name
else:
return self.ref_package(package)
@@ -96,7 +96,7 @@
return getattr(package, self.ref_package_by)
def group_offset(self, group_name=None):
- if group_name == None:
+ if group_name is None:
# Group Register
return self.offset('/rest/group')
else:
@@ -106,7 +106,7 @@
def group_ref_from_name(self, group_name):
group = self.get_group_by_name(unicode(group_name))
- if group == None:
+ if group is None:
return group_name
else:
return self.ref_group(group)
@@ -115,11 +115,52 @@
assert self.ref_group_by in ['id', 'name']
return getattr(group, self.ref_group_by)
+ def revision_offset(self, revision_id=None):
+ if revision_id is None:
+ # Revision Register
+ return self.offset('/rest/revision')
+ else:
+ # Revision Entity
+ return self.offset('/rest/revision/%s' % revision_id)
+
+ def rating_offset(self, package_name=None):
+ if package_name is None:
+ # Revision Register
+ return self.offset('/rest/rating')
+ else:
+ # Revision Entity
+ package_ref = self.package_ref_from_name(package_name)
+ return self.offset('/rest/rating/%s' % package_ref)
+
+ def relationship_offset(self, package_1_name=None,
+ relationship_type=None,
+ package_2_name=None,
+ ):
+ assert package_1_name
+ package_1_ref = self.package_ref_from_name(package_1_name)
+ if package_2_name is None:
+ if not relationship_type:
+ return self.offset('/rest/package/%s/relationships' % \
+ package_1_ref)
+ else:
+ return self.offset('/rest/package/%s/%s' %
+ (package_1_ref, relationship_type))
+ else:
+ package_2_ref = self.package_ref_from_name(package_2_name)
+ if not relationship_type:
+ return self.offset('/rest/package/%s/relationships/%s' % \
+ (package_1_ref, package_2_ref))
+ else:
+ return self.offset('/rest/package/%s/%s/%s' % \
+ (package_1_ref,
+ relationship_type,
+ package_2_ref))
+
def anna_offset(self, postfix=''):
return self.package_offset('annakarenina') + postfix
def tag_offset(self, tag_name=None):
- if tag_name == None:
+ if tag_name is None:
# Tag Register
return self.offset('/rest/tag')
else:
@@ -129,7 +170,7 @@
def tag_ref_from_name(self, tag_name):
tag = self.get_tag_by_name(unicode(tag_name))
- if tag == None:
+ if tag is None:
return tag_name
else:
return self.ref_tag(tag)
@@ -199,9 +240,10 @@
def assert_msg_represents_russian(self, msg):
data = self.loads(msg)
pkgs = set(data)
- expected_pkgs = set(['annakarenina', 'warandpeace'])
- missing_pkgs = expected_pkgs - pkgs
- assert not missing_pkgs, missing_pkgs
+ expected_pkgs = set([self.package_ref_from_name('annakarenina'),
+ self.package_ref_from_name('warandpeace')])
+ differences = expected_pkgs ^ pkgs
+ assert not differences, '%r != %r' % (pkgs, expected_pkgs)
def data_from_res(self, res):
return self.loads(res.body)
@@ -218,6 +260,16 @@
except ValueError, inst:
raise Exception, "Couldn't loads string '%s': %s" % (chars, inst)
+ def assert_json_response(self, res, expected_in_body=None):
+ content_type = res.header_dict['Content-Type']
+ assert 'application/json' in content_type, content_type
+ res_json = self.loads(res.body)
+ if expected_in_body:
+ assert expected_in_body in res_json or \
+ expected_in_body in str(res_json), \
+ 'Expected to find %r in JSON response %r' % \
+ (expected_in_body, res_json)
+
# Todo: Rename to Version1TestCase.
class Api1TestCase(ApiTestCase):
@@ -297,8 +349,6 @@
def teardown(self):
model.Session.remove()
model.repo.rebuild_db()
- #self.delete_common_fixtures()
- #self.commit_remove()
super(BaseModelApiTestCase, self).teardown()
def init_extra_environ(self):
@@ -312,22 +362,38 @@
application/x-www-form-urlencoded)
'''
- return self.post_body(offset, data, content_type='application/json',
- content_length=len(data),
- status=status, extra_environ=extra_environ)
+ return self.http_request(offset, data, content_type='application/json',
+ request_method='POST',
+ content_length=len(data),
+ status=status, extra_environ=extra_environ)
- def post_body(self, offset, data, content_type, content_length=None,
- status=None, extra_environ=None):
+ def delete_request(self, offset, status=None, extra_environ=None):
+ ''' Sends a delete request. Similar to the paste.delete but it
+ does not send the content type or content length.
+ '''
+ return self.http_request(offset, data='', content_type=None,
+ request_method='DELETE',
+ content_length=None,
+ status=status,
+ extra_environ=extra_environ)
+
+ def http_request(self, offset, data,
+ content_type='application/json',
+ request_method='POST',
+ content_length=None,
+ status=None,
+ extra_environ=None):
''' Posts data in the body in a user-specified format.
(rather than Paste Fixture\'s default Content-Type of
application/x-www-form-urlencoded)
'''
environ = self.app._make_environ()
- environ['CONTENT_TYPE'] = content_type
+ if content_type:
+ environ['CONTENT_TYPE'] = content_type
if content_length is not None:
environ['CONTENT_LENGTH'] = str(content_length)
- environ['REQUEST_METHOD'] = 'POST'
+ environ['REQUEST_METHOD'] = request_method
environ['wsgi.input'] = StringIO(data)
if extra_environ:
environ.update(extra_environ)
--- a/ckan/tests/functional/api/model/test_group.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/model/test_group.py Thu Jul 07 22:01:30 2011 +0100
@@ -1,5 +1,7 @@
import copy
+from ckan import model
+
from nose.tools import assert_equal
from ckan.tests.functional.api.base import BaseModelApiTestCase
@@ -29,6 +31,10 @@
# check group object
group = self.get_group_by_name(self.testgroupvalues['name'])
assert group
+ assert group.title == self.testgroupvalues['title'], group
+ assert group.description == self.testgroupvalues['description'], group
+ pkg_names = [pkg.name for pkg in group.packages]
+ assert set(pkg_names) == set(('annakarenina', 'warandpeace')), pkg_names
# check register updated
res = self.app.get(offset, status=self.STATUS_200_OK)
@@ -53,11 +59,15 @@
res = self.app.post(offset, params=postparams,
status=self.STATUS_409_CONFLICT,
extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'Group name already exists')
def test_entity_get_ok(self):
offset = self.group_offset(self.roger.name)
res = self.app.get(offset, status=self.STATUS_200_OK)
self.assert_msg_represents_roger(msg=res.body)
+ assert self.package_ref_from_name('annakarenina') in res, res
+ assert self.group_ref_from_name('roger') in res, res
+ assert not self.package_ref_from_name('warandpeace') in res, res
def test_entity_get_then_post(self):
# (ticket 662) Ensure an entity you 'get' from a register can be
@@ -70,6 +80,123 @@
status=self.STATUS_200_OK,
extra_environ=self.extra_environ)
+ def test_05_get_group_entity_not_found(self):
+ offset = self.offset('/rest/group/22222')
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+ def test_10_edit_group(self):
+ # create a group with testgroupvalues
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ if not group:
+ offset = self.offset('/rest/group')
+ postparams = '%s=1' % self.dumps(self.testgroupvalues)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ assert group
+ assert len(group.packages) == 2, group.packages
+ user = model.User.by_name(self.user_name)
+ model.setup_default_user_roles(group, [user])
+
+ # edit it
+ group_vals = {'name':u'somethingnew', 'title':u'newtesttitle',
+ 'packages':[u'annakarenina']}
+ offset = self.group_offset(self.testgroupvalues['name'])
+ postparams = '%s=1' % self.dumps(group_vals)
+ res = self.app.post(offset, params=postparams, status=[200],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ group = model.Session.query(model.Group).filter_by(name=group_vals['name']).one()
+ assert group.name == group_vals['name']
+ assert group.title == group_vals['title']
+ assert len(group.packages) == 1, group.packages
+ assert group.packages[0].name == group_vals['packages'][0]
+
+ def test_10_edit_group_name_duplicate(self):
+ # create a group with testgroupvalues
+ if not model.Group.by_name(self.testgroupvalues['name']):
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = self.testgroupvalues['name']
+ model.Session.commit()
+
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ model.setup_default_user_roles(group, [self.user])
+ rev = model.repo.new_revision()
+ model.repo.commit_and_remove()
+ assert model.Group.by_name(self.testgroupvalues['name'])
+
+ # create a group with name 'dupname'
+ dupname = u'dupname'
+ if not model.Group.by_name(dupname):
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = dupname
+ model.Session.commit()
+ assert model.Group.by_name(dupname)
+
+ # edit first group to have dupname
+ group_vals = {'name':dupname}
+ offset = self.group_offset(self.testgroupvalues['name'])
+ postparams = '%s=1' % self.dumps(group_vals)
+ res = self.app.post(offset, params=postparams, status=[409],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'Group name already exists')
+
+ def test_11_delete_group(self):
+ # Test Groups Entity Delete 200.
+
+ # create a group with testgroupvalues
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ if not group:
+ rev = model.repo.new_revision()
+ group = model.Group()
+ model.Session.add(group)
+ group.name = self.testgroupvalues['name']
+ model.repo.commit_and_remove()
+
+ rev = model.repo.new_revision()
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ model.setup_default_user_roles(group, [self.user])
+ model.repo.commit_and_remove()
+ assert group
+ user = model.User.by_name(self.user_name)
+ model.setup_default_user_roles(group, [user])
+
+ # delete it
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.delete(offset, status=[200],
+ extra_environ=self.extra_environ)
+
+ group = model.Group.by_name(self.testgroupvalues['name'])
+ assert group
+ assert group.state == 'deleted', group.state
+
+ res = self.app.get(offset, status=[403])
+ self.assert_json_response(res, 'Access denied')
+ res = self.app.get(offset, status=[200],
+ extra_environ=self.extra_environ)
+
+ def test_12_get_group_404(self):
+ # Test Package Entity Get 404.
+ assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+ def test_13_delete_group_404(self):
+ # Test Packages Entity Delete 404.
+ assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
+ offset = self.group_offset(self.testgroupvalues['name'])
+ res = self.app.delete(offset, status=[404],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'not found')
+
+
class TestGroupsVersion1(Version1TestCase, GroupsTestCase): pass
class TestGroupsVersion2(Version2TestCase, GroupsTestCase): pass
class TestGroupsUnversioned(UnversionedTestCase, GroupsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_licenses.py Thu Jul 07 22:01:30 2011 +0100
@@ -0,0 +1,32 @@
+from nose.tools import assert_equal
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class LicensesTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = False
+
+ def test_register_get_ok(self):
+ from ckan.model.license import LicenseRegister
+ register = LicenseRegister()
+ assert len(register), "No changesets found in model."
+ offset = self.offset('/rest/licenses')
+ res = self.app.get(offset, status=[200])
+ licenses_data = self.data_from_res(res)
+ assert len(licenses_data) == len(register), (len(licenses_data), len(register))
+ for license_data in licenses_data:
+ id = license_data['id']
+ license = register[id]
+ assert license['title'] == license.title
+ assert license['url'] == license.url
+
+
+class TestLicensesVersion1(Version1TestCase, LicensesTestCase): pass
+class TestLicensesVersion2(Version2TestCase, LicensesTestCase): pass
+class TestLicensesUnversioned(UnversionedTestCase, LicensesTestCase): pass
--- a/ckan/tests/functional/api/model/test_package.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py Thu Jul 07 22:01:30 2011 +0100
@@ -1,3 +1,5 @@
+import copy
+
from nose.tools import assert_equal
from ckan.tests.functional.api.base import BaseModelApiTestCase
@@ -35,6 +37,15 @@
res = self.app.post(offset, params=postparams,
status=self.STATUS_201_CREATED,
extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], self.package_fixture_data['name'])
+ assert_equal(pkg['title'], self.package_fixture_data['title'])
+ assert_equal(set(pkg['tags']), set(self.package_fixture_data['tags']))
+ assert_equal(len(pkg['resources']), len(self.package_fixture_data['resources']))
+ assert_equal(pkg['extras'], self.package_fixture_data['extras'])
+
# Check the value of the Location header.
location = res.header('Location')
assert offset in location
@@ -107,14 +118,26 @@
assert not self.get_package_by_name(self.package_fixture_data['name'])
offset = self.package_offset()
data = self.dumps(self.package_fixture_data)
- res = self.post_body(offset, data, content_type='something/unheard_of',
- status=self.STATUS_400_BAD_REQUEST,
- extra_environ=self.extra_environ)
+ res = self.http_request(offset, data, content_type='something/unheard_of',
+ status=self.STATUS_400_BAD_REQUEST,
+ extra_environ=self.extra_environ)
# Check there is no database record.
self.remove()
package = self.get_package_by_name(self.package_fixture_data['name'])
assert not package
+ def test_register_post_json(self):
+ assert not self.get_package_by_name(self.package_fixture_data['name'])
+ offset = self.package_offset()
+ data = self.dumps(self.package_fixture_data)
+ res = self.post_json(offset, data, status=self.STATUS_201_CREATED,
+ extra_environ=self.extra_environ)
+ # Check the database record.
+ self.remove()
+ package = self.get_package_by_name(self.package_fixture_data['name'])
+ assert package
+ self.assert_equal(package.title, self.package_fixture_data['title'])
+
def test_register_post_bad_request(self):
test_params = {
'name':u'testpackage06_400',
@@ -211,7 +234,8 @@
def create_package_roles_revision(self, package_data):
self.create_package(admins=[self.user], data=package_data)
- def assert_package_update_ok(self, package_ref_attribute):
+ def assert_package_update_ok(self, package_ref_attribute,
+ method_str):
old_fixture_data = {
'name': self.package_fixture_data['name'],
'url': self.package_fixture_data['url'],
@@ -248,10 +272,28 @@
'tags': [u'tag1', u'tag2', u'tag4', u'tag5'],
}
self.create_package_roles_revision(old_fixture_data)
- offset = self.package_offset(old_fixture_data['name'])
+ pkg = self.get_package_by_name(old_fixture_data['name'])
+ # This is the one occasion where we reference package explicitly
+ # by name or ID, rather than use the value from self.ref_package_by
+ # because you should be able to specify the package both ways round
+ # for both versions of the API.
+ package_ref = getattr(pkg, package_ref_attribute)
+ offset = self.offset('/rest/package/%s' % package_ref)
params = '%s=1' % self.dumps(new_fixture_data)
- res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
- extra_environ=self.extra_environ)
+ method_func = getattr(self.app, method_str)
+ res = method_func(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ assert_equal(pkg['title'], new_fixture_data['title'])
+ assert_equal(set(pkg['tags']), set(new_fixture_data['tags']))
+ assert_equal(len(pkg['resources']), len(new_fixture_data['resources']))
+ expected_extras = copy.deepcopy(new_fixture_data['extras'])
+ del expected_extras['key2']
+ expected_extras['key1'] = old_fixture_data['extras']['key1']
+ assert_equal(pkg['extras'], expected_extras)
# Check submitted field have changed.
self.remove()
@@ -296,10 +338,78 @@
assert not package.extras.has_key('key2')
def test_package_update_ok_by_id(self):
- self.assert_package_update_ok('id')
+ self.assert_package_update_ok('id', 'post')
def test_entity_update_ok_by_name(self):
- self.assert_package_update_ok('name')
+ self.assert_package_update_ok('name', 'post')
+
+ def test_package_update_ok_by_id_by_put(self):
+ self.assert_package_update_ok('id', 'put')
+
+ def test_entity_update_ok_by_name_by_put(self):
+ self.assert_package_update_ok('name', 'put')
+
+ def test_package_update_delete_last_extra(self):
+ old_fixture_data = {
+ 'name': self.package_fixture_data['name'],
+ 'extras': {
+ u'key1': u'val1',
+ },
+ }
+ new_fixture_data = {
+ 'name':u'somethingnew',
+ 'extras': {
+ u'key1': None,
+ },
+ }
+ self.create_package_roles_revision(old_fixture_data)
+ offset = self.package_offset(old_fixture_data['name'])
+ params = '%s=1' % self.dumps(new_fixture_data)
+ res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ expected_extras = copy.deepcopy(new_fixture_data['extras'])
+ del expected_extras['key1']
+ assert_equal(pkg['extras'], expected_extras)
+
+ # Check extra was deleted
+ self.remove()
+ package = self.get_package_by_name(new_fixture_data['name'])
+ # - title
+ self.assert_equal(package.extras, {})
+
+ def test_package_update_do_not_delete_last_extra(self):
+ old_fixture_data = {
+ 'name': self.package_fixture_data['name'],
+ 'extras': {
+ u'key1': u'val1',
+ },
+ }
+ new_fixture_data = {
+ 'name':u'somethingnew',
+ 'extras': {}, # no extras specified, but existing
+ # ones should be left alone
+ }
+ self.create_package_roles_revision(old_fixture_data)
+ offset = self.package_offset(old_fixture_data['name'])
+ params = '%s=1' % self.dumps(new_fixture_data)
+ res = self.app.post(offset, params=params, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+
+ # Check the returned package is as expected
+ pkg = self.loads(res.body)
+ assert_equal(pkg['name'], new_fixture_data['name'])
+ expected_extras = {u'key1': u'val1'} # should not be deleted
+ assert_equal(pkg['extras'], expected_extras)
+
+ # Check extra was not deleted
+ self.remove()
+ package = self.get_package_by_name(new_fixture_data['name'])
+ # - title
+ assert len(package.extras) == 1, package.extras
def test_entity_update_conflict(self):
package1_name = self.package_fixture_data['name']
@@ -311,18 +421,19 @@
package1_offset = self.package_offset(package1_name)
self.post(package1_offset, package2_data, self.STATUS_409_CONFLICT)
+ def test_entity_update_empty(self):
+ package1_name = self.package_fixture_data['name']
+ package1_data = {'name': package1_name}
+ package1 = self.create_package_roles_revision(package1_data)
+ package2_data = '' # this is the error
+ package1_offset = self.package_offset(package1_name)
+ self.app.put(package1_offset, package2_data,
+ status=self.STATUS_400_BAD_REQUEST)
+
def test_entity_delete_ok(self):
# create a package with package_fixture_data
if not self.get_package_by_name(self.package_fixture_data['name']):
- rev = model.repo.new_revision()
- package = model.Package()
- model.Session.add(package)
- package.name = self.package_fixture_data['name']
- model.repo.commit_and_remove()
- rev = model.repo.new_revision()
- package = self.get_package_by_name(self.package_fixture_data['name'])
- model.setup_default_user_roles(package, [self.user])
- model.repo.commit_and_remove()
+ self.create_package(admins=[self.user], name=self.package_fixture_data['name'])
assert self.get_package_by_name(self.package_fixture_data['name'])
# delete it
offset = self.package_offset(self.package_fixture_data['name'])
@@ -332,6 +443,19 @@
self.assert_equal(package.state, 'deleted')
model.Session.remove()
+ def test_entity_delete_ok_without_request_headers(self):
+ # create a package with package_fixture_data
+ if not self.get_package_by_name(self.package_fixture_data['name']):
+ self.create_package(admins=[self.user], name=self.package_fixture_data['name'])
+ assert self.get_package_by_name(self.package_fixture_data['name'])
+ # delete it
+ offset = self.package_offset(self.package_fixture_data['name'])
+ res = self.delete_request(offset, status=self.STATUS_200_OK,
+ extra_environ=self.extra_environ)
+ package = self.get_package_by_name(self.package_fixture_data['name'])
+ self.assert_equal(package.state, 'deleted')
+ model.Session.remove()
+
def test_entity_delete_not_found(self):
package_name = u'random_one'
assert not model.Session.query(model.Package).filter_by(name=package_name).count()
@@ -374,7 +498,52 @@
assert len(revisions) == 3, len(revisions)
-class TestPackagesVersion1(Version1TestCase, PackagesTestCase): pass
+class TestPackagesVersion1(Version1TestCase, PackagesTestCase):
+ def test_06_create_pkg_using_download_url(self):
+ test_params = {
+ 'name':u'testpkg06',
+ 'download_url':u'ftp://ftp.monash.edu.au/pub/nihongo/JMdict.gz',
+ }
+ offset = self.package_offset()
+ postparams = '%s=1' % self.dumps(test_params)
+ res = self.app.post(offset, params=postparams,
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(test_params['name'])
+ assert pkg
+ assert pkg.name == test_params['name'], pkg
+ assert len(pkg.resources) == 1, pkg.resources
+ assert pkg.resources[0].url == test_params['download_url'], pkg.resources[0]
+
+ def test_10_edit_pkg_with_download_url(self):
+ test_params = {
+ 'name':u'testpkg10',
+ 'download_url':u'testurl',
+ }
+ rev = model.repo.new_revision()
+ pkg = model.Package()
+ model.Session.add(pkg)
+ pkg.name = test_params['name']
+ pkg.download_url = test_params['download_url']
+ model.Session.commit()
+
+ pkg = self.get_package_by_name(test_params['name'])
+ model.setup_default_user_roles(pkg, [self.user])
+ rev = model.repo.new_revision()
+ model.repo.commit_and_remove()
+ assert self.get_package_by_name(test_params['name'])
+
+ # edit it
+ pkg_vals = {'download_url':u'newurl'}
+ offset = self.package_offset(test_params['name'])
+ postparams = '%s=1' % self.dumps(pkg_vals)
+ res = self.app.post(offset, params=postparams, status=[200],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = model.Session.query(model.Package).filter_by(name=test_params['name']).one()
+ assert len(pkg.resources) == 1, pkg.resources
+ assert pkg.resources[0].url == pkg_vals['download_url']
+
class TestPackagesVersion2(Version2TestCase, PackagesTestCase): pass
class TestPackagesUnversioned(UnversionedTestCase, PackagesTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_ratings.py Thu Jul 07 22:01:30 2011 +0100
@@ -0,0 +1,94 @@
+from nose.tools import assert_equal
+from nose.plugins.skip import SkipTest
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RatingsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ def test_register_get(self):
+ raise SkipTest('"Rating register get" functionality is not implemented')
+ rating1 = model.Rating(user_ip_address='1.2.3.4',
+ package=self.anna,
+ rating=4.0)
+ rating2 = model.Rating(user=model.User.by_name(u'annafan'),
+ package=self.anna,
+ rating=2.0)
+ model.Session.add_all((rating1, rating2))
+ model.repo.commit_and_remove()
+
+ offset = self.rating_offset()
+ res = self.app.get(offset, status=[200])
+
+ def test_entity_get(self):
+ raise SkipTest('"Rating entity get" functionality is not implemented')
+ rating = model.Rating(user_ip_address='1.2.3.4',
+ package=self.anna,
+ rating=4.0)
+ model.Session.add(rating)
+ model.repo.commit_and_remove()
+
+ offset = self.rating_offset(self.anna.name)
+ res = self.app.get(offset, status=[200])
+ assert_equal(res, rating_opts['rating'])
+
+ def test_register_post(self):
+ # Test Rating Register Post 200.
+ self.clear_all_tst_ratings()
+ offset = self.rating_offset()
+ rating_opts = {'package':u'warandpeace',
+ 'rating':5}
+ pkg_name = rating_opts['package']
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(pkg_name)
+ assert pkg
+ assert len(pkg.ratings) == 1
+ assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
+
+ # Get package to see rating
+ offset = self.package_offset(pkg_name)
+ res = self.app.get(offset, status=[200])
+ assert pkg_name in res, res
+ assert '"ratings_average": %s.0' % rating_opts['rating'] in res, res
+ assert '"ratings_count": 1' in res, res
+
+ model.Session.remove()
+
+ # Rerate package
+ offset = self.rating_offset()
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ model.Session.remove()
+ pkg = self.get_package_by_name(pkg_name)
+ assert pkg
+ assert len(pkg.ratings) == 1
+ assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
+
+ def test_entity_post_invalid(self):
+ self.clear_all_tst_ratings()
+ offset = self.rating_offset()
+ rating_opts = {'package':u'warandpeace',
+ 'rating':0}
+ postparams = '%s=1' % self.dumps(rating_opts)
+ res = self.app.post(offset, params=postparams, status=[409],
+ extra_environ=self.extra_environ)
+ self.assert_json_response(res, 'rating')
+ model.Session.remove()
+ pkg = self.get_package_by_name(rating_opts['package'])
+ assert pkg
+ assert len(pkg.ratings) == 0
+
+class TestRatingsVersion1(Version1TestCase, RatingsTestCase): pass
+class TestRatingsVersion2(Version2TestCase, RatingsTestCase): pass
+class TestRatingsUnversioned(UnversionedTestCase, RatingsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_relationships.py Thu Jul 07 22:01:30 2011 +0100
@@ -0,0 +1,242 @@
+from nose.tools import assert_equal
+from nose.plugins.skip import SkipTest
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RelationshipsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ @classmethod
+ def setup_class(cls):
+# super(RelationshipsTestCase, cls).setup_class()
+ cls.testsysadmin = model.User.by_name(u'testsysadmin')
+ cls.comment = u'Comment umlaut: \xfc.'
+
+ def test_01_create_and_read_relationship(self):
+ # check anna has no existing relationships
+ assert not self.anna.get_relationships()
+ assert self.get_relationships(package1_name='annakarenina') == [], self.get_relationships(package1_name='annakarenina')
+ assert self.get_relationships(package1_name='annakarenina',
+ package2_name='warandpeace') == []
+ assert self.get_relationships(package1_name='annakarenina',
+ type='child_of',
+ package2_name='warandpeace') == 404
+ assert self.get_relationships_via_package('annakarenina') == []
+
+ # Create a relationship.
+ self.create_annakarenina_parent_of_war_and_peace()
+
+ # Check package relationship register.
+ rels = self.get_relationships(package1_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # Todo: Name this?
+ # Check '/api/VER/rest/package/annakarenina/relationships/warandpeace'
+ rels = self.get_relationships(package1_name='annakarenina',
+ package2_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # Todo: Name this?
+ # check '/api/VER/rest/package/annakarenina/parent_of/warandpeace'
+ rels = self.get_relationships(package1_name='annakarenina',
+ type='parent_of',
+ package2_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ # same checks in reverse direction
+ rels = self.get_relationships(package1_name='warandpeace')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ rels = self.get_relationships(package1_name='warandpeace',
+ package2_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ rels = self.get_relationships(package1_name='warandpeace',
+ type='child_of',
+ package2_name='annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'warandpeace', 'child_of', 'annakarenina', self.comment)
+
+ # Check package entity relationships.
+ rels = self.get_relationships_via_package('annakarenina')
+ assert len(rels) == 1
+ self.check_relationship_dict(rels[0],
+ 'annakarenina', 'parent_of', 'warandpeace', self.comment)
+
+ def test_03_update_relationship(self):
+ # Create a relationship.
+ self.create_annakarenina_parent_of_war_and_peace()
+
+ # Check the relationship before update.
+ self.check_relationships_rest('warandpeace', 'annakarenina',
+ [{'type': 'child_of',
+ 'comment': self.comment}])
+
+ # Update the relationship.
+ new_comment = u'New comment.'
+ self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
+
+ # Check the relationship after update.
+ self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
+
+ # Repeat update with same values, to check it remains the same?
+
+ # Update the relationship.
+ new_comment = u'New comment.'
+ self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
+
+ # Check the relationship after update.
+ self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
+
+ def test_05_delete_relationship(self):
+ self.create_annakarenina_parent_of_war_and_peace()
+ self.update_annakarenina_parent_of_war_and_peace()
+ expected = [ {'type': 'child_of', 'comment': u'New comment.'} ]
+ self.check_relationships_rest('warandpeace', 'annakarenina', expected)
+
+ self.delete_annakarenina_parent_of_war_and_peace()
+
+ expected = []
+ self.check_relationships_rest('warandpeace', 'annakarenina', expected)
+
+ def test_create_relationship_unknown(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'unheard_of_type', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':self.comment})
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
+ def test_create_relationship_incorrectly(self):
+ raise SkipTest() # leaving broken for now
+ offset = self.relationship_offset('annakarenina', 'relationships', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'type':'parent_of'})
+ # type should do in the URL offset, not the params.
+ res = self.app.post(offset, params=postparams, status=[400],
+ extra_environ=self.extra_environ)
+
+ def create_annakarenina_parent_of_war_and_peace(self):
+ # Create package relationship.
+ # Todo: Redesign this in a RESTful style, so that a relationship is
+ # created by posting a relationship to a relationship **register**.
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':self.comment})
+ res = self.app.post(offset, params=postparams, status=[201],
+ extra_environ=self.extra_environ)
+ # Check the response
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
+ # Check the model, directly.
+ rels = self.anna.get_relationships()
+ assert len(rels) == 1, rels
+ assert rels[0].type == 'child_of'
+ assert rels[0].subject.name == 'warandpeace'
+ assert rels[0].object.name == 'annakarenina'
+
+ def update_annakarenina_parent_of_war_and_peace(self, comment=u'New comment.'):
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ postparams = '%s=1' % self.dumps({'comment':comment})
+ res = self.app.post(offset, params=postparams, status=[201], extra_environ=self.extra_environ)
+ # Check the response (normalised to 'child_of')
+ rel = self.loads(res.body)
+ assert_equal(rel['type'], 'child_of')
+ assert_equal(rel['subject'], self.ref_package(self.war))
+ assert_equal(rel['object'], self.ref_package(self.anna))
+
+ # Check the model, directly (normalised to 'child_of')
+ rels = self.anna.get_relationships()
+ assert len(rels) == 1, rels
+ assert rels[0].type == 'child_of'
+ assert rels[0].subject.name == 'warandpeace'
+ assert rels[0].object.name == 'annakarenina'
+ return res
+
+ def delete_annakarenina_parent_of_war_and_peace(self):
+ offset = self.relationship_offset('annakarenina', 'parent_of', 'warandpeace')
+ res = self.app.delete(offset, status=[200], extra_environ=self.extra_environ)
+ assert not res.body
+
+ def get_relationships(self, package1_name=u'annakarenina', type='relationships', package2_name=None):
+ offset = self.relationship_offset(package1_name, type, package2_name)
+ allowable_statuses = [200]
+ if type:
+ allowable_statuses.append(404)
+ res = self.app.get(offset, status=allowable_statuses)
+ if res.status == 200:
+ res_dict = self.data_from_res(res) if res.body else []
+ return res_dict
+ else:
+ return 404
+
+ def get_relationships_via_package(self, package1_name):
+ offset = self.package_offset(package1_name)
+ res = self.app.get(offset, status=200)
+ res_dict = self.data_from_res(res)
+ return res_dict['relationships']
+
+ def assert_len_relationships(self, relationships, expected_relationships):
+ len_relationships = len(relationships)
+ len_expected_relationships = len(expected_relationships)
+ if len_relationships != len_expected_relationships:
+ msg = 'Found %i relationships, ' % len_relationships
+ msg += 'but expected %i.' % len_expected_relationships
+ if len_relationships:
+ msg += ' Found: '
+ for r in relationships:
+ msg += '%s %s %s; ' % (r['subject'], r['type'], r['object'])
+ msg += '.'
+ raise Exception, msg
+
+ def check_relationships_rest(self, pkg1_name, pkg2_name=None,
+ expected_relationships=[]):
+ rels = self.get_relationships(package1_name=pkg1_name,
+ package2_name=pkg2_name)
+ self.assert_len_relationships(rels, expected_relationships)
+ for rel in rels:
+ the_expected_rel = None
+ for expected_rel in expected_relationships:
+ if expected_rel['type'] == rel['type'] and \
+ (pkg2_name or expected_rel['object'] == pkg2_name):
+ the_expected_rel = expected_rel
+ break
+ if not the_expected_rel:
+ raise Exception('Unexpected relationship: %s %s %s' %
+ (rel['subject'], rel['type'], rel['object']))
+ for field in ('subject', 'object', 'type', 'comment'):
+ if the_expected_rel.has_key(field):
+ value = rel[field]
+ expected = the_expected_rel[field]
+ assert value == expected, (value, expected, field, rel)
+
+ def check_relationship_dict(self, rel_dict, subject_name, type, object_name, comment):
+ subject_ref = self.package_ref_from_name(subject_name)
+ object_ref = self.package_ref_from_name(object_name)
+
+ assert rel_dict['subject'] == subject_ref, (rel_dict, subject_ref)
+ assert rel_dict['object'] == object_ref, (rel_dict, object_ref)
+ assert rel_dict['type'] == type, (rel_dict, type)
+ assert rel_dict['comment'] == comment, (rel_dict, comment)
+
+class TestRelationshipsVersion1(Version1TestCase, RelationshipsTestCase): pass
+class TestRelationshipsVersion2(Version2TestCase, RelationshipsTestCase): pass
+class TestRelationshipsUnversioned(UnversionedTestCase, RelationshipsTestCase): pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_revisions.py Thu Jul 07 22:01:30 2011 +0100
@@ -0,0 +1,49 @@
+from nose.tools import assert_equal
+
+from ckan import model
+
+from ckan.tests.functional.api.base import BaseModelApiTestCase
+from ckan.tests.functional.api.base import Api1TestCase as Version1TestCase
+from ckan.tests.functional.api.base import Api2TestCase as Version2TestCase
+from ckan.tests.functional.api.base import ApiUnversionedTestCase as UnversionedTestCase
+
+class RevisionsTestCase(BaseModelApiTestCase):
+
+ commit_changesets = False
+ reuse_common_fixtures = True
+
+ def test_register_get_ok(self):
+ # Check mock register behaviour.
+ offset = self.revision_offset()
+ res = self.app.get(offset, status=200)
+ revs = model.Session.query(model.Revision).all()
+ assert revs, 'There are no revisions in the model.'
+ res_dict = self.data_from_res(res)
+ for rev in revs:
+ assert rev.id in res_dict, (rev.id, res_dict)
+
+ def test_entity_get_ok(self):
+ rev = model.repo.history().all()[-2] # 2nd revision is the creation of pkgs
+ assert rev.id
+ assert rev.timestamp.isoformat()
+ offset = self.revision_offset(rev.id)
+ response = self.app.get(offset, status=[200])
+ response_data = self.data_from_res(response)
+ assert_equal(rev.id, response_data['id'])
+ assert_equal(rev.timestamp.isoformat(), response_data['timestamp'])
+ assert 'packages' in response_data
+ packages = response_data['packages']
+ assert isinstance(packages, list)
+ #assert len(packages) != 0, "Revision packages is empty: %s" % packages
+ assert self.ref_package(self.anna) in packages, packages
+ assert self.ref_package(self.war) in packages, packages
+
+ def test_entity_get_404(self):
+ revision_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
+ offset = self.revision_offset(revision_id)
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
+
+class TestRevisionsVersion1(Version1TestCase, RevisionsTestCase): pass
+class TestRevisionsVersion2(Version2TestCase, RevisionsTestCase): pass
+class TestRevisionsUnversioned(UnversionedTestCase, RevisionsTestCase): pass
--- a/ckan/tests/functional/api/model/test_tag.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/model/test_tag.py Thu Jul 07 22:01:30 2011 +0100
@@ -23,6 +23,10 @@
res = self.app.get(offset, status=self.STATUS_200_OK)
self.assert_msg_represents_russian(msg=res.body)
+ def test_entity_get_not_found(self):
+ offset = self.tag_offset('doesntexist')
+ res = self.app.get(offset, status=404)
+ self.assert_json_response(res, 'Not found')
class TestTagsVersion1(Version1TestCase, TagsTestCase): pass
class TestTagsVersion2(Version2TestCase, TagsTestCase): pass
--- a/ckan/tests/functional/api/test_model.py Wed Jul 06 18:48:53 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-from ckan.tests.functional.api.base import *
-from ckan.lib.create_test_data import CreateTestData
-from ckan.tests import TestController as ControllerTestCase
-
-class ModelApiTestCase(BaseModelApiTestCase):
-
- def setup(self):
- self.create_common_fixtures()
- self.init_extra_environ()
- self.source = None
- self.source1 = None
- self.source2 = None
- self.source3 = None
- self.source4 = None
- self.source5 = None
- self.job = None
- self.job1 = None
- self.job2 = None
- self.job3 = None
-
- def teardown(self):
- model.repo.rebuild_db()
-
- def test_02_get_tag_register_ok(self):
- # Test Packages Register Get 200.
- offset = self.offset('/rest/tag')
- res = self.app.get(offset, status=[200])
- assert 'russian' in res, res
- assert 'tolstoy' in res, res
-
- def test_02_get_group_register_ok(self):
- offset = self.offset('/rest/group')
- res = self.app.get(offset, status=[200])
- assert self.group_ref_from_name('david') in res, res
- assert self.group_ref_from_name('roger') in res, res
-
- def test_04_get_tag(self):
- offset = self.offset('/rest/tag/tolstoy')
- res = self.app.get(offset, status=[200])
- assert 'annakarenina' in res, res
- assert not 'warandpeace' in res, res
-
- def test_04_get_group(self):
- offset = self.offset('/rest/group/roger')
- res = self.app.get(offset, status=[200])
- assert self.package_ref_from_name('annakarenina') in res, res
- assert self.group_ref_from_name('roger') in res, res
- assert not self.package_ref_from_name('warandpeace') in res, res
-
- def test_05_get_group_entity_not_found(self):
- offset = self.offset('/rest/group/22222')
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_05_get_tag_entity_not_found(self):
- offset = self.offset('/rest/tag/doesntexist')
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_06_create_group_entity_ok(self):
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=201,
- extra_environ=self.extra_environ)
- model.Session.remove()
- rev = model.repo.new_revision()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- model.setup_default_user_roles(group, [self.user])
- model.repo.commit_and_remove()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert group.title == self.testgroupvalues['title'], group
- assert group.description == self.testgroupvalues['description'], group
- assert len(group.packages) == 2, len(group.packages)
- anna = self.anna
- warandpeace = self.war
- assert anna in group.packages
- assert warandpeace in group.packages
-
- # Check group packages.
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.get(offset, status=[200])
- assert self.testgroupvalues['name'] in res, res
- assert self.package_ref_from_name(self.testgroupvalues['packages'][0]) in res, res
- ref = self.package_ref_from_name(self.testgroupvalues['packages'][0])
- assert ref in res, res
- ref = self.package_ref_from_name(self.testgroupvalues['packages'][1])
- assert ref in res, res
- model.Session.remove()
-
- # Check create group entity conflict.
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
-
- def test_06_rate_package(self):
- # Test Rating Register Post 200.
- self.clear_all_tst_ratings()
- offset = self.offset('/rest/rating')
- rating_opts = {'package':u'warandpeace',
- 'rating':5}
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 1
- assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
-
- # Get package to see rating
- offset = self.offset('/rest/package/%s' % rating_opts['package'])
- res = self.app.get(offset, status=[200])
- assert rating_opts['package'] in res, res
- assert '"ratings_average": %s.0' % rating_opts['rating'] in res, res
- assert '"ratings_count": 1' in res, res
-
- model.Session.remove()
-
- # Rerate package
- offset = self.offset('/rest/rating')
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 1
- assert pkg.ratings[0].rating == rating_opts['rating'], pkg.ratings
-
- def test_06_rate_package_out_of_range(self):
- self.clear_all_tst_ratings()
- offset = self.offset('/rest/rating')
- rating_opts = {'package':u'warandpeace',
- 'rating':0}
- postparams = '%s=1' % self.dumps(rating_opts)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(rating_opts['package'])
- assert pkg
- assert len(pkg.ratings) == 0
-
- def test_10_edit_group(self):
- # create a group with testgroupvalues
- group = model.Group.by_name(self.testgroupvalues['name'])
- if not group:
- offset = self.offset('/rest/group')
- postparams = '%s=1' % self.dumps(self.testgroupvalues)
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- model.Session.remove()
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert len(group.packages) == 2, group.packages
- user = model.User.by_name(self.user_name)
- model.setup_default_user_roles(group, [user])
-
- # edit it
- group_vals = {'name':u'somethingnew', 'title':u'newtesttitle',
- 'packages':[u'annakarenina']}
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- postparams = '%s=1' % self.dumps(group_vals)
- res = self.app.post(offset, params=postparams, status=[200],
- extra_environ=self.extra_environ)
- model.Session.remove()
- group = model.Session.query(model.Group).filter_by(name=group_vals['name']).one()
- assert group.name == group_vals['name']
- assert group.title == group_vals['title']
- assert len(group.packages) == 1, group.packages
- assert group.packages[0].name == group_vals['packages'][0]
-
- def test_10_edit_group_name_duplicate(self):
- # create a group with testgroupvalues
- if not model.Group.by_name(self.testgroupvalues['name']):
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = self.testgroupvalues['name']
- model.Session.commit()
-
- group = model.Group.by_name(self.testgroupvalues['name'])
- model.setup_default_user_roles(group, [self.user])
- rev = model.repo.new_revision()
- model.repo.commit_and_remove()
- assert model.Group.by_name(self.testgroupvalues['name'])
-
- # create a group with name 'dupname'
- dupname = u'dupname'
- if not model.Group.by_name(dupname):
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = dupname
- model.Session.commit()
- assert model.Group.by_name(dupname)
-
- # edit first group to have dupname
- group_vals = {'name':dupname}
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- postparams = '%s=1' % self.dumps(group_vals)
- res = self.app.post(offset, params=postparams, status=[409],
- extra_environ=self.extra_environ)
- model.Session.remove()
-
- def test_11_delete_group(self):
- # Test Groups Entity Delete 200.
-
- # create a group with testgroupvalues
- group = model.Group.by_name(self.testgroupvalues['name'])
- if not group:
- rev = model.repo.new_revision()
- group = model.Group()
- model.Session.add(group)
- group.name = self.testgroupvalues['name']
- model.repo.commit_and_remove()
-
- rev = model.repo.new_revision()
- group = model.Group.by_name(self.testgroupvalues['name'])
- model.setup_default_user_roles(group, [self.user])
- model.repo.commit_and_remove()
- assert group
- user = model.User.by_name(self.user_name)
- model.setup_default_user_roles(group, [user])
-
- # delete it
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.delete(offset, status=[200],
- extra_environ=self.extra_environ)
-
- group = model.Group.by_name(self.testgroupvalues['name'])
- assert group
- assert group.state == 'deleted', group.state
-
- res = self.app.get(offset, status=[403])
- res = self.app.get(offset, status=[200],
- extra_environ=self.extra_environ)
-
- model.Session.remove()
-
- def test_12_get_group_404(self):
- # Test Package Entity Get 404.
- assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_13_delete_group_404(self):
- # Test Packages Entity Delete 404.
- assert not model.Session.query(model.Group).filter_by(name=self.testgroupvalues['name']).count()
- offset = self.offset('/rest/group/%s' % self.testgroupvalues['name'])
- res = self.app.delete(offset, status=[404],
- extra_environ=self.extra_environ)
-
- def test_14_list_revisions(self):
- # Check mock register behaviour.
- offset = self.offset('/rest/revision')
- res = self.app.get(offset, status=200)
- revs = model.Session.query(model.Revision).all()
- assert revs, "There are no revisions in the model."
- res_dict = self.data_from_res(res)
- for rev in revs:
- assert rev.id in res_dict, (rev.id, res_dict)
-
- def test_14_get_revision(self):
- rev = model.repo.history().all()[-2] # 2nd revision is the creation of pkgs
- assert rev.id
- assert rev.timestamp.isoformat()
- offset = self.offset('/rest/revision/%s' % rev.id)
- response = self.app.get(offset, status=[200])
- response_data = self.data_from_res(response)
- assert rev.id == response_data['id']
- assert rev.timestamp.isoformat() == response_data['timestamp'], (rev.timestamp.isoformat(), response_data['timestamp'])
- assert 'packages' in response_data
- packages = response_data['packages']
- assert isinstance(packages, list)
- #assert len(packages) != 0, "Revision packages is empty: %s" % packages
- assert self.ref_package(self.anna) in packages, packages
- assert self.ref_package(self.war) in packages, packages
-
- def test_14_get_revision_404(self):
- revision_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
- offset = self.offset('/rest/revision/%s' % revision_id)
- res = self.app.get(offset, status=404)
- model.Session.remove()
-
- def test_16_list_licenses(self):
- from ckan.model.license import LicenseRegister
- register = LicenseRegister()
- assert len(register), "No changesets found in model."
- offset = self.offset('/rest/licenses')
- res = self.app.get(offset, status=[200])
- licenses_data = self.data_from_res(res)
- assert len(licenses_data) == len(register), (len(licenses_data), len(register))
- for license_data in licenses_data:
- id = license_data['id']
- license = register[id]
- assert license['title'] == license.title
- assert license['url'] == license.url
-
-
-class RelationshipsApiTestCase(ApiTestCase, ControllerTestCase):
-
- @classmethod
- def setup_class(self):
- CreateTestData.create()
- self.user = self.create_user(name=u'barry')
- self.testsysadmin = model.User.by_name(u'testsysadmin')
- self.extra_environ={ 'Authorization' : str(self.user.apikey) }
- self.comment = u'Comment umlaut: \xfc.'
-
- @classmethod
- def teardown_class(self):
- model.Session.remove()
- model.repo.rebuild_db()
- model.Session.remove()
-
- def teardown(self):
- for relationship in self.anna.get_relationships():
- relationship.purge()
- model.Session.commit()
- relationships = self.anna.get_relationships()
- assert relationships == [], "There are still some relationships: %s" % relationships
-
- def test_01_create_and_read_relationship(self):
- # check anna has no existing relationships
- assert not self.anna.get_relationships()
- assert self.get_relationships(package1_name='annakarenina') == [], self.get_relationships(package1_name='annakarenina')
- assert self.get_relationships(package1_name='annakarenina',
- package2_name='warandpeace') == []
- assert self.get_relationships(package1_name='annakarenina',
- type='child_of',
- package2_name='warandpeace') == 404
- assert self.get_relationships_via_package('annakarenina') == []
-
- # Create a relationship.
- self.create_annakarenina_parent_of_war_and_peace()
-
- # Check package relationship register.
- rels = self.get_relationships(package1_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # Todo: Name this?
- # Check '/api/VER/rest/package/annakarenina/relationships/warandpeace'
- rels = self.get_relationships(package1_name='annakarenina',
- package2_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # Todo: Name this?
- # check '/api/VER/rest/package/annakarenina/parent_of/warandpeace'
- rels = self.get_relationships(package1_name='annakarenina',
- type='parent_of',
- package2_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- # same checks in reverse direction
- rels = self.get_relationships(package1_name='warandpeace')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- rels = self.get_relationships(package1_name='warandpeace',
- package2_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- rels = self.get_relationships(package1_name='warandpeace',
- type='child_of',
- package2_name='annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'warandpeace', 'child_of', 'annakarenina', self.comment)
-
- # Check package entity relationships.
- rels = self.get_relationships_via_package('annakarenina')
- assert len(rels) == 1
- self.check_relationship_dict(rels[0],
- 'annakarenina', 'parent_of', 'warandpeace', self.comment)
-
- def test_03_update_relationship(self):
- # Create a relationship.
- self.create_annakarenina_parent_of_war_and_peace()
-
- # Check the relationship before update.
- self.check_relationships_rest('warandpeace', 'annakarenina',
- [{'type': 'child_of',
- 'comment': self.comment}])
-
- # Update the relationship.
- new_comment = u'New comment.'
- self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
-
- # Check the relationship after update.
- self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
-
- # Repeat update with same values, to check it remains the same?
-
- # Update the relationship.
- new_comment = u'New comment.'
- self.update_annakarenina_parent_of_war_and_peace(comment=new_comment)
-
- # Check the relationship after update.
- self.check_relationships_rest('warandpeace', 'annakarenina', [{'type': 'child_of', 'comment': new_comment}])
-
- def test_05_delete_relationship(self):
- self.create_annakarenina_parent_of_war_and_peace()
- self.update_annakarenina_parent_of_war_and_peace()
- expected = [ {'type': 'child_of', 'comment': u'New comment.'} ]
- self.check_relationships_rest('warandpeace', 'annakarenina', expected)
-
- self.delete_annakarenina_parent_of_war_and_peace()
-
- expected = []
- self.check_relationships_rest('warandpeace', 'annakarenina', expected)
-
- def create_annakarenina_parent_of_war_and_peace(self):
- # Create package relationship.
- # Todo: Redesign this in a RESTful style, so that a relationship is
- # created by posting a relationship to a relationship **register**.
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- postparams = '%s=1' % self.dumps({'comment':self.comment})
- res = self.app.post(offset, params=postparams, status=[201],
- extra_environ=self.extra_environ)
- # Check the model, directly.
- rels = self.anna.get_relationships()
- assert len(rels) == 1, rels
- assert rels[0].type == 'child_of'
- assert rels[0].subject.name == 'warandpeace'
- assert rels[0].object.name == 'annakarenina'
-
- def update_annakarenina_parent_of_war_and_peace(self, comment=u'New comment.'):
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- postparams = '%s=1' % self.dumps({'comment':comment})
- res = self.app.post(offset, params=postparams, status=[201], extra_environ=self.extra_environ)
- return res
-
- def delete_annakarenina_parent_of_war_and_peace(self):
- offset = self.offset('/rest/package/annakarenina/parent_of/warandpeace')
- res = self.app.delete(offset, status=[200], extra_environ=self.extra_environ)
- return res
-
- def get_relationships(self, package1_name=u'annakarenina', type='relationships', package2_name=None):
- package1_ref = self.package_ref_from_name(package1_name)
- if not package2_name:
- offset = self.offset('/rest/package/%s/%s' % (package1_ref, type))
- else:
- package2_ref = self.package_ref_from_name(package2_name)
- offset = self.offset('/rest/package/%s/%s/%s' % (
- str(package1_ref), type, str(package2_ref)))
- allowable_statuses = [200]
- if type:
- allowable_statuses.append(404)
- res = self.app.get(offset, status=allowable_statuses)
- if res.status == 200:
- res_dict = self.data_from_res(res) if res.body else []
- return res_dict
- else:
- return 404
-
- def get_relationships_via_package(self, package1_name):
- offset = self.offset('/rest/package/%s' % (str(package1_name)))
- res = self.app.get(offset, status=200)
- res_dict = self.data_from_res(res)
- return res_dict['relationships']
-
- def assert_len_relationships(self, relationships, expected_relationships):
- len_relationships = len(relationships)
- len_expected_relationships = len(expected_relationships)
- if len_relationships != len_expected_relationships:
- msg = 'Found %i relationships, ' % len_relationships
- msg += 'but expected %i.' % len_expected_relationships
- if len_relationships:
- msg += ' Found: '
- for r in relationships:
- msg += '%s %s %s; ' % (r['subject'], r['type'], r['object'])
- msg += '.'
- raise Exception, msg
-
- def check_relationships_rest(self, pkg1_name, pkg2_name=None,
- expected_relationships=[]):
- rels = self.get_relationships(package1_name=pkg1_name,
- package2_name=pkg2_name)
- self.assert_len_relationships(rels, expected_relationships)
- for rel in rels:
- the_expected_rel = None
- for expected_rel in expected_relationships:
- if expected_rel['type'] == rel['type'] and \
- (pkg2_name or expected_rel['object'] == pkg2_name):
- the_expected_rel = expected_rel
- break
- if not the_expected_rel:
- raise Exception('Unexpected relationship: %s %s %s' %
- (rel['subject'], rel['type'], rel['object']))
- for field in ('subject', 'object', 'type', 'comment'):
- if the_expected_rel.has_key(field):
- value = rel[field]
- expected = the_expected_rel[field]
- assert value == expected, (value, expected, field, rel)
-
- def check_relationship_dict(self, rel_dict, subject_name, type, object_name, comment):
- subject_ref = self.package_ref_from_name(subject_name)
- object_ref = self.package_ref_from_name(object_name)
-
- assert rel_dict['subject'] == subject_ref, (rel_dict, subject_ref)
- assert rel_dict['object'] == object_ref, (rel_dict, object_ref)
- assert rel_dict['type'] == type, (rel_dict, type)
- assert rel_dict['comment'] == comment, (rel_dict, comment)
-
-
-# Tests for Version 1 of the API.
-class TestModelApi1(Api1TestCase, ModelApiTestCase):
-
- def test_06_create_pkg_using_download_url(self):
- test_params = {
- 'name':u'testpkg06',
- 'download_url':u'ftp://ftp.monash.edu.au/pub/nihongo/JMdict.gz',
- }
- offset = self.package_offset()
- postparams = '%s=1' % self.dumps(test_params)
- res = self.app.post(offset, params=postparams,
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = self.get_package_by_name(test_params['name'])
- assert pkg
- assert pkg.name == test_params['name'], pkg
- assert len(pkg.resources) == 1, pkg.resources
- assert pkg.resources[0].url == test_params['download_url'], pkg.resources[0]
-
- def test_10_edit_pkg_with_download_url(self):
- test_params = {
- 'name':u'testpkg10',
- 'download_url':u'testurl',
- }
- rev = model.repo.new_revision()
- pkg = model.Package()
- model.Session.add(pkg)
- pkg.name = test_params['name']
- pkg.download_url = test_params['download_url']
- model.Session.commit()
-
- pkg = self.get_package_by_name(test_params['name'])
- model.setup_default_user_roles(pkg, [self.user])
- rev = model.repo.new_revision()
- model.repo.commit_and_remove()
- assert self.get_package_by_name(test_params['name'])
-
- # edit it
- pkg_vals = {'download_url':u'newurl'}
- offset = self.package_offset(test_params['name'])
- postparams = '%s=1' % self.dumps(pkg_vals)
- res = self.app.post(offset, params=postparams, status=[200],
- extra_environ=self.extra_environ)
- model.Session.remove()
- pkg = model.Session.query(model.Package).filter_by(name=test_params['name']).one()
- assert len(pkg.resources) == 1, pkg.resources
- assert pkg.resources[0].url == pkg_vals['download_url']
-
-
-class TestRelationshipsApi1(Api1TestCase, RelationshipsApiTestCase): pass
-
-# Tests for Version 2 of the API.
-class TestModelApi2(Api2TestCase, ModelApiTestCase): pass
-class TestRelationshipsApi2(Api2TestCase, RelationshipsApiTestCase): pass
-
-# Tests for unversioned API.
-class TestModelApiUnversioned(ApiUnversionedTestCase, ModelApiTestCase): pass
-class TestRelationshipsApiUnversioned(RelationshipsApiTestCase, ApiUnversionedTestCase): pass
-
--- a/ckan/tests/functional/api/test_package_search.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/test_package_search.py Thu Jul 07 22:01:30 2011 +0100
@@ -179,6 +179,7 @@
def test_08_uri_qjson_malformed(self):
offset = self.base_url + '?qjson="q":""' # user forgot the curly braces
res = self.app.get(offset, status=400)
+ self.assert_json_response(res, 'Bad request - Could not read parameters')
def test_08_all_fields(self):
rating = model.Rating(user_ip_address=u'123.1.2.3',
@@ -251,6 +252,7 @@
res = self.app.get(offset, status=400)
assert('integer' in res.body)
assert('offset' in res.body)
+ self.assert_json_response(res, 'integer')
def test_12_all_packages_qjson(self):
query = {'q': ''}
--- a/ckan/tests/functional/api/test_resource_search.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/test_resource_search.py Thu Jul 07 22:01:30 2011 +0100
@@ -70,6 +70,7 @@
def test_04_bad_option(self):
offset = self.base_url + '?random=option'
result = self.app.get(offset, status=400)
+ self.assert_json_response(result, 'Bad request - Bad search option')
def test_05_options(self):
offset = self.base_url + '?url=site&all_fields=1&callback=mycallback'
--- a/ckan/tests/functional/api/test_revision_search.py Wed Jul 06 18:48:53 2011 +0100
+++ b/ckan/tests/functional/api/test_revision_search.py Thu Jul 07 22:01:30 2011 +0100
@@ -11,13 +11,19 @@
def teardown_class(self):
model.repo.rebuild_db()
- def test_12_search_revision_basic(self):
+ def test_12_search_revision_bad_requests(self):
offset = self.offset('/search/revision')
# Check bad request.
- self.app.get(offset, status=400)
- self.app.get(offset+'?since_rev=2010-01-01T00:00:00', status=400)
- self.app.get(offset+'?since_revision=2010-01-01T00:00:00', status=400)
- self.app.get(offset+'?since_id=', status=400)
+ res = self.app.get(offset, status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_rev=2010-01-01T00:00:00', status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_revision=2010-01-01T00:00:00', status=400)
+ self.assert_json_response(res, 'Bad request - Missing search term')
+ res = self.app.get(offset+'?since_id=', status=400)
+ self.assert_json_response(res, 'Bad request - No revision specified')
+ res = self.app.get(offset+'?since_id=1234', status=404)
+ self.assert_json_response(res, 'Not found - There is no revision')
def test_12_search_revision_since_rev(self):
offset = self.offset('/search/revision')
@@ -54,8 +60,9 @@
assert res_list == [], res_list
# Check bad format.
params = "?since_time=2010-04-31T23:45"
- self.app.get(offset+params, status=400)
+ res = self.app.get(offset+params, status=400)
+ self.assert_json_response(res, 'Bad request - ValueError: day is out of range for month')
-class TestPackageSearchApi1(Api1TestCase, RevisionSearchApiTestCase): pass
-class TestPackageSearchApi2(Api2TestCase, RevisionSearchApiTestCase): pass
+class TestRevisionSearchApi1(Api1TestCase, RevisionSearchApiTestCase): pass
+class TestRevisionSearchApi2(Api2TestCase, RevisionSearchApiTestCase): pass
--- a/doc/api/model_formats.rst.inc Wed Jul 06 18:48:53 2011 +0100
+++ b/doc/api/model_formats.rst.inc Thu Jul 07 22:01:30 2011 +0100
@@ -26,6 +26,6 @@
* When you update an object, fields that you don't supply will remain as they were before.
- * To delete an 'extra' key-value pair, supply the key with a None value.
+ * To delete an 'extra' key-value pair, supply the key with JSON value: ``null``
* When you read a package then some additional information is supplied that cannot current be adjusted throught the CKAN API. This includes info on Package Relationship ('relationships'), Group membership ('groups'), ratings ('ratings_average' and 'ratings_count'), full URL of the package in CKAN ('ckan_url') and Package ID ('id'). This is purely a convenience for clients, and only forms part of the Package on GET.
--- a/doc/api/model_resources_table.rst.inc Wed Jul 06 18:48:53 2011 +0100
+++ b/doc/api/model_resources_table.rst.inc Thu Jul 07 22:01:30 2011 +0100
@@ -8,7 +8,7 @@
+--------------------------------+-------------------------------------------------------------------+
| Group Register | ``/rest/group`` |
+--------------------------------+-------------------------------------------------------------------+
-| Group Entity | ``/rest/group/GROUP-NAME`` |
+| Group Entity | ``/rest/group/GROUP-REF`` |
+--------------------------------+-------------------------------------------------------------------+
| Tag Register | ``/rest/tag`` |
+--------------------------------+-------------------------------------------------------------------+
@@ -16,9 +16,9 @@
+--------------------------------+-------------------------------------------------------------------+
| Rating Register | ``/rest/rating`` |
+--------------------------------+-------------------------------------------------------------------+
-| Rating Entity | ``/rest/rating/PACKAGE-REF`` |
+| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships`` |
+--------------------------------+-------------------------------------------------------------------+
-| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships`` |
+| Package Relationships Register | ``/rest/package/PACKAGE-REF/RELATIONSHIP-TYPE`` |
+--------------------------------+-------------------------------------------------------------------+
| Package Relationships Register | ``/rest/package/PACKAGE-REF/relationships/PACKAGE-REF`` |
+--------------------------------+-------------------------------------------------------------------+
Repository URL: https://bitbucket.org/okfn/ckan/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the ckan-changes
mailing list