[ckan-changes] commit/ckan: 7 new changesets

Bitbucket commits-noreply at bitbucket.org
Thu Jul 7 17:32:46 UTC 2011


7 new changesets in ckan:

http://bitbucket.org/okfn/ckan/changeset/7247f216274c/
changeset:   7247f216274c
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 13:36:35
summary:     [tests]: Completed moving of model API tests into tests/funcation/api/model. Minor corrections to API docs, including removing missing rating entity.
affected #:  9 files (20.6 KB)

--- a/ckan/tests/functional/api/base.py	Wed Jul 06 20:58:59 2011 +0100
+++ b/ckan/tests/functional/api/base.py	Thu Jul 07 12:36:35 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)
@@ -307,8 +348,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):


--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/tests/functional/api/model/test_licenses.py	Thu Jul 07 12:36:35 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 20:58:59 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 12:36:35 2011 +0100
@@ -363,7 +363,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 12:36:35 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 12:36:35 2011 +0100
@@ -0,0 +1,208 @@
+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 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 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 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)
+        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
+
+    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 12:36:35 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 20:58:59 2011 +0100
+++ b/ckan/tests/functional/api/model/test_tag.py	Thu Jul 07 12:36:35 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 20:58:59 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +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_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_05_get_tag_entity_not_found(self):
-        offset = self.offset('/rest/tag/doesntexist')
-        res = self.app.get(offset, status=404)
-        self.assert_json_response(res, 'Not found')
-
-    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)
-        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
-
-    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)
-        self.assert_json_response(res, 'Not found')
-        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/doc/api/model_resources_table.rst.inc	Wed Jul 06 20:58:59 2011 +0100
+++ b/doc/api/model_resources_table.rst.inc	Thu Jul 07 12:36:35 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/cd164bfbbce5/
changeset:   cd164bfbbce5
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 14:06:18
summary:     [tests]: Working on package delete without specific headers.
affected #:  2 files (1.6 KB)

--- a/ckan/tests/functional/api/base.py	Thu Jul 07 12:36:35 2011 +0100
+++ b/ckan/tests/functional/api/base.py	Thu Jul 07 13:06:18 2011 +0100
@@ -361,9 +361,37 @@
         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))
+        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['wsgi.input'] = StringIO(data)
         if extra_environ:


--- a/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 12:36:35 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 13:06:18 2011 +0100
@@ -303,15 +303,7 @@
     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 +313,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()


http://bitbucket.org/okfn/ckan/changeset/50df15bd148a/
changeset:   50df15bd148a
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 14:09:26
summary:     [lib/base]: #1210 Fix application/json errors associated with newer WebOb. (cset:8f6ba8ef63f3 transplanted).
affected #:  1 file (99 bytes)

--- a/ckan/lib/base.py	Thu Jul 07 13:06:18 2011 +0100
+++ b/ckan/lib/base.py	Thu Jul 07 13:09:26 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')


http://bitbucket.org/okfn/ckan/changeset/8a84eff41415/
changeset:   8a84eff41415
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 14:16:46
summary:     [tests]: Fixed ability to DELETE package without Content-Length header.
affected #:  1 file (8 bytes)

--- a/ckan/tests/functional/api/base.py	Thu Jul 07 13:09:26 2011 +0100
+++ b/ckan/tests/functional/api/base.py	Thu Jul 07 13:16:46 2011 +0100
@@ -392,7 +392,7 @@
             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)


http://bitbucket.org/okfn/ckan/changeset/557b8ac1688d/
changeset:   557b8ac1688d
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 14:31:33
summary:     [logic]: Fix listing of packages for a tag - used to give package names even for apiv2.
affected #:  3 files (122 bytes)

--- a/ckan/logic/action/get.py	Thu Jul 07 13:16:46 2011 +0100
+++ b/ckan/logic/action/get.py	Thu Jul 07 13:31:33 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/tests/functional/api/base.py	Thu Jul 07 13:16:46 2011 +0100
+++ b/ckan/tests/functional/api/base.py	Thu Jul 07 13:31:33 2011 +0100
@@ -240,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)


--- a/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 13:16:46 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 13:31:33 2011 +0100
@@ -35,6 +35,7 @@
         res = self.app.post(offset, params=postparams,
                             status=self.STATUS_201_CREATED,
                             extra_environ=self.extra_environ)
+        
         # Check the value of the Location header.
         location = res.header('Location')
         assert offset in location


http://bitbucket.org/okfn/ckan/changeset/164d4260f37e/
changeset:   164d4260f37e
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 18:50:53
summary:     [logic]: Fix returned package and group on update. Add test for PUT of a package.
affected #:  3 files (2.7 KB)

--- a/ckan/logic/action/update.py	Thu Jul 07 13:31:33 2011 +0100
+++ b/ckan/logic/action/update.py	Thu Jul 07 17:50:53 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,
@@ -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/tests/functional/api/model/test_package.py	Thu Jul 07 13:31:33 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 17:50:53 2011 +0100
@@ -1,3 +1,5 @@
+import copy
+
 from nose.tools import assert_equal
 
 from ckan.tests.functional.api.base import BaseModelApiTestCase
@@ -36,6 +38,14 @@
                             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
@@ -103,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',
@@ -201,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'],
@@ -240,8 +262,20 @@
         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)
+        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()
@@ -286,10 +320,16 @@
         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_entity_update_conflict(self):
         package1_name = self.package_fixture_data['name']


--- a/doc/api/model_formats.rst.inc	Thu Jul 07 13:31:33 2011 +0100
+++ b/doc/api/model_formats.rst.inc	Thu Jul 07 17:50:53 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.


http://bitbucket.org/okfn/ckan/changeset/bf7d2162daf2/
changeset:   bf7d2162daf2
branch:      defect-1214-api-improvements
user:        dread
date:        2011-07-07 19:32:12
summary:     [tests]: Tracking down problem deleting last package extra. Left a failing test.
affected #:  2 files (3.1 KB)

--- a/ckan/logic/action/update.py	Thu Jul 07 17:50:53 2011 +0100
+++ b/ckan/logic/action/update.py	Thu Jul 07 18:32:12 2011 +0100
@@ -176,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)
 
@@ -260,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)
 


--- a/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 17:50:53 2011 +0100
+++ b/ckan/tests/functional/api/model/test_package.py	Thu Jul 07 18:32:12 2011 +0100
@@ -260,7 +260,13 @@
             '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)
         method_func = getattr(self.app, method_str)
         res = method_func(offset, params=params, status=self.STATUS_200_OK,
@@ -331,6 +337,68 @@
     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']
         package1_data = {'name': package1_name}
@@ -341,6 +409,15 @@
         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']):

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