source: OpenWorkouts-current/ow/tests/models/test_user.py @ 78af3d1

currentfeature/docs
Last change on this file since 78af3d1 was 78af3d1, checked in by Borja Lopez <borja@…>, 5 years ago

Fix permissions. From now on users can see (and edit, delete, etc) their own data

  • Property mode set to 100644
File size: 12.5 KB
Line 
1from decimal import Decimal
2from datetime import datetime, timedelta, timezone
3
4import pytest
5from pyramid.security import Allow, Everyone, Deny, ALL_PERMISSIONS
6
7from ow.models.root import OpenWorkouts
8from ow.models.workout import Workout
9from ow.models.user import User
10
11
12class TestUser(object):
13    @pytest.fixture
14    def root(self):
15        root = OpenWorkouts()
16        root['john'] = User(firstname='John', lastname='Doe',
17                            email='john.doe@example.net')
18        root['john'].password = 's3cr3t'
19        return root
20
21    @pytest.fixture
22    def workouts(self):
23        workouts = [Workout(sport='running'),
24                    Workout(sport='cycling'),
25                    Workout(sport='swimming')]
26        return workouts
27
28    def test_user_attrs(self, root):
29        assert root['john'].firstname == 'John'
30        assert root['john'].lastname == 'Doe'
31        assert root['john'].email == 'john.doe@example.net'
32
33    def test__acl__(self, root):
34        uid = str(root['john'].uid)
35        permissions = [
36            (Allow, uid, 'view'),
37            (Allow, uid, 'edit'),
38            (Deny, Everyone, ALL_PERMISSIONS),
39        ]
40        assert root['john'].__acl__() == permissions
41
42    def test__str__(self, root):
43        email = root['john'].email
44        uid = str(root['john'].uid)
45        assert root['john'].__str__() == u'User: ' + email + ' (' + uid + ')'
46
47    def test_fullname(self, root):
48        assert root['john'].fullname == 'John Doe'
49
50    def test_password_is_encrypted(self, root):
51        assert root['john'].password != 's3cr3t'
52
53    def test_check_wrong_password(self, root):
54        assert not root['john'].check_password('badpass')
55
56    def test_check_good_password(self, root):
57        assert root['john'].check_password('s3cr3t')
58
59    def test_add_workout(self, root, workouts):
60        # First add all workouts at once
61        for workout in workouts:
62            root['john'].add_workout(workout)
63        # Then check they are there, in the correct position/number
64        for workout in workouts:
65            index = workouts.index(workout) + 1
66            assert root['john'][str(index)] == workout
67
68    def test_workouts(self, root, workouts):
69        # First add all workouts at once
70        for workout in workouts:
71            root['john'].add_workout(workout)
72        # workouts() will return the workouts sorted from newest to oldest
73        workouts.reverse()
74        assert list(root['john'].workouts()) == workouts
75        assert list(root['john'].workout_ids()) == ['1', '2', '3']
76        assert root['john'].num_workouts == len(workouts)
77
78    def test_activity_dates_tree(self, root):
79        # first an empty test
80        assert root['john'].activity_dates_tree == {}
81        # now add a cycling workout in a given date (25/11/2018)
82        workout = Workout(
83            start=datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc),
84            duration=timedelta(minutes=(60*4)),
85            distance=115,
86            sport='cycling')
87        root['john'].add_workout(workout)
88        assert root['john'].activity_dates_tree == {
89            2018: {11: {'cycling': 1}}
90        }
91        # add a running workout on the same date
92        workout = Workout(
93            start=datetime(2018, 11, 25, 16, 30, tzinfo=timezone.utc),
94            duration=timedelta(minutes=60),
95            distance=12,
96            sport='running')
97        root['john'].add_workout(workout)
98        assert root['john'].activity_dates_tree == {
99            2018: {11: {'cycling': 1, 'running': 1}}
100        }
101        # add a swimming workout on a different date, same year
102        workout = Workout(
103            start=datetime(2018, 8, 15, 11, 30, tzinfo=timezone.utc),
104            duration=timedelta(minutes=30),
105            distance=2,
106            sport='swimming')
107        root['john'].add_workout(workout)
108        assert root['john'].activity_dates_tree == {
109            2018: {8: {'swimming': 1},
110                   11: {'cycling': 1, 'running': 1}}
111        }
112        # now add some more cycling in a different year
113        # add a swimming workout on a different date, same year
114        workout = Workout(
115            start=datetime(2017, 4, 15, 15, 00, tzinfo=timezone.utc),
116            duration=timedelta(minutes=(60*3)),
117            distance=78,
118            sport='cycling')
119        root['john'].add_workout(workout)
120        assert root['john'].activity_dates_tree == {
121            2017: {4: {'cycling': 1}},
122            2018: {8: {'swimming': 1},
123                   11: {'cycling': 1, 'running': 1}}
124        }
125
126    def test_stats(self, root):
127        expected_no_stats = {
128            'workouts': 0,
129            'time': timedelta(seconds=0),
130            'distance': Decimal(0),
131            'elevation': Decimal(0),
132            'sports': {}
133        }
134        # no stats
135        assert root['john'].stats() == expected_no_stats
136        # add a cycling workout
137        workout = Workout(
138            start=datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc),
139            duration=timedelta(minutes=(60*4)),
140            distance=115,
141            sport='cycling')
142        root['john'].add_workout(workout)
143        # asking for a different year, future
144        assert root['john'].stats(2019) == expected_no_stats
145        # asking for a different year, past
146        assert root['john'].stats(2016) == expected_no_stats
147        # asking fot the year the workout is in
148        assert root['john'].stats(2018) == {
149            'workouts': 1,
150            'time': timedelta(minutes=(60*4)),
151            'distance': Decimal(115),
152            'elevation': Decimal(0),
153            'sports': {
154                'cycling': {
155                    'workouts': 1,
156                    'time': timedelta(minutes=(60*4)),
157                    'distance': Decimal(115),
158                    'elevation': Decimal(0),
159                }
160            }
161        }
162        # add a second cycling workout
163        workout = Workout(
164            start=datetime(2018, 11, 26, 10, 00, tzinfo=timezone.utc),
165            duration=timedelta(minutes=(60*3)),
166            distance=100,
167            sport='cycling')
168        root['john'].add_workout(workout)
169        assert root['john'].stats(2018) == {
170            'workouts': 2,
171            'time': timedelta(minutes=(60*7)),
172            'distance': Decimal(215),
173            'elevation': Decimal(0),
174            'sports': {
175                'cycling': {
176                    'workouts': 2,
177                    'time': timedelta(minutes=(60*7)),
178                    'distance': Decimal(215),
179                    'elevation': Decimal(0),
180                }
181            }
182        }
183        # add a running workout
184        workout = Workout(
185            start=datetime(2018, 11, 26, 16, 00, tzinfo=timezone.utc),
186            duration=timedelta(minutes=(60)),
187            distance=10,
188            sport='running')
189        root['john'].add_workout(workout)
190        assert root['john'].stats(2018) == {
191            'workouts': 3,
192            'time': timedelta(minutes=(60*8)),
193            'distance': Decimal(225),
194            'elevation': Decimal(0),
195            'sports': {
196                'cycling': {
197                    'workouts': 2,
198                    'time': timedelta(minutes=(60*7)),
199                    'distance': Decimal(215),
200                    'elevation': Decimal(0),
201                },
202                'running': {
203                    'workouts': 1,
204                    'time': timedelta(minutes=(60)),
205                    'distance': Decimal(10),
206                    'elevation': Decimal(0),
207                }
208            }
209        }
210        # ensure the stats for future/past years did not change after
211        # adding those workouts
212        assert root['john'].stats(2019) == expected_no_stats
213        assert root['john'].stats(2016) == expected_no_stats
214
215    def test_get_week_stats(self, root):
216        expected_no_stats_per_day = {
217            'workouts': 0,
218            'time': timedelta(0),
219            'distance': Decimal(0),
220            'elevation': Decimal(0),
221            'sports': {}
222        }
223
224        expected_no_stats = {}
225        for i in range(19, 26):
226            day = datetime(2018, 11, i, 10, 00, tzinfo=timezone.utc)
227            expected_no_stats[day] = expected_no_stats_per_day
228
229        day = datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc)
230        assert root['john'].get_week_stats(day) == expected_no_stats
231
232        # add a cycling workout
233        workout = Workout(
234            start=datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc),
235            duration=timedelta(minutes=(60*4)),
236            distance=115,
237            sport='cycling')
238        root['john'].add_workout(workout)
239
240        # check a week in the future
241        day = datetime(2019, 11, 25, 10, 00, tzinfo=timezone.utc)
242        week_stats = root['john'].get_week_stats(day)
243        for day in week_stats:
244            assert week_stats[day] == expected_no_stats_per_day
245
246        # check a week in the past
247        day = datetime(2017, 11, 25, 10, 00, tzinfo=timezone.utc)
248        week_stats = root['john'].get_week_stats(day)
249        for day in week_stats:
250            assert week_stats[day] == expected_no_stats_per_day
251
252        # Check the week where the workout is
253        day = datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc)
254        week_stats = root['john'].get_week_stats(day)
255        for day in week_stats:
256            if day.day == 25:
257                # this is the day where we have a workout
258                assert week_stats[day] == {
259                    'workouts': 1,
260                    'time': timedelta(minutes=(60*4)),
261                    'distance': Decimal(115),
262                    'elevation': Decimal(0),
263                    'sports': {
264                        'cycling': {
265                            'workouts': 1,
266                            'time': timedelta(minutes=(60*4)),
267                            'distance': Decimal(115),
268                            'elevation': Decimal(0)
269                        }
270                    }
271                }
272            else:
273                # day without workout
274                assert week_stats[day] == expected_no_stats_per_day
275
276        # add a second cycling workout
277        workout = Workout(
278            start=datetime(2018, 11, 23, 10, 00, tzinfo=timezone.utc),
279            duration=timedelta(minutes=(60*3)),
280            distance=100,
281            sport='cycling')
282        root['john'].add_workout(workout)
283        day = datetime(2018, 11, 25, 10, 00, tzinfo=timezone.utc)
284        week_stats = root['john'].get_week_stats(day)
285        for day in week_stats:
286            if day.day == 25:
287                # this is the day where we have a workout
288                assert week_stats[day] == {
289                    'workouts': 1,
290                    'time': timedelta(minutes=(60*4)),
291                    'distance': Decimal(115),
292                    'elevation': Decimal(0),
293                    'sports': {
294                        'cycling': {
295                            'workouts': 1,
296                            'time': timedelta(minutes=(60*4)),
297                            'distance': Decimal(115),
298                            'elevation': Decimal(0)
299                        }
300                    }
301                }
302            elif day.day == 23:
303                # this is the day where we have a workout
304                assert week_stats[day] == {
305                    'workouts': 1,
306                    'time': timedelta(minutes=(60*3)),
307                    'distance': Decimal(100),
308                    'elevation': Decimal(0),
309                    'sports': {
310                        'cycling': {
311                            'workouts': 1,
312                            'time': timedelta(minutes=(60*3)),
313                            'distance': Decimal(100),
314                            'elevation': Decimal(0)
315                        }
316                    }
317                }
318            else:
319                # day without workout
320                assert week_stats[day] == expected_no_stats_per_day
321
322    def test_week_stats(self, root):
323        expected_no_stats_per_day = {
324            'workouts': 0,
325            'time': timedelta(0),
326            'distance': Decimal(0),
327            'elevation': Decimal(0),
328            'sports': {}
329        }
330
331        # no workouts for the current week (this tests is for coverage
332        # purposes mostly, as the main logic is tested in test_get_week_stats)
333        day = datetime.now(timezone.utc)
334        week_stats = root['john'].get_week_stats(day)
335        for day in week_stats:
336            assert week_stats[day] == expected_no_stats_per_day
337
338    def test_week_totals(self, root):
339        # no data, empty totals
340        assert root['john'].week_totals == {
341            'distance': Decimal(0),
342            'time': timedelta(0)
343        }
Note: See TracBrowser for help on using the repository browser.