Browse Source

Added tests for Lodel.user module

Testing authentication_method and identification_method decorator classes + UserIdentity and UserContext classes
Yann Weber 9 years ago
parent
commit
4c6f189c1f
4 changed files with 185 additions and 6 deletions
  1. 1
    1
      Lodel/hooks.py
  2. 155
    0
      Lodel/test/tests_user.py
  3. 27
    3
      Lodel/user.py
  4. 2
    2
      leapi/lecrud.py

+ 1
- 1
Lodel/hooks.py View File

@@ -83,5 +83,5 @@ class LodelHook(object):
83 83
     # @warning REALLY NOT a good idea !
84 84
     # @note implemented for testing purpose
85 85
     @classmethod
86
-    def __reset_hooks__(cls):
86
+    def __reset__(cls):
87 87
         cls._hooks = dict()

+ 155
- 0
Lodel/test/tests_user.py View File

@@ -0,0 +1,155 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+import unittest
4
+import unittest.mock
5
+from unittest.mock import Mock
6
+
7
+from Lodel.user import  authentication_method, identification_method, UserIdentity, UserContext
8
+
9
+
10
+class AuthIdMethodTestCase(unittest.TestCase):
11
+    
12
+    def test_authentication_method_registration(self):
13
+        before = set(authentication_method.list_methods())
14
+
15
+        def test_method(self):
16
+            pass
17
+        authentication_method(test_method) # faking test_method decoration
18
+
19
+        after = set(authentication_method.list_methods())
20
+        self.assertEqual(after - before, set([test_method]))
21
+
22
+    def test_identification_method_registration(self):
23
+        before = set(identification_method.list_methods())
24
+
25
+        def test_method(self):
26
+            pass
27
+        identification_method(test_method) # faking test_method decoration
28
+        
29
+        after = set(identification_method.list_methods())
30
+        self.assertEqual(after - before, set([test_method]))
31
+
32
+    def test_authentication_method_calls(self):
33
+        mock_list = list()
34
+        for i in range(5):
35
+            auth_mock = Mock(return_value = False)
36
+            mock_list.append(auth_mock)
37
+            authentication_method(auth_mock)
38
+        ret = authentication_method.authenticate('login', 'password')
39
+        self.assertFalse(ret)
40
+        for mock in mock_list:
41
+            mock.assert_called_once_with('login', 'password')
42
+        # Adding a mock that will fake a successfull auth
43
+        user_id = UserIdentity(42, 'superlogin', authenticated = True)
44
+        authentication_method( Mock(return_value = user_id) )
45
+        ret = authentication_method.authenticate('login', 'password')
46
+        self.assertEqual(ret, user_id)
47
+
48
+    def test_identificatio_method_calls(self):
49
+        mock_list = list()
50
+        for i in range(5):
51
+            id_mock = Mock(return_value = False)
52
+            mock_list.append(id_mock)
53
+            identification_method(id_mock)
54
+        client_infos = {'ip':'127.0.0.1', 'user-agent': 'bla bla'}
55
+        ret = identification_method.identify(client_infos)
56
+        self.assertFalse(ret)
57
+        for mock in mock_list:
58
+            mock.assert_called_once_with(client_infos)
59
+        # Adding a mock that will fake a successfull identification
60
+        user_id = UserIdentity(42, 'login', identified = True)
61
+        identification_method( Mock(return_value = user_id) )
62
+        ret = identification_method.identify(client_infos)
63
+        self.assertEqual(ret, user_id)
64
+
65
+class UserIdentityTestCase(unittest.TestCase):
66
+    
67
+    def test_init(self):
68
+        """ Testing UserIdentity constructor """
69
+        uid = UserIdentity(42, 'login', 'anonymous login')
70
+        self.assertEqual(uid.user_id, 42)
71
+        self.assertEqual(uid.username, 'login')
72
+        self.assertEqual(uid.fullname, 'anonymous login')
73
+        self.assertFalse(uid.is_authenticated)
74
+        self.assertFalse(uid.is_identified)
75
+        self.assertEqual(str(uid), uid.fullname)
76
+
77
+    def test_identified(self):
78
+        """ Testing identified flag relation with authenticated flag """
79
+        uid = UserIdentity(42, 'login', identified = True)
80
+        self.assertTrue(uid.is_identified)
81
+        self.assertFalse(uid.is_authenticated)
82
+
83
+    def test_authentified(self):
84
+        """ Testing identified flag relation with authenticated flag """
85
+        uid = UserIdentity(42, 'login', authenticated = True)
86
+        self.assertTrue(uid.is_identified)
87
+        self.assertTrue(uid.is_authenticated)
88
+
89
+    def test_anonymous(self):
90
+        """ Testing the anonymous UserIdentity """
91
+        anon = UserIdentity.anonymous()
92
+        self.assertEqual(anon, UserIdentity.anonymous())
93
+        self.assertFalse(anon.is_authenticated)
94
+        self.assertFalse(anon.is_identified)
95
+
96
+class UserContextTestCase(unittest.TestCase):
97
+    
98
+    def test_static(self):
99
+        """ Testing that the class is static """
100
+        with self.assertRaises(NotImplementedError):
101
+            UserContext()
102
+
103
+    def test_not_init(self):
104
+        """ Testing method call with a non initialised class """
105
+        UserContext.__reset__()
106
+        with self.assertRaises(AssertionError):
107
+            UserContext.identity()
108
+        with self.assertRaises(AssertionError):
109
+            UserContext.authenticate('login', 'foobar')
110
+
111
+    def test_anon_init(self):
112
+        """ Testing class initialisation """
113
+        identification_method.__reset__()
114
+        authentication_method.__reset__()
115
+        UserContext.__reset__()
116
+        auth_id = UserIdentity(43, 'loggedlogin', authenticated = True)
117
+        # Add a fake authentication method
118
+        auth_mock = Mock(return_value = auth_id)
119
+        authentication_method(auth_mock)
120
+        # Are we anonymous ?
121
+        UserContext.init('localhost')
122
+        self.assertEqual(UserContext.identity(), UserIdentity.anonymous())
123
+        # Can we authenticate ourself ?
124
+        UserContext.authenticate('login', 'pass')
125
+        auth_mock.assert_called_once_with('login', 'pass')
126
+        self.assertEqual(auth_id, UserContext.identity())
127
+
128
+    def test_init(self):
129
+        """ Testing class initialisation being identified by client_infos"""
130
+        identification_method.__reset__()
131
+        authentication_method.__reset__()
132
+        UserContext.__reset__()
133
+        user_id = UserIdentity(42, 'login', identified = True)
134
+        auth_id = UserIdentity(43, 'loggedlogin', authenticated = True)
135
+        # Add a fake id method
136
+        id_mock = Mock(return_value = user_id)
137
+        identification_method(id_mock)
138
+        # Add a fake authentication method
139
+        auth_mock = Mock(return_value = auth_id)
140
+        authentication_method(auth_mock)
141
+        # testing lazy identification
142
+        UserContext.init('localhost')
143
+        id_mock.assert_not_called()
144
+        auth_mock.assert_not_called() # should really not be called yet
145
+        # triggering identification
146
+        ret_id = UserContext.identity()
147
+        id_mock.assert_called_once_with('localhost')
148
+        self.assertEqual(ret_id, user_id)
149
+        auth_mock.assert_not_called() # should really not be called yet
150
+        id_mock.reset_mock()
151
+        # Trying to auth
152
+        UserContext.authenticate('identifier', 'superproof')
153
+        id_mock.assert_not_called()
154
+        auth_mock.assert_called_once_with('identifier', 'superproof')
155
+        self.assertEqual(UserContext.identity(), auth_id)

+ 27
- 3
Lodel/user.py View File

@@ -107,7 +107,7 @@ class authentication_method(object):
107 107
     @classmethod
108 108
     def authenticate(cls, identifier, proof):
109 109
         if len(cls.__methods) == 0:
110
-            raise RuntimeError("Not authentication method registered")
110
+            raise RuntimeError("No authentication method registered")
111 111
         res = False
112 112
         for method in cls.__methods:
113 113
             ret = method(identifier, proof)
@@ -127,6 +127,12 @@ class authentication_method(object):
127 127
     def list_methods(cls):
128 128
         return list(copy.copy(cls.__methods))
129 129
 
130
+    ## @brief Unregister all authentication methods
131
+    # @warning REALLY NOT a good idead !
132
+    # @note implemented for testing purpose
133
+    @classmethod
134
+    def __reset__(cls):
135
+        cls.__methods = set()
130 136
 
131 137
 
132 138
 ## @brief Decorator class designed to register identification methods
@@ -165,8 +171,9 @@ class identification_method(object):
165 171
                     if res is not False:
166 172
                         warnings.warn("Identifying methods returns multiple identity given client_infos")
167 173
                     else:
168
-                        return ret
169
-                    res = ret
174
+                        res = ret
175
+                else:
176
+                    return ret
170 177
         return res
171 178
     
172 179
     ## @return registered identification methods
@@ -174,6 +181,13 @@ class identification_method(object):
174 181
     def list_methods(cls):
175 182
         return list(copy.copy(cls.__methods))
176 183
 
184
+    ## @brief Unregister all identification methods
185
+    # @warning REALLY NOT a good idead !
186
+    # @note implemented for testing purpose
187
+    @classmethod
188
+    def __reset__(cls):
189
+        cls.__methods = set()
190
+
177 191
 
178 192
 ## @brief Static class designed to handle user context
179 193
 class UserContext(object):
@@ -232,6 +246,7 @@ class UserContext(object):
232 246
         cls.__identity = ret
233 247
     
234 248
     ## @return UserIdentity instance
249
+    # @todo useless alias to identity()
235 250
     @classmethod
236 251
     def user_identity(cls):
237 252
         cls.assert_init()
@@ -246,3 +261,12 @@ class UserContext(object):
246 261
     @classmethod
247 262
     def assert_init(cls):
248 263
         assert cls.initialized(), "User context is not initialized"
264
+    
265
+    ## @brief Reset the UserContext
266
+    # @warning Most of the time IT IS NOT A GOOD IDEAD
267
+    # @note implemented for test purpose
268
+    @classmethod
269
+    def __reset__(cls):
270
+        cls.__client_infos = None
271
+        cls.__identity = None
272
+        cls.__context = None

+ 2
- 2
leapi/lecrud.py View File

@@ -309,8 +309,8 @@ class _LeCrud(object):
309 309
     # @todo better error handling
310 310
     def delete(self):
311 311
         LodelHook.call_hook('leapi_delete_pre', self, None)
312
-        self._datasource.delete(self.__class__, self.uidget())
313
-        return LodelHook.call_hook('leapi_delete_post', self, None)
312
+        ret = self._datasource.delete(self.__class__, self.uidget())
313
+        return LodelHook.call_hook('leapi_delete_post', self, ret)
314 314
 
315 315
     ## @brief Check that datas are valid for this type
316 316
     # @param datas dict : key == field name value are field values

Loading…
Cancel
Save