[ckan-changes] [okfn/ckan] 676d7a: [#2304] More work on follower_create tests

GitHub noreply at github.com
Sat Apr 28 20:16:04 UTC 2012


  Branch: refs/heads/feature-2304-follow
  Home:   https://github.com/okfn/ckan
  Commit: 676d7a332824af1e27d433ac455ac507ff0abbaf
      https://github.com/okfn/ckan/commit/676d7a332824af1e27d433ac455ac507ff0abbaf
  Author: Sean Hammond <seanhammond at lavabit.com>
  Date:   2012-04-28 (Sat, 28 Apr 2012)

  Changed paths:
    M ckan/tests/functional/api/test_follow.py

  Log Message:
  -----------
  [#2304] More work on follower_create tests

Broke long test methods into lots of smaller ones, and also added in
some test conditions, including testing responses from am_following


diff --git a/ckan/tests/functional/api/test_follow.py b/ckan/tests/functional/api/test_follow.py
index 867300f..569071a 100644
--- a/ckan/tests/functional/api/test_follow.py
+++ b/ckan/tests/functional/api/test_follow.py
@@ -13,6 +13,7 @@ def datetime_from_string(s):
     return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
 
 class TestFollow(object):
+    '''Tests for the follow API.'''
 
     @classmethod
     def setup_class(self):
@@ -51,15 +52,21 @@ def _start_following(self, follower_id, api_key, object_id, object_type,
         assert response['success'] is True
         count_before = response['result']
 
+        # Check that the user is not already following the object.
+        params = json.dumps({'id': object_id})
+        extra_environ = {'Authorization': str(api_key)}
+        response = self.app.post('/api/action/am_following',
+                params=params, extra_environ=extra_environ).json
+        assert response['success'] is True
+        assert response['result'] is False
+
         # Make the  user start following the object.
         before = datetime.datetime.now()
         params = json.dumps({
             'object_id': object_arg,
             'object_type': object_type,
             })
-        extra_environ = {
-                'Authorization': str(api_key)
-                }
+        extra_environ = {'Authorization': str(api_key)}
         response = self.app.post('/api/action/follower_create',
             params=params, extra_environ=extra_environ).json
         after = datetime.datetime.now()
@@ -73,6 +80,14 @@ def _start_following(self, follower_id, api_key, object_id, object_type,
         timestamp = datetime_from_string(follower['datetime'])
         assert (timestamp >= before and timestamp <= after), str(timestamp)
 
+        # Check that am_following now returns True.
+        params = json.dumps({'id': object_id})
+        extra_environ = {'Authorization': str(api_key)}
+        response = self.app.post('/api/action/am_following',
+                params=params, extra_environ=extra_environ).json
+        assert response['success'] is True
+        assert response['result'] is True
+
         # Check that the user appears in the object's list of followers.
         params = json.dumps({'id': object_id})
         response = self.app.post('/api/action/follower_list',
@@ -91,48 +106,35 @@ def _start_following(self, follower_id, api_key, object_id, object_type,
         assert response['success'] is True
         assert response['result'] == count_before + 1
 
-    def test_user_follow_user(self):
-
-        # Test with a bad API key.
-        params = json.dumps({
-            'object_id': self.russianfan.id,
-            'object_type': 'user',
-            })
-        extra_environ = {
-                'Authorization': 'bad api key'
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=403).json
-        assert response['success'] == False
-        assert response['error']['message'] == 'Access denied'
-
-        # Test with a bad object ID.
-        params = json.dumps({
-            'object_id': 'bad id',
-            'object_type': 'user',
-            })
-        extra_environ = {
-                'Authorization': str(self.annafan.apikey),
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=409).json
-        assert response['success'] == False
-        assert response['error']['object_id'] == ['Not found: User']
+    def test_01_user_follow_user_bad_api_key(self):
+        for apikey in ('bad api key', '', '     ', 'None', '3', '35.7', 'xxx'):
+            params = json.dumps({
+                'object_id': self.russianfan.id,
+                'object_type': 'user',
+                })
+            extra_environ = {
+                    'Authorization': apikey,
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=403).json
+            assert response['success'] == False
+            assert response['error']['message'] == 'Access denied'
 
-        # Test with a bad object type.
-        params = json.dumps({
-            'object_id': self.russianfan.id,
-            'object_type': 'foobar',
-            })
-        extra_environ = {
-                'Authorization': str(self.annafan.apikey),
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=409).json
-        assert response['success'] == False
-        assert response['error']['object_id'] == ['object_type foobar not recognised']
+    def test_01_user_follow_dataset_bad_api_key(self):
+        for apikey in ('bad api key', '', '     ', 'None', '3', '35.7', 'xxx'):
+            params = json.dumps({
+                'object_id': self.warandpeace.id,
+                'object_type': 'dataset',
+                })
+            extra_environ = {
+                    'Authorization': 'bad api key'
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=403).json
+            assert response['success'] == False
+            assert response['error']['message'] == 'Access denied'
 
-        # Test with missing API key.
+    def test_01_user_follow_user_missing_api_key(self):
         params = json.dumps({
             'object_id': self.russianfan.id,
             'object_type': 'user',
@@ -142,43 +144,20 @@ def test_user_follow_user(self):
         assert response['success'] == False
         assert response['error']['message'] == 'Access denied'
 
-        # Test with missing object_id.
+    def test_01_user_follow_dataset_missing_api_key(self):
         params = json.dumps({
-            'object_type': 'user',
-            })
-        extra_environ = {
-                'Authorization': str(self.annafan.apikey),
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=409).json
-        assert response['success'] == False
-        assert response['error']['object_id'] == ['Missing value']
-
-        # Test with missing object_type.
-        params = json.dumps({
-            'object_id': self.russianfan.id,
+            'object_id': self.warandpeace.id,
+            'object_type': 'dataset',
             })
-        extra_environ = {
-                'Authorization': str(self.annafan.apikey),
-                }
         response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=409).json
+            params=params, status=403).json
         assert response['success'] == False
-        assert response['error']['object_type'] == ['Missing value']
-
-        # Test with good arguments.
-        self._start_following(self.annafan.id, self.annafan.apikey,
-                self.russianfan.id, 'user', self.russianfan.id)
-
-        # Test with good arguments, by name.
-        self._start_following(self.annafan.id, self.annafan.apikey,
-                self.testsysadmin.id, 'user', self.testsysadmin.name)
+        assert response['error']['message'] == 'Access denied'
 
-        # Test trying to follow a user that the user is already following.
-        for object_id in (self.russianfan.id, self.russianfan.name,
-                self.testsysadmin.id, self.testsysadmin.name):
+    def test_01_user_follow_user_bad_object_id(self):
+        for object_id in ('bad id', '', '     ', None, 3, 35.7, 'xxx'):
             params = json.dumps({
-                'object_id': object_id,
+                'object_id': 'bad id',
                 'object_type': 'user',
                 })
             extra_environ = {
@@ -187,14 +166,24 @@ def test_user_follow_user(self):
             response = self.app.post('/api/action/follower_create',
                 params=params, extra_environ=extra_environ, status=409).json
             assert response['success'] == False
-            assert response['error']['message'].startswith(
-                    'Follower {follower_id} -> '.format(
-                        follower_id = self.annafan.id))
-            assert response['error']['message'].endswith(' already exists')
+            assert response['error']['object_id'] == ['Not found: User']
+
+    def test_01_user_follow_dataset_bad_object_id(self):
+        for object_id in ('bad id', '', '     ', None, 3, 35.7, 'xxx'):
+            params = json.dumps({
+                'object_id': 'bad id',
+                'object_type': 'dataset',
+                })
+            extra_environ = {
+                    'Authorization': str(self.annafan.apikey),
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=409).json
+            assert response['success'] == False
+            assert response['error']['object_id'] == ['Not found: Dataset']
 
-        # Test that a user cannot follow herself.
+    def test_01_user_follow_user_missing_object_id(self):
         params = json.dumps({
-            'object_id': self.annafan.id,
             'object_type': 'user',
             })
         extra_environ = {
@@ -203,27 +192,10 @@ def test_user_follow_user(self):
         response = self.app.post('/api/action/follower_create',
             params=params, extra_environ=extra_environ, status=409).json
         assert response['success'] == False
-        assert response['error']['object_id'] == [
-                'An object cannot follow itself']
-
-    def test_user_follow_dataset(self):
-
-        # Test with a bad API key.
-        params = json.dumps({
-            'object_id': self.warandpeace.id,
-            'object_type': 'dataset',
-            })
-        extra_environ = {
-                'Authorization': 'bad api key'
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=403).json
-        assert response['success'] == False
-        assert response['error']['message'] == 'Access denied'
+        assert response['error']['object_id'] == ['Missing value']
 
-        # Test with a bad object ID.
+    def test_01_user_follow_dataset_missing_object_id(self):
         params = json.dumps({
-            'object_id': 'bad id',
             'object_type': 'dataset',
             })
         extra_environ = {
@@ -232,34 +204,39 @@ def test_user_follow_dataset(self):
         response = self.app.post('/api/action/follower_create',
             params=params, extra_environ=extra_environ, status=409).json
         assert response['success'] == False
-        assert response['error']['object_id'] == ['Not found: Dataset']
+        assert response['error']['object_id'] == ['Missing value']
 
-        # Test with a bad object type.
-        params = json.dumps({
-            'object_id': self.warandpeace.id,
-            'object_type': 'foobar',
-            })
-        extra_environ = {
-                'Authorization': str(self.annafan.apikey),
-                }
-        response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ, status=409).json
-        assert response['success'] == False
-        assert response['error']['object_id'] == ['object_type foobar not recognised']
+    def test_01_user_follow_user_bad_object_type(self):
+        for object_type in ('foobar', 'dataset', '', '     ', None, 3, 35.7):
+            params = json.dumps({
+                'object_id': self.russianfan.id,
+                'object_type': 'foobar',
+                })
+            extra_environ = {
+                    'Authorization': str(self.annafan.apikey),
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=409).json
+            assert response['success'] == False
+            assert response['error']['object_id'] == ['object_type foobar not recognised']
 
-        # Test with missing API key.
-        params = json.dumps({
-            'object_id': self.warandpeace.id,
-            'object_type': 'dataset',
-            })
-        response = self.app.post('/api/action/follower_create',
-            params=params, status=403).json
-        assert response['success'] == False
-        assert response['error']['message'] == 'Access denied'
+    def test_01_user_follow_dataset_bad_object_type(self):
+        for object_type in ('foobar', 'user', '', '     ', None, 3, 35.7):
+            params = json.dumps({
+                'object_id': self.warandpeace.id,
+                'object_type': 'foobar',
+                })
+            extra_environ = {
+                    'Authorization': str(self.annafan.apikey),
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=409).json
+            assert response['success'] == False
+            assert response['error']['object_id'] == ['object_type foobar not recognised']
 
-        # Test with missing object_id.
+    def test_01_user_follow_user_missing_object_type(self):
         params = json.dumps({
-            'object_type': 'dataset',
+            'object_id': self.russianfan.id,
             })
         extra_environ = {
                 'Authorization': str(self.annafan.apikey),
@@ -267,9 +244,9 @@ def test_user_follow_dataset(self):
         response = self.app.post('/api/action/follower_create',
             params=params, extra_environ=extra_environ, status=409).json
         assert response['success'] == False
-        assert response['error']['object_id'] == ['Missing value']
+        assert response['error']['object_type'] == ['Missing value']
 
-        # Test with missing object_type.
+    def test_01_user_follow_dataset_missing_object_type(self):
         params = json.dumps({
             'object_id': self.warandpeace.id,
             })
@@ -281,15 +258,41 @@ def test_user_follow_dataset(self):
         assert response['success'] == False
         assert response['error']['object_type'] == ['Missing value']
 
-        # Test with good arguments.
+    def test_02_user_follow_user_by_id(self):
+        self._start_following(self.annafan.id, self.annafan.apikey,
+                self.russianfan.id, 'user', self.russianfan.id)
+
+    def test_02_user_follow_dataset_by_id(self):
         self._start_following(self.annafan.id, self.annafan.apikey,
                 self.warandpeace.id, 'dataset', self.warandpeace.id)
 
-        # Test with good arguments, by name.
+    def test_02_user_follow_user_by_name(self):
+        self._start_following(self.annafan.id, self.annafan.apikey,
+                self.testsysadmin.id, 'user', self.testsysadmin.name)
+
+    def test_02_user_follow_dataset_by_name(self):
         self._start_following(self.annafan.id, self.annafan.apikey,
                 self.annakarenina.id, 'dataset', self.annakarenina.name)
 
-        # Test trying to follow a dataset that the user is already following.
+    def test_03_user_follow_user_already_following(self):
+        for object_id in (self.russianfan.id, self.russianfan.name,
+                self.testsysadmin.id, self.testsysadmin.name):
+            params = json.dumps({
+                'object_id': object_id,
+                'object_type': 'user',
+                })
+            extra_environ = {
+                    'Authorization': str(self.annafan.apikey),
+                    }
+            response = self.app.post('/api/action/follower_create',
+                params=params, extra_environ=extra_environ, status=409).json
+            assert response['success'] == False
+            assert response['error']['message'].startswith(
+                    'Follower {follower_id} -> '.format(
+                        follower_id = self.annafan.id))
+            assert response['error']['message'].endswith(' already exists')
+
+    def test_03_user_follow_dataset_already_following(self):
         for object_id in (self.warandpeace.id, self.warandpeace.name,
                 self.annakarenina.id, self.annakarenina.name):
             params = json.dumps({
@@ -307,4 +310,18 @@ def test_user_follow_dataset(self):
                         follower_id = self.annafan.id))
             assert response['error']['message'].endswith(' already exists')
 
+    def test_03_user_cannot_follow_herself(self):
+        params = json.dumps({
+            'object_id': self.annafan.id,
+            'object_type': 'user',
+            })
+        extra_environ = {
+                'Authorization': str(self.annafan.apikey),
+                }
+        response = self.app.post('/api/action/follower_create',
+            params=params, extra_environ=extra_environ, status=409).json
+        assert response['success'] == False
+        assert response['error']['object_id'] == [
+                'An object cannot follow itself']
+
 # Test follow with datetime, should be ignored.


================================================================
  Commit: 1848f0ba1da79b0fda33d0b2a5f9a2df54727cc1
      https://github.com/okfn/ckan/commit/1848f0ba1da79b0fda33d0b2a5f9a2df54727cc1
  Author: Sean Hammond <seanhammond at lavabit.com>
  Date:   2012-04-28 (Sat, 28 Apr 2012)

  Changed paths:
    M ckan/tests/functional/api/test_follow.py

  Log Message:
  -----------
  [#2304] Add one more test for follower_create


diff --git a/ckan/tests/functional/api/test_follow.py b/ckan/tests/functional/api/test_follow.py
index 569071a..293e771 100644
--- a/ckan/tests/functional/api/test_follow.py
+++ b/ckan/tests/functional/api/test_follow.py
@@ -22,7 +22,7 @@ def setup_class(self):
         self.annafan = ckan.model.User.get('annafan')
         self.russianfan = ckan.model.User.get('russianfan')
         self.tester = ckan.model.User.get('tester')
-        self.tester = ckan.model.User.get('joeadmin')
+        self.joeadmin = ckan.model.User.get('joeadmin')
         self.warandpeace = ckan.model.Package.get('warandpeace')
         self.annakarenina = ckan.model.Package.get('annakarenina')
         self.app = paste.fixture.TestApp(pylons.test.pylonsapp)
@@ -32,7 +32,7 @@ def teardown_class(self):
         ckan.model.repo.rebuild_db()
 
     def _start_following(self, follower_id, api_key, object_id, object_type,
-            object_arg):
+            object_arg, datetime_param=None):
         '''Test a user starting to follow an object via the API.
 
         :param follower_id: id of the user that will be following something.
@@ -42,6 +42,8 @@ def _start_following(self, follower_id, api_key, object_id, object_type,
             user, e.g. 'user' or 'dataset'.
         :param object_arg: the argument to pass to follower_create as the id of
             the object that will be followed, could be the object's id or name.
+        :param datetime_param Will be passed as 'datetime' arg to
+            follower_create
 
         '''
 
@@ -62,13 +64,15 @@ def _start_following(self, follower_id, api_key, object_id, object_type,
 
         # Make the  user start following the object.
         before = datetime.datetime.now()
-        params = json.dumps({
+        params = {
             'object_id': object_arg,
             'object_type': object_type,
-            })
+            }
+        if datetime_param:
+            params['datetime'] = datetime_param
         extra_environ = {'Authorization': str(api_key)}
         response = self.app.post('/api/action/follower_create',
-            params=params, extra_environ=extra_environ).json
+            params=json.dumps(params), extra_environ=extra_environ).json
         after = datetime.datetime.now()
         assert response['success'] is True
         assert response['result']
@@ -274,6 +278,12 @@ def test_02_user_follow_dataset_by_name(self):
         self._start_following(self.annafan.id, self.annafan.apikey,
                 self.annakarenina.id, 'dataset', self.annakarenina.name)
 
+    def test_02_user_follow_user_with_datetime(self):
+        'Test that a datetime passed to follower_create is ignored.'
+        self._start_following(self.annafan.id, self.annafan.apikey,
+                self.joeadmin.id, 'user', self.joeadmin.name,
+                datetime_param = str(datetime.datetime.min))
+
     def test_03_user_follow_user_already_following(self):
         for object_id in (self.russianfan.id, self.russianfan.name,
                 self.testsysadmin.id, self.testsysadmin.name):
@@ -323,5 +333,3 @@ def test_03_user_cannot_follow_herself(self):
         assert response['success'] == False
         assert response['error']['object_id'] == [
                 'An object cannot follow itself']
-
-# Test follow with datetime, should be ignored.


================================================================
  Commit: 22347eb1f5d177e317f8316caf0bbe16a61d6977
      https://github.com/okfn/ckan/commit/22347eb1f5d177e317f8316caf0bbe16a61d6977
  Author: Sean Hammond <seanhammond at lavabit.com>
  Date:   2012-04-28 (Sat, 28 Apr 2012)

  Changed paths:
    M ckan/logic/action/delete.py
    M ckan/tests/functional/api/test_follow.py

  Log Message:
  -----------
  [#2304] Add tests for follower_delete api


diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py
index 41bb593..d3ad5b8 100644
--- a/ckan/logic/action/delete.py
+++ b/ckan/logic/action/delete.py
@@ -217,17 +217,17 @@ def follower_delete(context, data_dict):
     follower_id = userobj.id
 
     object_id = data_dict.get('id')
-    if not object_id:
+    if object_id is None:
         raise ValidationError({'id': _('id not in data')})
 
+    check_access('follower_delete', context,
+            {'follower_id': follower_id, 'object_id':object_id})
+
     follower_obj = model.Follower.get(follower_id, object_id)
     if follower_obj is None:
         raise NotFound(
                 _('Could not find follower {follower} -> {object}').format(
                     follower=follower_id, object=object_id))
 
-    check_access('follower_delete', context,
-            {'follower_id': follower_id, 'object_id':object_id})
-
     follower_obj.delete()
     model.repo.commit()
diff --git a/ckan/tests/functional/api/test_follow.py b/ckan/tests/functional/api/test_follow.py
index 293e771..b668c2e 100644
--- a/ckan/tests/functional/api/test_follow.py
+++ b/ckan/tests/functional/api/test_follow.py
@@ -12,8 +12,87 @@ def datetime_from_string(s):
     '''
     return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
 
+def start_following(app, follower_id, api_key, object_id, object_type,
+        object_arg, datetime_param=None):
+    '''Test a user starting to follow an object via the API.
+
+    :param follower_id: id of the user that will be following something.
+    :param api_key: API key of the user that will be following something.
+    :param object_id: id of the object that will be followed by the user.
+    :param object_type: type of the object that will be followed by the
+        user, e.g. 'user' or 'dataset'.
+    :param object_arg: the argument to pass to follower_create as the id of
+        the object that will be followed, could be the object's id or name.
+    :param datetime_param Will be passed as 'datetime' arg to
+        follower_create
+
+    '''
+
+    # Record the object's number of followers before.
+    params = json.dumps({'id': object_id})
+    response = app.post('/api/action/follower_count',
+            params=params).json
+    assert response['success'] is True
+    count_before = response['result']
+
+    # Check that the user is not already following the object.
+    params = json.dumps({'id': object_id})
+    extra_environ = {'Authorization': str(api_key)}
+    response = app.post('/api/action/am_following',
+            params=params, extra_environ=extra_environ).json
+    assert response['success'] is True
+    assert response['result'] is False
+
+    # Make the  user start following the object.
+    before = datetime.datetime.now()
+    params = {
+        'object_id': object_arg,
+        'object_type': object_type,
+        }
+    if datetime_param:
+        params['datetime'] = datetime_param
+    extra_environ = {'Authorization': str(api_key)}
+    response = app.post('/api/action/follower_create',
+        params=json.dumps(params), extra_environ=extra_environ).json
+    after = datetime.datetime.now()
+    assert response['success'] is True
+    assert response['result']
+    follower = response['result']
+    assert follower['follower_id'] == follower_id
+    assert follower['follower_type'] == 'user'
+    assert follower['object_id'] == object_id
+    assert follower['object_type'] == object_type
+    timestamp = datetime_from_string(follower['datetime'])
+    assert (timestamp >= before and timestamp <= after), str(timestamp)
+
+    # Check that am_following now returns True.
+    params = json.dumps({'id': object_id})
+    extra_environ = {'Authorization': str(api_key)}
+    response = app.post('/api/action/am_following',
+            params=params, extra_environ=extra_environ).json
+    assert response['success'] is True
+    assert response['result'] is True
+
+    # Check that the user appears in the object's list of followers.
+    params = json.dumps({'id': object_id})
+    response = app.post('/api/action/follower_list',
+            params=params).json
+    assert response['success'] is True
+    assert response['result']
+    followers = response['result']
+    assert len(followers) == count_before + 1
+    assert len([follower for follower in followers if follower['id'] ==
+            follower_id]) == 1
+
+    # Check that the object's follower count has increased by 1.
+    params = json.dumps({'id': object_id})
+    response = app.post('/api/action/follower_count',
+            params=params).json
+    assert response['success'] is True
+    assert response['result'] == count_before + 1
+
 class TestFollow(object):
-    '''Tests for the follow API.'''
+    '''Tests for the follower API.'''
 
     @classmethod
     def setup_class(self):
@@ -31,85 +110,6 @@ def setup_class(self):
     def teardown_class(self):
         ckan.model.repo.rebuild_db()
 
-    def _start_following(self, follower_id, api_key, object_id, object_type,
-            object_arg, datetime_param=None):
-        '''Test a user starting to follow an object via the API.
-
-        :param follower_id: id of the user that will be following something.
-        :param api_key: API key of the user that will be following something.
-        :param object_id: id of the object that will be followed by the user.
-        :param object_type: type of the object that will be followed by the
-            user, e.g. 'user' or 'dataset'.
-        :param object_arg: the argument to pass to follower_create as the id of
-            the object that will be followed, could be the object's id or name.
-        :param datetime_param Will be passed as 'datetime' arg to
-            follower_create
-
-        '''
-
-        # Record the object's number of followers before.
-        params = json.dumps({'id': object_id})
-        response = self.app.post('/api/action/follower_count',
-                params=params).json
-        assert response['success'] is True
-        count_before = response['result']
-
-        # Check that the user is not already following the object.
-        params = json.dumps({'id': object_id})
-        extra_environ = {'Authorization': str(api_key)}
-        response = self.app.post('/api/action/am_following',
-                params=params, extra_environ=extra_environ).json
-        assert response['success'] is True
-        assert response['result'] is False
-
-        # Make the  user start following the object.
-        before = datetime.datetime.now()
-        params = {
-            'object_id': object_arg,
-            'object_type': object_type,
-            }
-        if datetime_param:
-            params['datetime'] = datetime_param
-        extra_environ = {'Authorization': str(api_key)}
-        response = self.app.post('/api/action/follower_create',
-            params=json.dumps(params), extra_environ=extra_environ).json
-        after = datetime.datetime.now()
-        assert response['success'] is True
-        assert response['result']
-        follower = response['result']
-        assert follower['follower_id'] == follower_id
-        assert follower['follower_type'] == 'user'
-        assert follower['object_id'] == object_id
-        assert follower['object_type'] == object_type
-        timestamp = datetime_from_string(follower['datetime'])
-        assert (timestamp >= before and timestamp <= after), str(timestamp)
-
-        # Check that am_following now returns True.
-        params = json.dumps({'id': object_id})
-        extra_environ = {'Authorization': str(api_key)}
-        response = self.app.post('/api/action/am_following',
-                params=params, extra_environ=extra_environ).json
-        assert response['success'] is True
-        assert response['result'] is True
-
-        # Check that the user appears in the object's list of followers.
-        params = json.dumps({'id': object_id})
-        response = self.app.post('/api/action/follower_list',
-                params=params).json
-        assert response['success'] is True
-        assert response['result']
-        followers = response['result']
-        assert len(followers) == 1
-        follower = followers[0]
-        assert follower['id'] == follower_id
-
-        # Check that the object's follower count has increased by 1.
-        params = json.dumps({'id': object_id})
-        response = self.app.post('/api/action/follower_count',
-                params=params).json
-        assert response['success'] is True
-        assert response['result'] == count_before + 1
-
     def test_01_user_follow_user_bad_api_key(self):
         for apikey in ('bad api key', '', '     ', 'None', '3', '35.7', 'xxx'):
             params = json.dumps({
@@ -263,24 +263,24 @@ def test_01_user_follow_dataset_missing_object_type(self):
         assert response['error']['object_type'] == ['Missing value']
 
     def test_02_user_follow_user_by_id(self):
-        self._start_following(self.annafan.id, self.annafan.apikey,
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.russianfan.id, 'user', self.russianfan.id)
 
     def test_02_user_follow_dataset_by_id(self):
-        self._start_following(self.annafan.id, self.annafan.apikey,
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.warandpeace.id, 'dataset', self.warandpeace.id)
 
     def test_02_user_follow_user_by_name(self):
-        self._start_following(self.annafan.id, self.annafan.apikey,
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.testsysadmin.id, 'user', self.testsysadmin.name)
 
     def test_02_user_follow_dataset_by_name(self):
-        self._start_following(self.annafan.id, self.annafan.apikey,
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.annakarenina.id, 'dataset', self.annakarenina.name)
 
     def test_02_user_follow_user_with_datetime(self):
         'Test that a datetime passed to follower_create is ignored.'
-        self._start_following(self.annafan.id, self.annafan.apikey,
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.joeadmin.id, 'user', self.joeadmin.name,
                 datetime_param = str(datetime.datetime.min))
 
@@ -333,3 +333,166 @@ def test_03_user_cannot_follow_herself(self):
         assert response['success'] == False
         assert response['error']['object_id'] == [
                 'An object cannot follow itself']
+
+class TestFollowerDelete(object):
+    '''Tests for the follower_delete API.'''
+
+    @classmethod
+    def setup_class(self):
+        ckan.tests.CreateTestData.create()
+        self.testsysadmin = ckan.model.User.get('testsysadmin')
+        self.annafan = ckan.model.User.get('annafan')
+        self.russianfan = ckan.model.User.get('russianfan')
+        self.tester = ckan.model.User.get('tester')
+        self.joeadmin = ckan.model.User.get('joeadmin')
+        self.warandpeace = ckan.model.Package.get('warandpeace')
+        self.annakarenina = ckan.model.Package.get('annakarenina')
+        self.app = paste.fixture.TestApp(pylons.test.pylonsapp)
+        start_following(self.app, self.testsysadmin.id, self.testsysadmin.apikey,
+                self.joeadmin.id, 'user', self.joeadmin.id)
+        start_following(self.app, self.tester.id, self.tester.apikey,
+                self.joeadmin.id, 'user', self.joeadmin.id)
+        start_following(self.app, self.russianfan.id, self.russianfan.apikey,
+                self.joeadmin.id, 'user', self.joeadmin.id)
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
+                self.joeadmin.id, 'user', self.joeadmin.id)
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
+                self.tester.id, 'user', self.tester.id)
+
+    @classmethod
+    def teardown_class(self):
+        ckan.model.repo.rebuild_db()
+
+    def test_01_follower_delete_not_exists(self):
+        '''Test the error response when a user tries to unfollow something
+        that she is not following.
+
+        '''
+        params = json.dumps({
+            'id': self.russianfan.id,
+            })
+        extra_environ = {
+                'Authorization': str(self.annafan.apikey),
+                }
+        response = self.app.post('/api/action/follower_delete',
+            params=params, extra_environ=extra_environ, status=404).json
+        assert response['success'] == False
+        assert response['error']['message'].startswith(
+                'Not found: Could not find follower ')
+
+    def test_01_follower_delete_bad_api_key(self):
+        '''Test the error response when a user tries to unfollow something
+        but provides a bad API key.
+
+        '''
+        for apikey in ('bad api key', '', '     ', 'None', '3', '35.7', 'xxx'):
+            params = json.dumps({
+                'id': self.joeadmin.id,
+                })
+            extra_environ = {
+                    'Authorization': apikey,
+                    }
+            response = self.app.post('/api/action/follower_delete',
+                params=params, extra_environ=extra_environ, status=403).json
+            assert response['success'] == False
+            assert response['error']['message'] == 'Access denied'
+
+    def test_01_follower_delete_missing_api_key(self):
+        params = json.dumps({
+            'id': self.joeadmin.id,
+            })
+        response = self.app.post('/api/action/follower_delete',
+            params=params, status=403).json
+        assert response['success'] == False
+        assert response['error']['message'] == 'Access denied'
+
+    def test_01_follower_delete_bad_object_id(self):
+        '''Test error response when calling follower_delete with a bad object
+        id.
+
+        '''
+        for object_id in ('bad id', '     ', 3, 35.7, 'xxx', ''):
+            params = json.dumps({
+                'id': object_id,
+                })
+            extra_environ = {
+                    'Authorization': str(self.annafan.apikey),
+                    }
+            response = self.app.post('/api/action/follower_delete',
+                params=params, extra_environ=extra_environ, status=404).json
+            assert response['success'] == False
+            assert response['error']['message'].startswith(
+                'Not found: Could not find follower ')
+
+    def test_01_follower_delete_missing_object_id(self):
+        params = json.dumps({})
+        extra_environ = {'Authorization': str(self.annafan.apikey),}
+        response = self.app.post('/api/action/follower_delete',
+            params=params, extra_environ=extra_environ, status=409).json
+        assert response['success'] == False
+        assert response['error']['id'] == 'id not in data'
+
+    def _stop_following(self, follower_id, api_key, object_id, object_arg):
+        '''Test a user unfollowing an object via the API.
+
+        :param follower_id: id of the user.
+        :param api_key: API key of the user.
+        :param object_id: id of the object to unfollow.
+        :param object_arg: the argument to pass to follower_delete as the id of
+            the object to unfollow, could be the object's id or name.
+
+        '''
+
+        # Record the object's number of followers before.
+        params = json.dumps({'id': object_id})
+        response = self.app.post('/api/action/follower_count',
+                params=params).json
+        assert response['success'] is True
+        count_before = response['result']
+
+        # Check that the user is following the object.
+        params = json.dumps({'id': object_id})
+        extra_environ = {'Authorization': str(api_key)}
+        response = self.app.post('/api/action/am_following',
+                params=params, extra_environ=extra_environ).json
+        assert response['success'] is True
+        assert response['result'] is True
+
+        # Make the user unfollow the object.
+        params = {
+            'id': object_arg,
+            }
+        extra_environ = {'Authorization': str(api_key)}
+        response = self.app.post('/api/action/follower_delete',
+            params=json.dumps(params), extra_environ=extra_environ).json
+        after = datetime.datetime.now()
+        assert response['success'] is True
+
+        # Check that am_following now returns False.
+        params = json.dumps({'id': object_id})
+        extra_environ = {'Authorization': str(api_key)}
+        response = self.app.post('/api/action/am_following',
+                params=params, extra_environ=extra_environ).json
+        assert response['success'] is True
+        assert response['result'] is False
+
+        # Check that the user doesn't appear in the object's list of followers.
+        params = json.dumps({'id': object_id})
+        response = self.app.post('/api/action/follower_list',
+                params=params).json
+        assert response['success'] is True
+        assert response['result']
+        followers = response['result']
+        assert len([follower for follower in followers if follower['id'] ==
+                follower_id]) == 0
+
+        # Check that the object's follower count has decreased by 1.
+        params = json.dumps({'id': object_id})
+        response = self.app.post('/api/action/follower_count',
+                params=params).json
+        assert response['success'] is True
+        assert response['result'] == count_before - 1
+
+    def test_02_follower_delete_by_id(self):
+        self._stop_following(self.annafan.id, self.annafan.apikey,
+                self.joeadmin.id, self.joeadmin.id)


================================================================
  Commit: e273bea8f71b0898d75b1b48a6f0e894dd00728b
      https://github.com/okfn/ckan/commit/e273bea8f71b0898d75b1b48a6f0e894dd00728b
  Author: Sean Hammond <seanhammond at lavabit.com>
  Date:   2012-04-28 (Sat, 28 Apr 2012)

  Changed paths:
    M ckan/logic/action/get.py
    M ckan/tests/functional/api/test_follow.py

  Log Message:
  -----------
  [#2304] Add a few more follow api tests


diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index c429f2e..b45c973 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -1383,8 +1383,8 @@ def follower_count(context, data_dict):
     '''Return the number of followers of an object.'''
     model = context['model']
     object_id = data_dict.get('id')
-    if not object_id:
-        raise ValidationError({'id': 'id not in data'})
+    if object_id is None:
+        raise ValidationError({'id': _('id not in data')})
     return model.Follower.follower_count(object_id)
 
 def follower_list(context, data_dict):
@@ -1393,8 +1393,8 @@ def follower_list(context, data_dict):
     # Get the list of Follower objects.
     model = context['model']
     object_id = data_dict.get('id')
-    if not object_id:
-        raise ValidationError({'id': 'id not in data'})
+    if object_id is None:
+        raise ValidationError({'id': _('id not in data')})
     followers = model.Follower.follower_list(object_id)
 
     # Convert the list of Follower objects to a list of User objects.
diff --git a/ckan/tests/functional/api/test_follow.py b/ckan/tests/functional/api/test_follow.py
index b668c2e..0ec1c9e 100644
--- a/ckan/tests/functional/api/test_follow.py
+++ b/ckan/tests/functional/api/test_follow.py
@@ -334,6 +334,52 @@ def test_03_user_cannot_follow_herself(self):
         assert response['error']['object_id'] == [
                 'An object cannot follow itself']
 
+    def test_04_follower_count_bad_id(self):
+        # follower_count always succeeds, but just returns 0 for bad IDs.
+        for object_id in ('bad id', '     ', 3, 35.7, 'xxx', ''):
+            params = json.dumps({'id': object_id})
+            response = self.app.post('/api/action/follower_count',
+                    params=params).json
+            assert response['success'] is True
+            assert response['result'] == 0
+
+    def test_04_follower_count_missing_id(self):
+        params = json.dumps({})
+        response = self.app.post('/api/action/follower_count',
+                params=params, status=409).json
+        assert response['success'] is False
+        assert response['error']['id'] == 'id not in data'
+
+    def test_04_follower_count_no_followers(self):
+        params = json.dumps({'id': self.annafan.id})
+        response = self.app.post('/api/action/follower_count',
+                params=params).json
+        assert response['success'] is True
+        assert response['result'] == 0
+
+    def test_04_follower_list_bad_id(self):
+        # follower_list always succeeds, but just returns [] for bad IDs.
+        for object_id in ('bad id', '     ', 3, 35.7, 'xxx', ''):
+            params = json.dumps({'id': object_id})
+            response = self.app.post('/api/action/follower_list',
+                    params=params).json
+            assert response['success'] is True
+            assert response['result'] == []
+
+    def test_04_follower_list_missing_id(self):
+        params = json.dumps({})
+        response = self.app.post('/api/action/follower_list',
+                params=params, status=409).json
+        assert response['success'] is False
+        assert response['error']['id'] == 'id not in data'
+
+    def test_04_follower_list_no_followers(self):
+        params = json.dumps({'id': self.annafan.id})
+        response = self.app.post('/api/action/follower_list',
+                params=params).json
+        assert response['success'] is True
+        assert response['result'] == []
+
 class TestFollowerDelete(object):
     '''Tests for the follower_delete API.'''
 
@@ -358,6 +404,14 @@ def setup_class(self):
                 self.joeadmin.id, 'user', self.joeadmin.id)
         start_following(self.app, self.annafan.id, self.annafan.apikey,
                 self.tester.id, 'user', self.tester.id)
+        start_following(self.app, self.testsysadmin.id, self.testsysadmin.apikey,
+                self.warandpeace.id, 'dataset', self.warandpeace.id)
+        start_following(self.app, self.tester.id, self.tester.apikey,
+                self.warandpeace.id, 'dataset', self.warandpeace.id)
+        start_following(self.app, self.russianfan.id, self.russianfan.apikey,
+                self.warandpeace.id, 'dataset', self.warandpeace.id)
+        start_following(self.app, self.annafan.id, self.annafan.apikey,
+                self.warandpeace.id, 'dataset', self.warandpeace.id)
 
     @classmethod
     def teardown_class(self):
@@ -496,3 +550,5 @@ def _stop_following(self, follower_id, api_key, object_id, object_arg):
     def test_02_follower_delete_by_id(self):
         self._stop_following(self.annafan.id, self.annafan.apikey,
                 self.joeadmin.id, self.joeadmin.id)
+        self._stop_following(self.annafan.id, self.annafan.apikey,
+                self.warandpeace.id, self.warandpeace.id)


================================================================
Compare: https://github.com/okfn/ckan/compare/2c13b2b...e273bea


More information about the ckan-changes mailing list