From 128609968a07a76e64ada5598ad5f0264e166355 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 2 Jan 2019 20:16:08 +0100 Subject: [PATCH 01/18] working with pytest --- .gitignore | 4 + rowers/mailprocessing.py | 4 +- rowers/tests/tests.py | 227 +++++++++++++++++++++++++++++++-------- 3 files changed, 189 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 8b1d4df3..6e393dc4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ /htmlcov/ .coverage +# pytest stuff +/.pytest_cache/ +pytest.ini + # CSV files /media/ diff --git a/rowers/mailprocessing.py b/rowers/mailprocessing.py index ee8b23a1..95077670 100644 --- a/rowers/mailprocessing.py +++ b/rowers/mailprocessing.py @@ -9,8 +9,8 @@ from rowers.tasks import ( ) from django_mailbox.models import Message, MessageAttachment,Mailbox -workoutmailbox = Mailbox.objects.get(name='workouts') -failedmailbox = Mailbox.objects.get(name='Failed') +#workoutmailbox = Mailbox.objects.get(name='workouts') +#failedmailbox = Mailbox.objects.get(name='Failed') from rowers.models import User, Rower, RowerForm diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index 43ba5ceb..11147a79 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -1,4 +1,8 @@ #from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + from bs4 import BeautifulSoup import re from nose_parameterized import parameterized @@ -40,7 +44,7 @@ from rowers.dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() - +@pytest.mark.django_db class DjangoTestCase(TestCase, MockTestCase): def _pre_setup(self): MockTestCase.setUp(self) @@ -376,7 +380,7 @@ def mocked_requests(*args, **kwargs): return MockResponse(None,404) - +@pytest.mark.django_db class C2Objects(DjangoTestCase): def setUp(self): self.c = Client() @@ -509,6 +513,7 @@ class C2Objects(DjangoTestCase): res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') +@pytest.mark.django_db class StravaObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -547,6 +552,7 @@ class StravaObjects(DjangoTestCase): +@pytest.mark.django_db class STObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -664,6 +670,7 @@ class STObjects(DjangoTestCase): res = add_workout_from_data(self.u,1,data,data) +@pytest.mark.django_db class RunKeeperObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -755,6 +762,7 @@ class RunKeeperObjects(DjangoTestCase): +@pytest.mark.django_db class UAObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -855,6 +863,7 @@ class UAObjects(DjangoTestCase): self.assertEqual(response.status_code, 200) +@pytest.mark.django_db class TPObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -940,6 +949,7 @@ class TPObjects(DjangoTestCase): +@pytest.mark.django_db class TestErrorPages(TestCase): def test_error_handlers(self): @@ -954,6 +964,7 @@ class TestErrorPages(TestCase): self.assertEqual(response.status_code, 500) self.assertIn('500 Internal Server Error', unicode(response)) +@pytest.mark.django_db class NewUserRegistrationTest(TestCase): def setUp(self): self.c = Client() @@ -1030,7 +1041,10 @@ boattype: 2x for filename in os.listdir('media/mailbox_attachments'): path = os.path.join('media/mailbox_attachments/',filename) if not os.path.isdir(path): - os.remove(path) + try: + os.remove(path) + except WindowsError: + pass @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) @@ -1072,7 +1086,7 @@ workout run if not os.path.isdir(path): try: os.remove(path) - except IOError: + except (IOError,WindowsError): pass @patch('requests.get', side_effect=mocked_requests) @@ -1133,7 +1147,7 @@ workout water if not os.path.isdir(path): try: os.remove(path) - except IOError: + except (IOError,WindowsError): pass @patch('requests.get', side_effect=mocked_requests) @@ -1450,7 +1464,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass @@ -1504,7 +1521,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass @@ -1539,7 +1559,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_logcard(self): self.c.login(username='john',password='koeinsloot') @@ -1615,7 +1638,10 @@ class ViewTest(TestCase): self.assertEqual(response.status_code, 200) w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_TCX_SpeedCoach2a(self): self.c.login(username='john',password='koeinsloot') @@ -1646,7 +1672,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_TCX_SpeedCoach2b(self): self.c.login(username='john',password='koeinsloot') @@ -1677,7 +1706,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass @@ -1710,7 +1742,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_SpeedCoach2v127(self): self.c.login(username='john',password='koeinsloot') @@ -1741,7 +1777,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_SpeedCoach2v127intervals(self): @@ -1773,7 +1813,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_TCX_NoHR(self): @@ -1805,7 +1849,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_TCX_CN(self): self.c.login(username='john',password='koeinsloot') @@ -1833,7 +1881,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_RP(self): self.c.login(username='john',password='koeinsloot') @@ -1861,7 +1913,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_Mystery(self): self.c.login(username='john',password='koeinsloot') @@ -1889,7 +1945,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_RP_interval(self): self.c.login(username='john',password='koeinsloot') @@ -1917,7 +1977,11 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass + def test_upload_view_sled_desktop(self): @@ -1946,7 +2010,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_sled_ergdata(self): self.c.login(username='john',password='koeinsloot') @@ -1974,7 +2041,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_sled_boatcoach(self): self.c.login(username='john',password='koeinsloot') @@ -2002,7 +2072,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass def test_upload_view_sled_ergstick(self): self.c.login(username='john',password='koeinsloot') @@ -2030,7 +2103,10 @@ class ViewTest(TestCase): w = Workout.objects.get(id=1) f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted+'.gz') + try: + os.remove(f_to_be_deleted+'.gz') + except WindowsError: + pass # def test_upload_view_FIT_SpeedCoach2a(self): @@ -2398,7 +2474,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 1 if (w.workouttype=='water'): @@ -2408,7 +2487,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 2 if (w.workouttype=='water'): @@ -2418,7 +2500,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 3 if (w.workouttype=='water'): @@ -2428,7 +2513,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 4 if (w.workouttype=='water'): @@ -2438,7 +2526,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 5 if (w.workouttype=='water'): @@ -2448,7 +2539,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 6 if (w.workouttype=='water'): @@ -2458,7 +2552,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 7 if (w.workouttype=='water'): @@ -2468,7 +2565,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 8 if (w.workouttype=='water'): @@ -2478,7 +2578,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 13 if (w.workouttype=='water'): @@ -2488,7 +2591,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass def test_otw_plots(self): w = self.wotw @@ -2505,7 +2611,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 1 if (w.workouttype=='water'): @@ -2515,7 +2624,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 2 if (w.workouttype=='water'): @@ -2525,7 +2637,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 3 if (w.workouttype=='water'): @@ -2535,7 +2650,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 4 if (w.workouttype=='water'): @@ -2545,7 +2663,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 5 if (w.workouttype=='water'): @@ -2555,7 +2676,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 6 if (w.workouttype=='water'): @@ -2565,7 +2689,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 7 if (w.workouttype=='water'): @@ -2575,7 +2702,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 8 if (w.workouttype=='water'): @@ -2585,7 +2715,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 9 if (w.workouttype=='water'): @@ -2595,7 +2728,10 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass plotnr = 13 if (w.workouttype=='water'): @@ -2605,4 +2741,7 @@ class PlotTests(TestCase): w.name,self.hrdata,plotnr,imagename) i = GraphImage(workout=w,creationdatetime=self.nu, filename=fullpathimagename) - os.remove(fullpathimagename) + try: + os.remove(fullpathimagename) + except WindowsError: + pass From 76d2325797ad3a179ec3d727b4fc823047b71dd2 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 2 Jan 2019 21:54:25 +0100 Subject: [PATCH 02/18] adding tests to increase coverage --- .gitignore | 1 + rowers/celery.py | 6 +- rowers/plots.py | 8 +- rowers/tests/test_admin.py | 47 + rowers/tests/test_admin.py,cover | 47 + rowers/tests/test_models.py | 14 + rowers/tests/test_user.py | 89 + rowers/tests/test_user.py,cover | 94 + rowers/tests/tests.py | 103 +- rowers/tests/tests.py,cover | 2831 ++++++++++++++++++++++++++++++ 10 files changed, 3224 insertions(+), 16 deletions(-) create mode 100644 rowers/tests/test_admin.py create mode 100644 rowers/tests/test_admin.py,cover create mode 100644 rowers/tests/test_models.py create mode 100644 rowers/tests/test_user.py create mode 100644 rowers/tests/test_user.py,cover create mode 100644 rowers/tests/tests.py,cover diff --git a/.gitignore b/.gitignore index 6e393dc4..665c5589 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ # pytest stuff /.pytest_cache/ pytest.ini +conftest.py # CSV files /media/ diff --git a/rowers/celery.py b/rowers/celery.py index 8ecc91a9..77d84ba3 100644 --- a/rowers/celery.py +++ b/rowers/celery.py @@ -30,7 +30,7 @@ app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) database_url = 'sqlite:///db.sqlite3' -@app.task(bind=True) -def debug_task(self): - print('Request: {0!r}'.format(self.request)) +#@app.task(bind=True) +#def debug_task(self): +# print('Request: {0!r}'.format(self.request)) diff --git a/rowers/plots.py b/rowers/plots.py index b57d263e..948ddd94 100644 --- a/rowers/plots.py +++ b/rowers/plots.py @@ -6,10 +6,10 @@ from rows import format_pace_tick, format_pace, format_time, format_time_tick # Formatting the distance tick marks -def format_dist_tick(x,pos=None): - km = x/1000. - template='%6.3f' - return template % (km) +#def format_dist_tick(x,pos=None): +# km = x/1000. +# template='%6.3f' +# return template % (km) # Utility to select reasonable y axis range diff --git a/rowers/tests/test_admin.py b/rowers/tests/test_admin.py new file mode 100644 index 00000000..230c6221 --- /dev/null +++ b/rowers/tests/test_admin.py @@ -0,0 +1,47 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +import datetime + +import json +import numpy as np + + +from redis import StrictRedis +redis_connection = StrictRedis() + +from rowers.models import User,Rower + +@pytest.mark.django_db +class AdminTests(TestCase): + def setUp(self): + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u) + my_admin = User.objects.create_superuser('myuser', + 'myemail@test.com', + 'apensstaart') + + self.c = Client() + self.c.login(username='myuser',password='apensstaart') + + def test_admin(self): + response = self.c.get('/admin',follow=True) + self.assertEqual(response.status_code,200) + + + response = self.c.get('/admin/auth/user/',follow=True) + self.assertEqual(response.status_code,200) + + response = self.c.get('/admin/auth/user/77/change/',follow=True) + self.assertEqual(response.status_code,200) diff --git a/rowers/tests/test_admin.py,cover b/rowers/tests/test_admin.py,cover new file mode 100644 index 00000000..083f75f0 --- /dev/null +++ b/rowers/tests/test_admin.py,cover @@ -0,0 +1,47 @@ + #from __future__ import print_function +> import pytest + +> pytestmark = pytest.mark.django_db + +> from bs4 import BeautifulSoup +> import re +> from nose_parameterized import parameterized +> from django.test import TestCase, Client,override_settings +> from django.core.management import call_command +> from django.utils.six import StringIO +> from django.test.client import RequestFactory +> import datetime + +> import json +> import numpy as np + + +> from redis import StrictRedis +> redis_connection = StrictRedis() + +> from rowers.models import User,Rower + +> @pytest.mark.django_db +> class AdminTests(TestCase): +> def setUp(self): +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> r = Rower.objects.create(user=u) +> my_admin = User.objects.create_superuser('myuser', +> 'myemail@test.com', +> 'apensstaart') + +> self.c = Client() +> self.c.login(username='myuser',password='apensstaart') + +> def test_admin(self): +> response = self.c.get('/admin',follow=True) +> self.assertEqual(response.status_code,200) + + +> response = self.c.get('/admin/auth/user/',follow=True) +> self.assertEqual(response.status_code,200) + +> response = self.c.get('/admin/auth/user/77/change/',follow=True) +> self.assertEqual(response.status_code,200) diff --git a/rowers/tests/test_models.py b/rowers/tests/test_models.py new file mode 100644 index 00000000..42f9bf71 --- /dev/null +++ b/rowers/tests/test_models.py @@ -0,0 +1,14 @@ +from django.test import TestCase +from rowers.models import * + +class FormTests(TestCase): + def SetUp(self): + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + r = Rower.objects.create(user=u) + + + def test_form(self): + form = TeamInviteForm() diff --git a/rowers/tests/test_user.py b/rowers/tests/test_user.py new file mode 100644 index 00000000..3a91de7d --- /dev/null +++ b/rowers/tests/test_user.py @@ -0,0 +1,89 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +import datetime +from django.utils import timezone + +import json +import numpy as np +import rowers.dataprep as dataprep + +from redis import StrictRedis +redis_connection = StrictRedis() + +from rowers.models import User,Rower, Workout + +class UserMiddleWareTest(TestCase): + def setUp(self): + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u) + + self.c = Client() + self.c.login(username='john',password='koeinsloot') + nu = datetime.datetime.now() + + response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', + title='sample') + + newworkoutid = response[0] + self.w = Workout.objects.get(id=newworkoutid) + + + def test_middleware(self): + response = self.c.get('/rowers/list-workouts',follow=True) + self.assertEqual(response.status_code,200) + +class UserExpireTest(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + yesterday_dt = timezone.now()-datetime.timedelta(days=1) + yesterday = yesterday_dt.date() + + r = Rower.objects.create(user=self.u,planexpires = yesterday,rowerplan='pro', + paymenttype='single') + + self.c = Client() + self.c.login(username='john',password='koeinsloot') + nu = datetime.datetime.now() + + response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', + title='sample') + + newworkoutid = response[0] + self.w = Workout.objects.get(id=newworkoutid) + + + def test_expire(self): + response = self.c.get('/rowers/list-workouts',follow=True) + self.assertEqual(response.status_code,200) + self.assertEqual(self.u.rower.rowerplan,'basic') + +class UserTestsNoRower(TestCase): + def setUp(self): + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.c = Client() + self.c.login(username='john',password='koeinsloot') + + + def test_user(self): + response = self.c.get('/rowers/list-workouts',follow=True) + self.assertEqual(response.status_code,200) + diff --git a/rowers/tests/test_user.py,cover b/rowers/tests/test_user.py,cover new file mode 100644 index 00000000..5ece6fa8 --- /dev/null +++ b/rowers/tests/test_user.py,cover @@ -0,0 +1,94 @@ + #from __future__ import print_function +> import pytest + +> pytestmark = pytest.mark.django_db + +> from bs4 import BeautifulSoup +> import re +> from nose_parameterized import parameterized +> from django.test import TestCase, Client,override_settings +> from django.core.management import call_command +> from django.utils.six import StringIO +> from django.test.client import RequestFactory +> import datetime +! from django.utils import timezone + +> import json +! import numpy as np + + +> from redis import StrictRedis +! redis_connection = StrictRedis() + +! from rowers.models import User,Rower, Workout + +> class UserMiddleWareTest(TestCase): +> def setUp(self): +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +! r = Rower.objects.create(user=u) + +> self.c = Client() +! self.c.login(username='john',password='koeinsloot') +> nu = datetime.datetime.now() + +> response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', +> title='sample') + +! newworkoutid = response[0] +! self.w = Workout.objects.get(id=newworkoutid) + + +! def test_middleware(self): +! response = self.c.get('/rowers/list-workouts',follow=True) +! self.assertEqual(response.status_code,200) + +! class UserExpireTest(TestCase): +! def setUp(self): +! redis_connection.publish('tasks','KILL') +! self.u = User.objects.create_user('john', +! 'sander@ds.ds', +! 'koeinsloot') + +! yesterday_dt = timezone.now()-datetime.timedelta(days=1) +! yesterday = yesterday_dt.date() + +! r = Rower.objects.create(user=self.u,planexpires = yesterday,rowerplan='pro', +! paymenttype='single') + +! self.c = Client() +! self.c.login(username='john',password='koeinsloot') +! nu = datetime.datetime.now() + +! response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', +! title='sample') + +! newworkoutid = response[0] +! self.w = Workout.objects.get(id=newworkoutid) + + +! def test_expire(self): +! response = self.c.get('/rowers/list-workouts',follow=True) +! self.assertEqual(response.status_code,200) +! self.assertEqual(self.u.rower.rowerplan,'basic') + +! class UserTestsNoRower(TestCase): +! def setUp(self): +! u = User.objects.create_user('john', +! 'sander@ds.ds', +! 'koeinsloot') + +! self.c = Client() +! self.c.login(username='john',password='koeinsloot') +! nu = datetime.datetime.now() +! self.w = Workout.objects.create(name='testworkout', +! workouttype='water', +! user=self.r,date=nu.strftime('%Y-%m-%d'), +! starttime=nu.strftime('%H:%M:%S'), +! duration="0:55:00",distance=8000) + +! def test_user(self): +! response = self.c.get('/rowers/list-workouts',follow=True) +! self.assertEqual(response.status_code,200) + diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index 11147a79..ee207208 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -44,7 +44,7 @@ from rowers.dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() -@pytest.mark.django_db +#@pytest.mark.django_db class DjangoTestCase(TestCase, MockTestCase): def _pre_setup(self): MockTestCase.setUp(self) @@ -355,6 +355,7 @@ def mocked_requests(*args, **kwargs): elif c2workoutlisttester.match(args[0]): return MockResponse(c2workoutlist,200) elif 'access_token' in args[0]: + print 'aap' json_data = { 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', 'expires_in': 604800, @@ -380,7 +381,7 @@ def mocked_requests(*args, **kwargs): return MockResponse(None,404) -@pytest.mark.django_db +#@pytest.mark.django_db class C2Objects(DjangoTestCase): def setUp(self): self.c = Client() @@ -512,8 +513,82 @@ class C2Objects(DjangoTestCase): res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') +class C2ObjectsTokenExpired(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + self.r.c2token = '12' + self.r.c2refreshtoken = 'ab' + self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) + self.r.save() + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() -@pytest.mark.django_db + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + + + @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_list(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/c2list',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_import(self, mock_get): + + response = self.c.get('/rowers/workout/c2import/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/2/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + + +#@pytest.mark.django_db class StravaObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -552,7 +627,7 @@ class StravaObjects(DjangoTestCase): -@pytest.mark.django_db +#@pytest.mark.django_db class STObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -670,7 +745,7 @@ class STObjects(DjangoTestCase): res = add_workout_from_data(self.u,1,data,data) -@pytest.mark.django_db +#@pytest.mark.django_db class RunKeeperObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -762,7 +837,7 @@ class RunKeeperObjects(DjangoTestCase): -@pytest.mark.django_db +#@pytest.mark.django_db class UAObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -863,7 +938,7 @@ class UAObjects(DjangoTestCase): self.assertEqual(response.status_code, 200) -@pytest.mark.django_db +#@pytest.mark.django_db class TPObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -949,7 +1024,7 @@ class TPObjects(DjangoTestCase): -@pytest.mark.django_db +#@pytest.mark.django_db class TestErrorPages(TestCase): def test_error_handlers(self): @@ -964,7 +1039,7 @@ class TestErrorPages(TestCase): self.assertEqual(response.status_code, 500) self.assertIn('500 Internal Server Error', unicode(response)) -@pytest.mark.django_db +#@pytest.mark.django_db class NewUserRegistrationTest(TestCase): def setUp(self): self.c = Client() @@ -997,6 +1072,7 @@ class NewUserRegistrationTest(TestCase): from django_mailbox.models import Mailbox,MessageAttachment,Message +#@pytest.mark.django_db class AutoExportTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1053,6 +1129,7 @@ boattype: 2x call_command('processemail', stdout=out, testing=True) self.assertIn('Successfully processed email attachments',out.getvalue()) +#@pytest.mark.django_db class UploadTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1096,6 +1173,7 @@ workout run w = Workout.objects.get(id=1) self.assertEqual(w.workouttype,'Run') +#@pytest.mark.django_db class EmailTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1157,6 +1235,7 @@ workout water self.assertIn('Successfully processed email attachments',out.getvalue()) +#@pytest.mark.django_db class WorkoutTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1176,6 +1255,7 @@ class WorkoutTests(TestCase): def test_checkworkoutuser(self): self.assertEqual(checkworkoutuser(self.u,self.w),True) +#@pytest.mark.django_db class C2Tests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1196,6 +1276,7 @@ class C2Tests(TestCase): # should raise NoTokenError self.assertRaises(NoTokenError) +#@pytest.mark.django_db class DataTest(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -1383,6 +1464,7 @@ class DataTest(TestCase): +#@pytest.mark.django_db class ViewTest(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -2143,6 +2225,7 @@ class ViewTest(TestCase): # f_to_be_deleted = w.csvfilename # os.remove(f_to_be_deleted+'.gz') +#@pytest.mark.django_db class URLTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -2389,6 +2472,7 @@ class URLTests(TestCase): msg=url+' response status code not 200') +#@pytest.mark.django_db class subroutinetests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -2414,6 +2498,7 @@ class subroutinetests(TestCase): +#@pytest.mark.django_db class PlotTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') diff --git a/rowers/tests/tests.py,cover b/rowers/tests/tests.py,cover new file mode 100644 index 00000000..3c9785cd --- /dev/null +++ b/rowers/tests/tests.py,cover @@ -0,0 +1,2831 @@ + #from __future__ import print_function +> import pytest + +> pytestmark = pytest.mark.django_db + +> from bs4 import BeautifulSoup +> import re +> from nose_parameterized import parameterized +> from django.test import TestCase, Client,override_settings +> from django.core.management import call_command +> from django.utils.six import StringIO +> from django.test.client import RequestFactory +> from rowers.views import checkworkoutuser,c2_open +> from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +> from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +> import rowers.plots as plots +> import rowers.interactiveplots as iplots +> import datetime +> from rowingdata import rowingdata as rdata +> from rowingdata import rower as rrower +> from django.utils import timezone +> from rowers.rows import handle_uploaded_file +> from django.core.files.uploadedfile import SimpleUploadedFile +> from time import strftime,strptime,mktime,time,daylight +> import os +> from rowers.tasks import handle_makeplot +> from rowers.utils import serialize_list,deserialize_list +> from rowers.utils import NoTokenError +> from shutil import copyfile +> from nose.tools import assert_true +> from mock import Mock, patch +> from minimocktest import MockTestCase +> import pandas as pd +> import rowers.c2stuff as c2stuff + +> import json +> import numpy as np + +> from rowers import urls +> from rowers.views import error500_view,error404_view,error400_view,error403_view + +> from rowers.dataprep import delete_strokedata + +> from redis import StrictRedis +> redis_connection = StrictRedis() + + #@pytest.mark.django_db +> class DjangoTestCase(TestCase, MockTestCase): +> def _pre_setup(self): +> MockTestCase.setUp(self) +> TestCase._pre_setup(self) +> self.client = Client() + +> def _post_teardown(self): +> TestCase._post_teardown(self) +> MockTestCase.tearDown(self) +> delete_strokedata(1) + + # to be done add polar mocks (for email processing) +> def mocked_requests(*args, **kwargs): +> with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: +> c2workoutdata = json.load(infile) + +> with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: +> c2strokedata = json.load(infile) + +> polar_json = { +> 'available-user-data': [] +> } + +> c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) + +> c2uploadjson = { +> "data": { +> "id": 339, +> "user_id": 1, +> "date": "2015-08-05 13:15:41", +> "timezone": "Europe/London", +> "date_utc": "2015-08-05 12:15:41", +> "distance": 5649, +> "type": "rower", +> "time": 8649, +> "time_formatted": "14:24.9", +> "workout_type": "JustRow", +> "source": "ErgData", +> "weight_class": "H", +> "verified": True, +> "ranked": False +> } +> } + +> stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) +> sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) + +> rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) +> uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) + +> stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) + +> stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) +> stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) + +> stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) + +> stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) +> stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) +> stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) +> stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) + +> uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) + +> tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) + +> stravastreamjson = { +> 'time':stravatimejson, +> 'velocity_smooth':stravavelojson, +> 'distance':stravadistancejson, +> 'latlng':stravalatlongjson, +> 'heartrate':stravahrjson, +> 'cadence':stravaspmjson, +> 'power':stravapowerjson, +> } + +> ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) + +> rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) + +> uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) +> uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) + +> class MockResponse: +> def __init__(self, json_data, status_code): +> self.json_data = json_data +> self.status_code = status_code + +> def json(self): +> return self.json_data + + +> class MockHeaderResponse: +> def __init__(self, header_data, status_code): +> self.headers = header_data +> self.status_code = status_code + +> class MockSession: +> def send(self,prepped): + # prepped.url + # prepped.body (post data) + # prepped.headers + # prepped.method + +> json_data = { +> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +> 'expires_in': 604800, +> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +> } + +> return MockResponse(json_data,200) + +> if not args: +> return MockSession() + +> polartester = re.compile('.*?polaraccesslink\.com') +> c2tester = re.compile('.*?log\.concept2\.com') +> stravatester = re.compile('.*?strava\.com') +> sttester = re.compile('.*?sporttracks\.mobi') +> rktester = re.compile('.*?runkeeper\.com') +> uatester = re.compile('.*?mapmyfitness\.com') +> tptester = re.compile('.*?trainingpeaks\.com') + +> c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' +> c2importtester = re.compile(c2importregex) + +> c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' +> c2uploadtester = re.compile(c2uploadregex) + +> c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' +> c2strokestester = re.compile(c2strokesregex) + +> c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' +> c2workoutlisttester = re.compile(c2workoutlistregex) + +> stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' +> stravaworkoutlisttester = re.compile(stravaworkoutlistregex) + +> stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' +> stravastreamtester = re.compile(stravastreamregex) + +> stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' +> stravasummarytester = re.compile(stravasummaryregex) + +> stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' +> stuploadtester = re.compile(stuploadregex) + +> stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' +> stworkoutlisttester = re.compile(stworkoutlistregex) + +> ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' +> ststrokestester = re.compile(ststrokesregex) + +> rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' +> rkuploadtester = re.compile(rkuploadregex) +> rkuserregex = '.*?api\.runkeeper\.com\/user$' +> rkusertester = re.compile(rkuserregex) +> rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' +> rkstrokestester = re.compile(rkstrokesregex) + +> uaapiregex = '.*?api\.ua\.com' +> uaapitester = re.compile(uaapiregex) + +> uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' +> uauploadtester = re.compile(uauploadregex) + +> uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' +> uastrokestester = re.compile(uastrokesregex) + +> ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' +> ualisttester = re.compile(ualistregex) + +> uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' +> uausertester = re.compile(uauserregex) + +> tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' +> tpuploadtester = re.compile(tpuploadregex) + +> if polartester.match(args[0]): +> json_data = polar_json +> return MockResponse(json_data,200) + +> if tptester.match(args[0]): +> if 'token' in args[0]: +> json_data = { +> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +> 'expires_in': 604800, +> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +> } +> return MockResponse(json_data,200) +> elif tpuploadtester.match(args[0]): +> return MockResponse(tpuploadresponse,200) + +> if uaapitester.match(args[0]): +> if 'access_token' in args[0]: +> json_data = { +> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +> 'expires_in': 604800, +> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +> } +> return MockResponse(json_data,200) +> elif uauploadtester.match(args[0]): +> if 'data' in kwargs: +> return MockResponse(uapostworkoutjson,200) +> elif uastrokestester.match(args[0]): +> return MockResponse(uastrokesjson,200) +> elif ualisttester.match(args[0]): +> return MockResponse(uaworkoutlistjson,200) +> elif uausertester.match(args[0]): +> return MockResponse(uauserjson,200) + + +> if uatester.match(args[0]): +! if 'access_token' in args[0]: +! json_data = { +! 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +! 'expires_in': 604800, +! 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +! } +! return MockResponse(json_data,200) + + +> if rktester.match(args[0]): +> if 'token' in args[0]: +> json_data = { +> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +> 'expires_in': 604800, +> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +> } +> return MockResponse(json_data,200) +> elif rkuploadtester.match(args[0]): +> if 'data' in kwargs: + # post +> header_data = { +> 'Location': '/fitnessActivities/12' +> } +> return MockHeaderResponse(header_data,200) +> else: +> json_data = rkworkoutlistjson +> return MockResponse(json_data,200) +> elif rkusertester.match(args[0]): +> json_data = { +> "userID": 1234567890, +> "profile": "/profile", +> "settings": "/settings", +> "fitness_activities": "/fitnessActivities", +> "strength_training_activities": "/strengthTrainingActivities", +> "background_activities": "/backgroundActivities", +> "sleep": "/sleep", +> "nutrition": "/nutrition", +> "weight": "/weight", +> "general_measurements": "/generalMeasurements", +> "diabetes": "/diabetes", +> "records": "/records", +> "team": "/team" +> } +> return MockResponse(json_data, 200) +> elif rkstrokestester.match(args[0]): +> return MockResponse(rkstrokesjson,200) + +> if sttester.match(args[0]): +> if 'oauth2/token' in args[0]: +> json_data = { +> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +> 'expires_in': 604800, +> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +> } +> return MockResponse(json_data,200) +> if ststrokestester.match(args[0]): +> return MockResponse(ststrokesjson,200) +> if stuploadtester.match(args[0]): +> json_data = { +> "uris": [ +> "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" +> ] +> } +> return MockResponse(json_data, 200) +> if stworkoutlisttester.match(args[0]): +> return MockResponse(sporttracksworkoutlist,200) + + +> if stravatester.match(args[0]): +> if stravaworkoutlisttester.match(args[0]): +! return MockResponse(stravaworkoutlist,200) +> if stravastreamtester.match(args[0]): +> metric = stravastreamtester.match(args[0]).group(1) +> json_data = stravastreamjson[metric] +> return MockResponse(json_data,200) +> elif stravasummarytester.match(args[0]): +> return MockResponse(stravasummaryjson,200) +> elif 'token' in args[0]: +> json_data = { +> "token_type": "Bearer", +> "access_token": "987654321234567898765432123456789", +> "refresh_token": "1234567898765432112345678987654321", +> "expires_at": 1531385304 +> } +> return MockResponse(json_data,200) + + +> if c2tester.match(args[0]): +> if c2uploadtester.match(args[0]): +> return MockResponse(c2uploadjson,201) +> if c2strokestester.match(args[0]): +> return MockResponse(c2strokedata,200) +> elif c2importtester.match(args[0]): +> return MockResponse(c2workoutdata,200) +> elif c2workoutlisttester.match(args[0]): +> return MockResponse(c2workoutlist,200) +> elif 'access_token' in args[0]: +! json_data = { +! 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', +! 'expires_in': 604800, +! 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' +! } +! return MockResponse(json_data,200) +> elif 'users/me' in args[0]: +> json_data = { +> 'data': { +> 'username': 'john', +> 'id': 1234, +> } +> } +> return MockResponse(json_data,200) +! elif 'results' in args[0]: +! json_data = { +! 'data': { +! 'id': 1223, +! } +! } +! else: +! return MockResponse(c2workoutdata,200) + +! return MockResponse(None,404) + + #@pytest.mark.django_db +> class C2Objects(DjangoTestCase): +> def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +> self.u.first_name = 'John' +> self.u.last_name = 'Sander' +> self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +> self.r.c2token = '12' +> self.r.c2refreshtoken = 'ab' +> self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) +> self.r.save() +> self.c.login(username='john',password='koeinsloot') + +> self.nu = datetime.datetime.now() + +> filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +> totaldist = row.df['cum_dist'].max() +> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + + +> @patch('rowers.c2stuff.requests.Session', side_effect=mocked_requests) +> def test_c2_callback(self, mock_Session): +> response = self.c.get('/call_back?code=dsdoij232s',follow=True) + + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.c2stuff.Session', side_effect=mocked_requests) +> def test_c2_token_refresh(self, mock_post): +> response = self.c.get('/rowers/me/c2refresh/',follow=True) + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) +> def test_c2_upload(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/1/c2uploadw/') + +> self.assertRedirects(response, +> expected_url = '/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.url, '/rowers/workout/1/edit') +> self.assertEqual(response.status_code, 302) + +> @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) +> def test_c2_list(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/c2list',follow=True) + +> self.assertEqual(response.status_code,200) + +> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) +> def test_c2_import(self, mock_get): + +> response = self.c.get('/rowers/workout/c2import/12/',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/2/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + + +> def test_strokedata(self): +> with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile: +> res = json.load(infile) + +> strokedata = pd.DataFrame.from_dict(res['data']) + +> with open('rowers/tests/testdata/c2testdata.txt','r') as infile: +> res = json.load(infile) + +> data = res['data'] + +> from rowers.views import add_workout_from_strokedata + +> res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') + +> def test_strokedatanohr(self): +> with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile: +> res = json.load(infile) + +> strokedata = pd.DataFrame.from_dict(res['data']) + +> with open('rowers/tests/testdata/c2testdata.txt','r') as infile: +> res = json.load(infile) + +> data = res['data'] + +> from rowers.views import add_workout_from_strokedata + + +> res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') + +! class C2ObjectsTokenExpired(DjangoTestCase): +! def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +> self.u.first_name = 'John' +! self.u.last_name = 'Sander' +> self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +! self.r.c2token = '12' +! self.r.c2refreshtoken = 'ab' +> self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) +! self.r.save() +> self.c.login(username='john',password='koeinsloot') + +! self.nu = datetime.datetime.now() + +! filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +! totaldist = row.df['cum_dist'].max() +! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +! seconds = int(totaltime - 3600.*hours - 60.*minutes) +> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + + + +! @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) +> def test_c2_list(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/c2list',follow=True) + +! self.assertEqual(response.status_code,200) + +! @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) +! def test_c2_import(self, mock_get): + +> response = self.c.get('/rowers/workout/c2import/12/',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/2/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + + + + #@pytest.mark.django_db +> class StravaObjects(DjangoTestCase): +> def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +! self.u.first_name = 'John' +> self.u.last_name = 'Sander' +> self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +> self.r.stravatoken = '12' + +> self.r.save() +> self.c.login(username='john',password='koeinsloot') + +! @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) +! def test_strava_list(self, mock_get): +! response = self.c.get('/rowers/workout/stravaimport/',follow=True) + +! self.assertEqual(response.status_code,200) + +> @patch('rowers.utils.requests.get', side_effect=mocked_requests) +> def test_strava_import(self, mock_get): + +> response = self.c.get('/rowers/workout/stravaimport/12',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/1/edit', +> status_code=301,target_status_code=200) + +! self.assertEqual(response.status_code, 200) + + + + #@pytest.mark.django_db +! class STObjects(DjangoTestCase): +> def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +! self.u.first_name = 'John' +> self.u.last_name = 'Sander' +! self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + + +! self.r.sporttrackstoken = '12' +! self.r.sporttracksrefreshtoken = '12' +> self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) +! self.r.save() + +> self.c.login(username='john',password='koeinsloot') + +! self.nu = datetime.datetime.now() + +! filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +! totaldist = row.df['cum_dist'].max() +> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +! totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +! minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +! tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +! workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + +> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) +> def test_sporttracks_callback(self, mock_post): +! response = self.c.get('/sporttracks_callback?code=dsdoij232s',follow=True) + + +! self.assertEqual(response.status_code, 200) + + +> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) +> def test_sporttracks_token_refresh(self, mock_post): +> response = self.c.get('/rowers/me/sporttracksrefresh/',follow=True) + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) +> def test_sporttracks_upload(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/1/sporttracksuploadw/') + +> self.assertRedirects(response, +> expected_url = '/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.url, '/rowers/workout/1/edit') +> self.assertEqual(response.status_code, 302) + +! @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) +! def test_sporttracks_list(self, mock_get): +! response = self.c.get('/rowers/workout/sporttracksimport',follow=True) + +> self.assertEqual(response.status_code,200) + +! @patch('rowers.imports.requests.get', side_effect=mocked_requests) +! def test_sporttracks_import(self, mock_get): + +> response = self.c.get('/rowers/workout/sporttracksimport/12/',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/2/edit', +> status_code=302,target_status_code=200) + +! self.assertEqual(response.status_code, 200) + +! def test_strokedata(self): +> with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile: +! data = json.load(infile) + +! from rowers.sporttracksstuff import add_workout_from_data + +> res = add_workout_from_data(self.u,1,data,data) + +> def test_strokedatanohr(self): +! with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile: +> data = json.load(infile) + +> from rowers.sporttracksstuff import add_workout_from_data + + + +! res = add_workout_from_data(self.u,1,data,data) + + #@pytest.mark.django_db +> class RunKeeperObjects(DjangoTestCase): +! def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +> self.u.first_name = 'John' +! self.u.last_name = 'Sander' +> self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + + +! self.r.runkeepertoken = '12' + +! self.r.save() + +> self.c.login(username='john',password='koeinsloot') + +> self.nu = datetime.datetime.now() + +> filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +> totaldist = row.df['cum_dist'].max() +! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +! totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +! tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +! workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + +> @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) +> def test_runkeeper_callback(self, mock_post): +> response = self.c.get('/runkeeper_callback?code=dsdoij232s',follow=True) + +> self.assertEqual(response.status_code, 200) + +! @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) +> def test_runkeeper_upload(self, mock_get, mock_post): +! response = self.c.get('/rowers/workout/1/runkeeperuploadw/') + +> self.assertRedirects(response, +> expected_url = '/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.url, '/rowers/workout/1/edit') +> self.assertEqual(response.status_code, 302) + +! @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) +! def test_runkeeper_list(self, mock_get): +! response = self.c.get('/rowers/workout/runkeeperimport',follow=True) + +! self.assertEqual(response.status_code,200) + +> @patch('rowers.imports.requests.get', side_effect=mocked_requests) +> def test_runkeeper_import(self, mock_get): + +> response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/2/edit', +> status_code=302,target_status_code=200) + +! self.assertEqual(response.status_code, 200) + + + + #@pytest.mark.django_db +! class UAObjects(DjangoTestCase): +> def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +! self.u.first_name = 'John' +> self.u.last_name = 'Sander' +! self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + + +! self.r.underarmourtoken = '12' +! self.r.underarmourrefreshtoken = '12' +> self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) +! self.r.save() + +> self.c.login(username='john',password='koeinsloot') + +! self.nu = datetime.datetime.now() + +! filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +> totaldist = row.df['cum_dist'].max() +> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + +> @patch('rowers.imports.requests.post', side_effect=mocked_requests) +> def test_underarmour_callback(self, mock_post): +> response = self.c.get('/underarmour_callback?code=dsdoij232s',follow=True) + + +! self.assertEqual(response.status_code, 200) + + +> @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) +> def test_underarmour_token_refresh(self, mock_post): +> response = self.c.get('/rowers/me/underarmourrefresh/',follow=True) + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) +> def test_underarmour_upload(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/1/underarmouruploadw/') + +> self.assertRedirects(response, +> expected_url = '/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.url, '/rowers/workout/1/edit') +! self.assertEqual(response.status_code, 302) + +> @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) +> def test_underarmour_list(self, mock_get): +> response = self.c.get('/rowers/workout/underarmourimport',follow=True) + +! self.assertEqual(response.status_code,200) + +! @patch('rowers.imports.requests.get', side_effect=mocked_requests) +! def test_underarmour_import(self, mock_get): + +! response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/workout/2/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + + + #@pytest.mark.django_db +! class TPObjects(DjangoTestCase): +> def setUp(self): +> self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') + +! self.u.first_name = 'John' +! self.u.last_name = 'Sander' +! self.u.save() +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + + +> self.r.tptoken = '12' +> self.r.tprefreshtoken = '12' +> self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) +> self.r.save() + +> self.c.login(username='john',password='koeinsloot') + +> self.nu = datetime.datetime.now() + +> filename = 'rowers/tests/testdata/testdata.csv' + +> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, +> hrut1=self.r.ut1,hrat=self.r.at, +> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) +> row = rdata(filename,rower=rr) +> totaldist = row.df['cum_dist'].max() +! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> self.w = Workout.objects.create( +> name='testworkout',workouttype='water', +> user=self.r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> startdatetime=row.rowdatetime, +> duration=duration,distance=totaldist, +> csvfilename=filename +> ) + +> @patch('rowers.imports.requests.post', side_effect=mocked_requests) +> def test_tp_callback(self, mock_post): +> response = self.c.get('/tp_callback?code=dsdoij232s',follow=True) + + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) +> def test_tp_token_refresh(self, mock_post): +> response = self.c.get('/rowers/me/tprefresh/',follow=True) + +> self.assertEqual(response.status_code, 200) + + +> @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) +> @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) +> def test_tp_upload(self, mock_get, mock_post): +> response = self.c.get('/rowers/workout/1/tpuploadw/') + +> self.assertRedirects(response, +> expected_url = '/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.url, '/rowers/workout/1/edit') +> self.assertEqual(response.status_code, 302) + + + + + #@pytest.mark.django_db +> class TestErrorPages(TestCase): +> def test_error_handlers(self): + +! self.assertTrue(urls.handler404.endswith('.error404_view')) +! self.assertTrue(urls.handler500.endswith('.error500_view')) +! factory = RequestFactory() +! request = factory.get('/') +> response = error404_view(request) +> self.assertEqual(response.status_code, 404) +> self.assertIn('404 Page not found', unicode(response)) +> response = error500_view(request) +> self.assertEqual(response.status_code, 500) +> self.assertIn('500 Internal Server Error', unicode(response)) + + #@pytest.mark.django_db +> class NewUserRegistrationTest(TestCase): +> def setUp(self): +> self.c = Client() +! redis_connection.publish('tasks','KILL') + +! def test_newuser(self): +> form_data = { +> 'first_name':'Jan', +> 'last_name':'Roeiert', +> 'email':'jan@loop.nl', +> 'username':'janderoeiert', +> 'password1':'aapindewei2', +> 'password2':'aapindewei2', +> 'tos':True, +> 'weightcategory':'hwt', +> 'adaptiveclass': 'None', +> 'sex':'male', +> 'next':'/rowers/list-workouts', +> 'birthdate':datetime.datetime(year=1970,month=4,day=2) +> } + +> form = RegistrationFormUniqueEmail(form_data) +> self.assertTrue(form.is_valid()) + +! response = self.c.post('/rowers/register', form_data, follow=True) + +> self.assertRedirects(response, +> expected_url='/rowers/me/gdpr-optin/?next=/rowers/list-workouts/', +> status_code=302,target_status_code=200) + +> from django_mailbox.models import Mailbox,MessageAttachment,Message + + #@pytest.mark.django_db +> class AutoExportTests(TestCase): +! def setUp(self): +! redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> r = Rower.objects.create(user=u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +> r.c2_auto_export = True +> r.sporttracks_auto_export = True +> r.mapmyfitness_auto_export = True +> r.trainingpeaks_auto_export = True + +! r.save() + +! nu = datetime.datetime.now() +! workoutsbox = Mailbox.objects.create(name='workouts') +> workoutsbox.save() +! failbox = Mailbox.objects.create(name='Failed') +> failbox.save() + +> filename = 'testdata.csv' + +> m = Message(mailbox=workoutsbox, +> from_header = u.email, +> subject = filename, +> body=""" +> --- +> workouttype: water +> boattype: 2x +> ... +> """) +> m.save() +! a2 = 'media/mailbox_attachments/'+filename +! copyfile('rowers/tests/testdata/'+filename,a2) +> a = MessageAttachment(message=m,document=a2[6:]) +> a.save() + +> def tearDown(self): +> for filename in os.listdir('media/mailbox_attachments'): +! path = os.path.join('media/mailbox_attachments/',filename) +> if not os.path.isdir(path): +> try: +> os.remove(path) +> except WindowsError: +! pass + +! @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) +! @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) +! def test_emailprocessing(self, mock_post, mock_get): +> out = StringIO() +> call_command('processemail', stdout=out, testing=True) +> self.assertIn('Successfully processed email attachments',out.getvalue()) + + #@pytest.mark.django_db +> class UploadTests(TestCase): +! def setUp(self): +> redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> r = Rower.objects.create(user=u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +> nu = datetime.datetime.now() +> workoutsbox = Mailbox.objects.create(name='workouts') +> workoutsbox.save() +! failbox = Mailbox.objects.create(name='Failed') +! failbox.save() +> m = Message(mailbox=workoutsbox, +> from_header = u.email, +> subject = "3x(5min/2min)/r2 \r2", +> body = """ +> workout run +> """) +! m.save() +! a2 = 'media/mailbox_attachments/colin2.csv' +! copyfile('rowers/tests/testdata/emails/colin.csv',a2) +> a = MessageAttachment(message=m,document=a2[6:]) +! a.save() + +> def tearDown(self): +> for filename in os.listdir('media/mailbox_attachments'): +! path = os.path.join('media/mailbox_attachments/',filename) +! if not os.path.isdir(path): +! try: +> os.remove(path) +> except (IOError,WindowsError): +> pass + +> @patch('requests.get', side_effect=mocked_requests) +> def test_email_workouttype(self, mock_get): +> out = StringIO() +> call_command('processemail', stdout=out, testing=True) +! w = Workout.objects.get(id=1) +> self.assertEqual(w.workouttype,'Run') + + #@pytest.mark.django_db +> class EmailTests(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> r = Rower.objects.create(user=u,gdproptin=True, +> gdproptindate=timezone.now() +> ) + +! nu = datetime.datetime.now() +! workoutsbox = Mailbox.objects.create(name='workouts') +! workoutsbox.save() +! failbox = Mailbox.objects.create(name='Failed') +! failbox.save() + +! for filename in os.listdir(u'rowers/tests/testdata/emails'): +> m = Message(mailbox=workoutsbox, +> from_header = u.email, +> subject = filename, +> body=""" +> --- +> workouttype: water +> boattype: 4x +> ... +> """) +! m.save() +! a2 = 'media/mailbox_attachments/'+filename +! copyfile(u'rowers/tests/testdata/emails/'+filename,a2) +> a = MessageAttachment(message=m,document=a2[6:]) +> a.save() + +> m = Message(mailbox=workoutsbox, +> from_header = u.email, +> subject = "3x(5min/2min)/r2 \r2", +> body = """ +> workout water +> """) +> m.save() +! a2 = 'media/mailbox_attachments/colin2.csv' +! copyfile('rowers/tests/testdata/emails/colin.csv',a2) +> a = MessageAttachment(message=m,document=a2[6:]) +> a.save() + + +> def tearDown(self): +> for filename in os.listdir('media/mailbox_attachments'): +> path = os.path.join('media/mailbox_attachments/',filename) +> if not os.path.isdir(path): +> try: +> os.remove(path) +> except (IOError,WindowsError): +> pass + +> @patch('requests.get', side_effect=mocked_requests) +> def test_emailprocessing(self, mock_get): +> out = StringIO() +> call_command('processemail', stdout=out,testing=True) +! self.assertIn('Successfully processed email attachments',out.getvalue()) + + + #@pytest.mark.django_db +> class WorkoutTests(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) +> nu = datetime.datetime.now() +> self.w = Workout.objects.create(name='testworkout', +> workouttype='water', +> user=self.r,date=nu.strftime('%Y-%m-%d'), +> starttime=nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000) + +> def test_checkworkoutuser(self): +> self.assertEqual(checkworkoutuser(self.u,self.w),True) + + #@pytest.mark.django_db +> class C2Tests(TestCase): +> def setUp(self): +! redis_connection.publish('tasks','KILL') +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now() +> ) +> self.nu = datetime.datetime.now() +> self.w = Workout.objects.create(name='testworkout',workouttype='water', +> user=r,date=nu.strftime('%Y-%m-%d'), +> starttime=nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000) + +> def c2_notokentest(self): +! thetoken = c2_open(self.u) + # should raise NoTokenError +> self.assertRaises(NoTokenError) + + #@pytest.mark.django_db +> class DataTest(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> r = Rower.objects.create(user=u,gdproptin=True, +> gdproptindate=timezone.now() +> ) +! self.nu = datetime.datetime.now() + + +! def test_workoutform(self): +> form_data = { +> 'name':'test', +> 'date':'2016-05-01', +> 'starttime':'07:53:00', +> 'timezone':'UTC', +> 'duration':'0:55:00.1', +> 'distance':8000, +> 'notes':'Aap noot \n mies', +> 'weightcategory':'lwt', +> 'adaptiveclass': 'PR1', +> 'workouttype':'water', +> 'boattype':'1x', +> 'private':False, +> } +> form = WorkoutForm(data=form_data) +> self.assertTrue(form.is_valid()) + +> def test_rower_form_withvalidnumbers(self): +> form_data = { +> 'max':192, +> 'rest':48, +> 'ut2':105, +> 'ut1':148, +> 'at':160, +> 'tr':167, +> 'an':180, +> 'weightcategory':'lwt', +> } +> form = RowerForm(data=form_data) +> self.assertTrue(form.is_valid()) + + +> def test_rower_form_twoequalvalues(self): +> form_data = { +> 'max':192, +> 'rest':48, +> 'ut2':105, +> 'ut1':105, +> 'at':160, +> 'an':180, +> 'tr':167, +> 'weightcategory':'lwt', +> } +! form = RowerForm(data=form_data) +> self.assertFalse(form.is_valid()) + +! def test_rower_form_abovemaxallowed(self): +> form_data = { +> 'max':300, +> 'rest':48, +> 'ut2':105, +> 'ut1':148, +> 'at':160, +> 'an':180, +> 'tr':167, +> 'weightcategory':'lwt', +> } +> form = RowerForm(data=form_data) +> self.assertFalse(form.is_valid()) + +! def test_rower_form_wrongorder(self): +> form_data = { +> 'max':192, +> 'rest':48, +> 'ut2':20, +> 'ut1':148, +> 'at':160, +> 'an':180, +> 'tr':167, +> 'weightcategory':'lwt', +> } +> form = RowerForm(data=form_data) +! self.assertFalse(form.is_valid()) + +> def test_rower_form_belowminalloed(self): +> form_data = { +> 'max':192, +> 'rest':2, +> 'ut2':105, +> 'ut1':148, +> 'at':160, +> 'an':180, +> 'tr':167, +> 'weightcategory':'lwt', +> } +> form = RowerForm(data=form_data) +> self.assertFalse(form.is_valid()) + +> def test_rower_form_wrongorder2(self): +> form_data = { +> 'max':192, +> 'rest':48, +> 'ut2':105, +> 'ut1':170, +> 'at':160, +> 'an':180, +> 'tr':167, +> 'weightcategory':'lwt', +> } +! form = RowerForm(data=form_data) +! self.assertFalse(form.is_valid()) + +> def test_painsled(self): +> filename = 'rowers/tests/testdata/testdata.csv' +> f = open(filename,'rb') +> file_data = {'file': SimpleUploadedFile(f.name, f.read())} +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> } + +! form = DocumentsForm(form_data,file_data) +> self.assertTrue(form.is_valid()) + +! f.close() + +! u = User.objects.get(username='john') +! r = Rower.objects.get(user=u) + +> rr = rrower(hrmax=r.max,hrut2=r.ut2, +> hrut1=r.ut1,hrat=r.at, +> hrtr=r.tr,hran=r.an,ftp=r.ftp) +> row = rdata(filename,rower=rr) +! totaldist = row.df['cum_dist'].max() +> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +> hours = int(totaltime/3600.) +> minutes = int((totaltime - 3600.*hours)/60.) +> seconds = int(totaltime - 3600.*hours - 60.*minutes) +> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + +! workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +! workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +> w = Workout.objects.create(name='testworkout',workouttype='water', +> user=r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=workoutstarttime, +> duration=duration,distance=totaldist, +> csvfilename=filename) + + +> fig1 = plots.mkplot(row,'test') +! res = iplots.interactive_chart(w.id) +> res = iplots.interactive_chart(w.id,promember=1) +> res = iplots.interactive_bar_chart(w.id) +! res = iplots.interactive_bar_chart(w.id,promember=1) +> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', +> yparam1='pace',yparam2='hr') +! res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', +! yparam1='pace',yparam2='hr') +> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', +> yparam1='pace',yparam2='spm') +> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', +> yparam1='pace',yparam2='spm') + +> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', +> yparam1='pace',yparam2='hr') +> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', +> yparam1='pace',yparam2='hr') +> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', +> yparam1='pace',yparam2='spm') +> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', +> yparam1='pace',yparam2='spm') + + + + + #@pytest.mark.django_db +> class ViewTest(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +! self.c = Client() +> self.u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +> self.r = Rower.objects.create(user=self.u,gdproptin=True, +> gdproptindate=timezone.now(), +> rowerplan='coach', +> ) +! self.nu = datetime.datetime.now() + +! def test_upload_view_notloggedin(self): +! response = self.c.post('/rowers/workout/upload/',follow=True) + + +! self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', +! status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> def test_upload_view_sled(self): +! self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/testdata.csv' +! f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + +> f.close() + +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> response = self.c.get('/rowers/workout/1/', form_data, follow=True) +! self.assertEqual(response.status_code, 200) + +! response = self.c.get('/rowers/workout/1/edit', form_data, follow=True) +> self.assertEqual(response.status_code, 200) + + +> response = self.c.get('/rowers/workout/1/histo', form_data, follow=True) +! self.assertEqual(response.status_code, 200) + +> form_data = { +> 'name':'aap', +> 'date':'2016-11-05', +> 'starttime':'09:07:14', +> 'timezone':'Europe/Berlin', +> 'duration':'1:00:00.5', +> 'distance':'15000', +> 'weightcategory':'hwt', +> 'adaptiveclass':'PR1', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'private':True, +> 'notes':'noot mies', +> } +> form = WorkoutForm(data=form_data) +! self.assertTrue(form.is_valid()) +> response = self.c.post('/rowers/workout/1/edit', form_data, follow=True) +> self.assertEqual(response.status_code, 200) + + +> w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + + + +> def test_upload_view_notloggedin(self): +! response = self.c.post('/rowers/workout/upload/',follow=True) + + +> self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> def test_upload_view_sled_negativetime(self): +! self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/tim.csv' +> f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_C2':False, +> 'upload_to_Strava':False, +> 'upload_to_SportTracks':False, +> 'upload_to_RunKeeper':False, +> 'upload_to_MapMyFitness':False, +> 'plottype':'timeplot', +> 'file': f, +> 'makeprivate':False, +> 'landingpage':'workout_edit_view', +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + +! f.close() + +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> response = self.c.get('/rowers/workout/1/', form_data, follow=True) +! self.assertEqual(response.status_code, 200) + + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +> os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + + + + +! def test_upload_view_sled_noname(self): +! self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/testdata.csv' +! f = open(filename,'rb') +! file_data = {'file': f} +! form_data = { +! 'title':'', +! 'workouttype':'rower', +! 'boattype':'1x', +! 'notes':'aap noot mies', +! 'make_plot':False, +! 'upload_to_c2':False, +! 'plottype':'timeplot', +! 'file': f, +! } + +! form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + +! f.close() + +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) + +! self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + +! def test_upload_view_logcard(self): +! self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/logcard.csv' +! f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'', +> 'workouttype':'rower', +> 'boattype': '1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + +! f.close() + +> self.assertRedirects(response, +> expected_url='/rowers/workout/upload/', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + + + + +> def test_upload_view_TCX_CN(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/crewnerddata.tcx' +! f = open(filename,'rb') +! file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> filename = 'rowers/tests/testdata/crewnerddata.CSV' +> f = open(filename,'rb') +> file_data = {'file': f} +> form_data = {} +! form = CNsummaryForm(form_data,file_data) + +> response = self.c.post('rowers/workout/1/crewnerdsummary', +> form_data, +> follow=True) + +> f.close() + +! self.assertEqual(response.status_code, 200) +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +! pass + +> def test_upload_view_TCX_SpeedCoach2a(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/Speedcoach2example.csv' +> f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + +> def test_upload_view_TCX_SpeedCoach2b(self): +> self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/Speedcoach2example.csv' +> f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + + + +> def test_upload_view_TCX_SpeedCoach2c(self): +> self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/speedcoach3test3.csv' +> f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + + +! def test_upload_view_SpeedCoach2v127(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/SpeedCoach2Linkv1.27.csv' +! f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + + + +> def test_upload_view_SpeedCoach2v127intervals(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/SpeedCoach2Link_interval.csv' +> f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> f.close() +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) + +! self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +> pass + + + +> def test_upload_view_TCX_NoHR(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/NoHR.tcx' +> f = open(filename,'rb') +> file_data = {'file': f} + +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! f.close() +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) + +> self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + +> def test_upload_view_TCX_CN(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/rowinginmotionexample.tcx' +> f = open(filename,'rb') +! file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'water', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +> self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + +> def test_upload_view_RP(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/RP_testdata.csv' +> f = open(filename,'rb') +! file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +! self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + +> def test_upload_view_Mystery(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/mystery.csv' +> f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +> self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + +> def test_upload_view_RP_interval(self): +> self.c.login(username='john',password='koeinsloot') + +> filename = 'rowers/tests/testdata/RP_interval.csv' +> f = open(filename,'rb') +! file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) +> self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + + +> def test_upload_view_sled_desktop(self): +> self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/painsled_desktop_example.csv' +! f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +! form = DocumentsForm(form_data,file_data) + +> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +> status_code=302,target_status_code=200) +> self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + +> def test_upload_view_sled_ergdata(self): +> self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/ergdata_example.csv' +! f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +! form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +! self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +! try: +! os.remove(f_to_be_deleted+'.gz') +! except WindowsError: +! pass + +! def test_upload_view_sled_boatcoach(self): +! self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/boatcoach.csv' +! f = open(filename,'rb') +! file_data = {'file': f} +! form_data = { +! 'title':'test', +! 'workouttype':'rower', +! 'boattype':'1x', +! 'notes':'aap noot mies', +! 'make_plot':False, +! 'upload_to_c2':False, +! 'plottype':'timeplot', +! 'file': f, +! } + +! form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +! self.assertEqual(response.status_code, 200) + +> w = Workout.objects.get(id=1) +> f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + +> def test_upload_view_sled_ergstick(self): +> self.c.login(username='john',password='koeinsloot') + +! filename = 'rowers/tests/testdata/ergstick.csv' +> f = open(filename,'rb') +> file_data = {'file': f} +> form_data = { +> 'title':'test', +> 'workouttype':'rower', +> 'boattype':'1x', +> 'notes':'aap noot mies', +> 'make_plot':False, +> 'upload_to_c2':False, +> 'plottype':'timeplot', +> 'file': f, +> } + +> form = DocumentsForm(form_data,file_data) + +! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) +! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +! status_code=302,target_status_code=200) +! self.assertEqual(response.status_code, 200) + +! w = Workout.objects.get(id=1) +! f_to_be_deleted = w.csvfilename +> try: +> os.remove(f_to_be_deleted+'.gz') +> except WindowsError: +> pass + + + # def test_upload_view_FIT_SpeedCoach2a(self): + # self.c.login(username='john',password='koeinsloot') + + # filename = 'rowers/tests/testdata/3x250m.fit' + # with open(filename,'rb') as f: + + # file_data = {'file': f} + + # form_data = { + # 'title':'test', + # 'workouttype':'water', + # 'boattype':'1x', + # 'notes':'aap noot mies', + # 'make_plot':False, + # 'upload_to_c2':False, + # 'plottype':'timeplot', + # 'file': f, + # } + + # form = DocumentsForm(form_data,file_data) + + # response = self.c.post('/rowers/workout/upload/', + # form_data, follow=True, + # format='multipart') + # f.close() + # self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + # status_code=302,target_status_code=200) + + # self.assertEqual(response.status_code, 200) + + # w = Workout.objects.get(id=1) + # f_to_be_deleted = w.csvfilename + # os.remove(f_to_be_deleted+'.gz') + + #@pytest.mark.django_db +> class URLTests(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot', +> ) +> r = Rower.objects.create(user=u,rowerplan='coach') +> self.c = Client() +> self.c.login(username='john',password='koeinsloot') + +> self.nu = datetime.datetime.now() +> filename = 'rowers/tests/testdata/testdata.csv' +> self.wotw = Workout.objects.create(name='testworkout', +> workouttype='water', +> user=r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=self.nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000, +> csvfilename=filename) + +> self.wote = Workout.objects.create(name='testworkout', +> workouttype='Indoor Rower', +> user=r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=self.nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000, +> csvfilename=filename) + +> powerperc = 100*np.array([r.pw_ut2, +> r.pw_ut1, +> r.pw_at, +> r.pw_tr,r.pw_an])/r.ftp + + +> self.hrdata = { +> 'hrmax':r.max, +> 'hrut2':r.ut2, +> 'hrut1':r.ut1, +> 'hrat':r.at, +> 'hrtr':r.tr, +> 'hran':r.an, +> 'ftp':r.ftp, +> 'powerperc':serialize_list(powerperc), +> 'powerzones':serialize_list(r.powerzones), +> } + +> urlstotest = [ +> '/rowers/400/', +> '/rowers/403/', +> '/rowers/404/', +> '/rowers/500/', +> '/rowers/502/', +> '/rowers/1/list-workouts/', +> '/rowers/1/list-workouts/2016-01-01/2016-12-31', +> '/rowers/1/ote-bests/', +> '/rowers/1/ote-bests2/2016-01-01/2016-12-31', +> '/rowers/about', +> '/rowers/addmanual/', +> '/rowers/agegroupcp/30', +> '/rowers/agegroupcp/30/1', +> '/rowers/agegrouprecords/male/hwt', +> '/rowers/agegrouprecords/male/hwt/2000m', +> '/rowers/agegrouprecords/male/hwt/2000min', +> '/rowers/ajax_agegroup/45/hwt/male/1', +> '/rowers/analysis/', +> '/rowers/analysis/user/1', +> '/rowers/brochure', +> '/rowers/courses/upload', +> '/rowers/createplan/', +> '/rowers/createplan/user/1/', +> '/rowers/cumstats/', +> '/rowers/cumstats/2016-01-01/2016-12-31', +> '/rowers/cumstats/user/1', +> '/rowers/cumstats/user/1/2016-01-01/2016-12-31', +> '/rowers/developers', +> '/rowers/email/', +> '/rowers/email/thankyou/', +> '/rowers/fitness-progress/', +> '/rowers/fitness-progress/user/1', +> '/rowers/fitness-progress/user/1/rower', +> '/rowers/flexall/', +> '/rowers/flexall/spm/hr/None/', +> '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/', +> '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1', +> '/rowers/flexall/user/1/', +> '/rowers/flexalldata/', +> '/rowers/help', +> '/rowers/histo/', +> '/rowers/histo/user/1', +> '/rowers/histo/user/1/2016-01-01/2016-12-31', +> '/rowers/histodata', +> '/rowers/job-kill/1', +> '/rowers/jobs-status/', +> '/rowers/laboratory/', +> '/rowers/laboratory/user/1', +> '/rowers/legal', +> '/rowers/list-courses/', +> '/rowers/list-graphs/', +> '/rowers/list-jobs/', +> '/rowers/list-workouts/', +> '/rowers/list-workouts/2016-01-01/2016-12-31', +> '/rowers/list-workouts/2016-01-01/2016-12-31/user/1/', +> '/rowers/list-workouts/ranking', +> '/rowers/list-workouts/user/1/', +> '/rowers/me/calcdps/', +> '/rowers/me/edit/', +> '/rowers/me/edit/user/1', +> '/rowers/me/exportsettings/', +> '/rowers/me/exportsettings/user/1', +> '/rowers/me/favoritecharts/', +> '/rowers/me/favoritecharts/user/1', +> '/rowers/me/invitation/', +> '/rowers/me/preferences/', +> '/rowers/me/preferences/user/1', +> '/rowers/me/request/', +> '/rowers/me/teams/', +> '/rowers/me/workflowconfig2/', +> '/rowers/me/workflowconfig2/user/1', +> '/rowers/me/workflowdefault', +> '/rowers/multi-compare', +> '/rowers/ote-bests/', +> '/rowers/ote-bests/2016-01-01/2016-12-31', +> '/rowers/ote-bests/user/1', +> '/rowers/ote-bests/user/1/2016-01-01/2016-12-31', +> '/rowers/ote-bests2/', +> '/rowers/ote-bests2/2016-01-01/2016-12-31', +> '/rowers/ote-bests2/user/1', +> '/rowers/ote-ranking/', +> '/rowers/ote-ranking/2016-01-01/2016-12-31', +> '/rowers/ote-ranking/user/1/', +> '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31', +> '/rowers/otw-bests/', +> '/rowers/otw-bests/2016-01-01/2016-12-31', +> '/rowers/otw-bests/user/1/2016-01-01/2016-12-31', +> '/rowers/partners', +> '/rowers/physics', +> '/rowers/planrequired', +> '/rowers/promembership', +> '/rowers/register', +> '/rowers/register/thankyou/', +> '/rowers/sessions/', +> '/rowers/sessions/2016-01-01/2016-12-31', +> '/rowers/sessions/2016-01-01/2016-12-31/user/1', +> '/rowers/sessions/coach/', +> '/rowers/sessions/coach/user/1/', +> '/rowers/sessions/create/', +> '/rowers/sessions/create/user/1', +> '/rowers/sessions/manage/', +> '/rowers/sessions/manage/user/1/', +> '/rowers/sessions/multiclone/', +> '/rowers/sessions/multiclone/user/1/', +> '/rowers/sessions/multicreate/', +> '/rowers/sessions/multicreate/user/1/', +> '/rowers/sessions/print/', +> '/rowers/sessions/print/user/1', +> '/rowers/sessions/teamcreate/', +> '/rowers/sessions/user/1', +> '/rowers/team-compare-select/', +> '/rowers/team-compare-select/workout/1', +> '/rowers/team-compare-select/2016-01-01/2016-12-31', +> '/rowers/test-job/2', +> '/rowers/test-job2/2', +> '/rowers/test_callback', +> '/rowers/updatefitness', +> '/rowers/updatefitness/rower', +> '/rowers/updatefitness/rower/50', +> '/rowers/user-boxplot', +> '/rowers/user-boxplot-data', +> '/rowers/user-boxplot-select/', +> '/rowers/user-boxplot-select/user/1/', +> '/rowers/user-boxplot/user/1', +> '/rowers/user-multiflex-data', +> '/rowers/user-multiflex-select/', +> '/rowers/user-multiflex-select/2016-01-01/2016-12-31', +> '/rowers/user-multiflex-select/user/1/', +> '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31', +> '/rowers/user-multiflex/', +> '/rowers/user-multiflex/user/1', +> '/rowers/workout/1/', +> '/rowers/workout/1/adddistanceplot', +> '/rowers/workout/1/adddistanceplot2', +> '/rowers/workout/1/addotwpowerplot', +> '/rowers/workout/1/addpiechart', +> '/rowers/workout/1/addpowerpiechart', +> '/rowers/workout/1/addstatic', +> '/rowers/workout/1/addstatic/3', +> '/rowers/workout/1/addtimeplot', +> '/rowers/workout/1/addtimeplot2', +> '/rowers/workout/1/comment', +> '/rowers/workout/1/darkskywind', +> '/rowers/workout/1/data', +> '/rowers/workout/1/edit', +> '/rowers/workout/1/editintervals', +> '/rowers/workout/1/flexchart', +> '/rowers/workout/1/flexchart/spm/hr/None', +> '/rowers/workout/1/flexchart/spm/hr/None/scatter', +> '/rowers/workout/1/flexchart/spm/hr/None/scatter/', +> '/rowers/workout/1/forcecurve', +> '/rowers/workout/1/get-testscript', +> '/rowers/workout/1/get-thumbnails', +> '/rowers/workout/1/histo', +> '/rowers/workout/1/image', +> '/rowers/workout/1/instroke', +> '/rowers/workout/1/interactiveotwplot', +> '/rowers/workout/1/map', +> '/rowers/workout/1/otwsetpower', +> '/rowers/workout/1/recalcsummary/', +> '/rowers/workout/1/restore', +> '/rowers/workout/1/smoothenpace', +> '/rowers/workout/1/split', +> '/rowers/workout/1/stats', +> '/rowers/workout/1/stream', +> '/rowers/workout/1/task', +> '/rowers/workout/1/test_strokedata', +> '/rowers/workout/1/toggle-ranking', +> '/rowers/workout/1/undosmoothenpace', +> '/rowers/workout/1/unsubscribe', +> '/rowers/workout/1/updatecp', +> '/rowers/workout/1/view', +> '/rowers/workout/1/wind', +> '/rowers/workout/1/workflow', +> '/rowers/workout/compare/1/2016-01-01/2016-12-31', +> '/rowers/workout/fusion/1/', +> '/rowers/workout/fusion/1/2016-01-01/2016-12-31', +> '/rowers/workout/upload/', +> '/rowers/workout/upload/team/', +> '/rowers/workouts-join', +> '/rowers/workouts-join-select/', +> '/rowers/workouts-join-select/2016-01-01/2016-12-31', +> ] + +! lijst = [] +> for url in urlstotest: +> lijst.append( +> (url,200) +> ) + +> @parameterized.expand(lijst) +> def test_url_generator(self,url,expected): +> response = self.c.get(url,follow=True) +> if response.status_code != expected: +> print response.status_code +! self.assertEqual(response.status_code, +! expected, +! msg=url+' response status code not 200') + + + #@pytest.mark.django_db +> class subroutinetests(TestCase): +> def setUp(self): +> redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +! r = Rower.objects.create(user=u) +! nu = datetime.datetime.now() +> filename = 'rowers/tests/testdata/testdata.csv' +> self.w = Workout.objects.create(name='testworkout', +> workouttype='water', +> user=r,date=nu.strftime('%Y-%m-%d'), +> starttime=nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000, +> csvfilename=filename) + + +> def c2stuff(self): +> data = c2stuff.createc2workoutdata(self.w) +! jsond = json.dumps(data) +! data = c2stuff.createc2workoutdata_as_splits(w) +> jsond = json.dumps(data) + + + + #@pytest.mark.django_db +> class PlotTests(TestCase): +! def setUp(self): +! redis_connection.publish('tasks','KILL') +> u = User.objects.create_user('john', +> 'sander@ds.ds', +> 'koeinsloot') +! r = Rower.objects.create(user=u) +! self.nu = datetime.datetime.now() +> filename = 'rowers/tests/testdata/testdata.csv' +> self.wotw = Workout.objects.create(name='testworkout', +> workouttype='water', +> user=r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=self.nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000, +> csvfilename=filename) + +> self.wote = Workout.objects.create(name='testworkout', +> workouttype='Indoor Rower', +> user=r,date=self.nu.strftime('%Y-%m-%d'), +> starttime=self.nu.strftime('%H:%M:%S'), +> duration="0:55:00",distance=8000, +> csvfilename=filename) + + # timestr = strftime("%Y%m%d-%H%M%S") + # imagename = f1+timestr+'.png' + # fullpathimagename = 'static/plots/'+imagename +> powerperc = 100*np.array([r.pw_ut2, +> r.pw_ut1, +> r.pw_at, +> r.pw_tr,r.pw_an])/r.ftp + + +> self.hrdata = { +> 'hrmax':r.max, +> 'hrut2':r.ut2, +> 'hrut1':r.ut1, +> 'hrat':r.at, +> 'hrtr':r.tr, +> 'hran':r.an, +> 'ftp':r.ftp, +> 'powerperc':serialize_list(powerperc), +> 'powerzones':serialize_list(r.powerzones), +> } + + +! def test_ote_plots(self): +! w = self.wote +> f1 = 'testdata.csv'[:-4] +> timestr = strftime("%Y%m%d-%H%M%S") +> imagename = f1+timestr+'.png' +> fullpathimagename = 'static/plots/'+imagename + # make plot - asynchronous task +> plotnr = 1 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 1 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 2 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 3 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 4 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +! except WindowsError: +> pass + +> plotnr = 5 +! if (w.workouttype=='water'): +> plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +> pass + +> plotnr = 6 +! if (w.workouttype=='water'): +> plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +> pass + +> plotnr = 7 +! if (w.workouttype=='water'): +> plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +> pass + +> plotnr = 8 +! if (w.workouttype=='water'): +> plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +> pass + +> plotnr = 13 +! if (w.workouttype=='water'): +> plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +> pass + +> def test_otw_plots(self): +! w = self.wotw +> f1 = 'testdata.csv'[:-4] +> timestr = strftime("%Y%m%d-%H%M%S") +> imagename = f1+timestr+'.png' +> fullpathimagename = 'static/plots/'+imagename + # make plot - asynchronous task +> plotnr = 1 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 1 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 2 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 3 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 4 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +> res = handle_makeplot(f1,w.csvfilename, +> w.name,self.hrdata,plotnr,imagename) +> i = GraphImage(workout=w,creationdatetime=self.nu, +> filename=fullpathimagename) +> try: +> os.remove(fullpathimagename) +> except WindowsError: +> pass + +> plotnr = 5 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass + +! plotnr = 6 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass + +! plotnr = 7 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass + +! plotnr = 8 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass + +! plotnr = 9 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass + +! plotnr = 13 +! if (w.workouttype=='water'): +! plotnr = plotnr+3 + +! res = handle_makeplot(f1,w.csvfilename, +! w.name,self.hrdata,plotnr,imagename) +! i = GraphImage(workout=w,creationdatetime=self.nu, +! filename=fullpathimagename) +! try: +! os.remove(fullpathimagename) +! except WindowsError: +! pass From 670d2fc722911bdaceca2fdb0294f00a54d614b9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 2 Jan 2019 23:54:37 +0100 Subject: [PATCH 03/18] additional tests defined --- rowers/tests/__init__.py | 28 +- rowers/tests/test_emails.py | 157 ++++ rowers/tests/test_imports.py | 1083 ++++++++++++++++++++++++++ rowers/tests/test_models.py | 38 +- rowers/tests/test_urls.py | 294 +++++++ rowers/tests/test_user.py | 67 +- rowers/tests/tests.py | 1388 ---------------------------------- rowers/views.py | 8 + 8 files changed, 1625 insertions(+), 1438 deletions(-) create mode 100644 rowers/tests/test_emails.py create mode 100644 rowers/tests/test_imports.py create mode 100644 rowers/tests/test_urls.py diff --git a/rowers/tests/__init__.py b/rowers/tests/__init__.py index 613de3e3..8fd9adf2 100644 --- a/rowers/tests/__init__.py +++ b/rowers/tests/__init__.py @@ -1,21 +1,21 @@ pkg_mox = None -def setUpPackage(): - global pkg_mox - import urllib - import urllib2 - import mox - import requests - pkg_mox = mox.Mox() - pkg_mox.StubOutWithMock(requests.api.sessions.Session, 'send') - pkg_mox.StubOutWithMock(urllib.URLopener, 'open') - pkg_mox.StubOutWithMock(urllib2.OpenerDirector, 'open') - pkg_mox.ReplayAll() +# def setUpPackage(): +# global pkg_mox +# import urllib +# import urllib2 +# import mox +# import requests +# pkg_mox = mox.Mox() +# pkg_mox.StubOutWithMock(requests.api.sessions.Session, 'send') +# pkg_mox.StubOutWithMock(urllib.URLopener, 'open') +# pkg_mox.StubOutWithMock(urllib2.OpenerDirector, 'open') +# pkg_mox.ReplayAll() -def tearDownPackage(): - pkg_mox.VerifyAll() - pkg_mox.UnsetStubs() +#def tearDownPackage(): +# pkg_mox.VerifyAll() +# pkg_mox.UnsetStubs() from tests import * diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py new file mode 100644 index 00000000..ed0d5530 --- /dev/null +++ b/rowers/tests/test_emails.py @@ -0,0 +1,157 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import error500_view,error404_view,error400_view,error403_view + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +from rowers.tests.test_imports import mocked_requests + + +from django_mailbox.models import Mailbox,MessageAttachment,Message + + +#@pytest.mark.django_db +class UploadTests(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u,gdproptin=True, + gdproptindate=timezone.now() + ) + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + workoutsbox.save() + failbox = Mailbox.objects.create(name='Failed') + failbox.save() + m = Message(mailbox=workoutsbox, + from_header = u.email, + subject = "3x(5min/2min)/r2 \r2", + body = """ +workout run + """) + m.save() + a2 = 'media/mailbox_attachments/colin2.csv' + copyfile('rowers/tests/testdata/emails/colin.csv',a2) + a = MessageAttachment(message=m,document=a2[6:]) + a.save() + + def tearDown(self): + for filename in os.listdir('media/mailbox_attachments'): + path = os.path.join('media/mailbox_attachments/',filename) + if not os.path.isdir(path): + try: + os.remove(path) + except (IOError,WindowsError): + pass + + @patch('requests.get', side_effect=mocked_requests) + def test_email_workouttype(self, mock_get): + out = StringIO() + call_command('processemail', stdout=out, testing=True) + w = Workout.objects.get(id=1) + self.assertEqual(w.workouttype,'Run') + +#@pytest.mark.django_db +class EmailTests(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u,gdproptin=True, + gdproptindate=timezone.now() + ) + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + workoutsbox.save() + failbox = Mailbox.objects.create(name='Failed') + failbox.save() + + for filename in os.listdir(u'rowers/tests/testdata/emails'): + m = Message(mailbox=workoutsbox, + from_header = u.email, + subject = filename, + body=""" +--- +workouttype: water +boattype: 4x +... + """) + m.save() + a2 = 'media/mailbox_attachments/'+filename + copyfile(u'rowers/tests/testdata/emails/'+filename,a2) + a = MessageAttachment(message=m,document=a2[6:]) + a.save() + + m = Message(mailbox=workoutsbox, + from_header = u.email, + subject = "3x(5min/2min)/r2 \r2", + body = """ +workout water + """) + m.save() + a2 = 'media/mailbox_attachments/colin2.csv' + copyfile('rowers/tests/testdata/emails/colin.csv',a2) + a = MessageAttachment(message=m,document=a2[6:]) + a.save() + + + def tearDown(self): + for filename in os.listdir('media/mailbox_attachments'): + path = os.path.join('media/mailbox_attachments/',filename) + if not os.path.isdir(path): + try: + os.remove(path) + except (IOError,WindowsError): + pass + + @patch('requests.get', side_effect=mocked_requests) + def test_emailprocessing(self, mock_get): + out = StringIO() + call_command('processemail', stdout=out,testing=True) + self.assertIn('Successfully processed email attachments',out.getvalue()) + diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py new file mode 100644 index 00000000..b550cb71 --- /dev/null +++ b/rowers/tests/test_imports.py @@ -0,0 +1,1083 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import error500_view,error404_view,error400_view,error403_view + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +from django_mailbox.models import Mailbox,MessageAttachment,Message + +#@pytest.mark.django_db +class DjangoTestCase(TestCase, MockTestCase): + def _pre_setup(self): + MockTestCase.setUp(self) + TestCase._pre_setup(self) + self.client = Client() + + def _post_teardown(self): + TestCase._post_teardown(self) + MockTestCase.tearDown(self) + delete_strokedata(1) + +# to be done add polar mocks (for email processing) +def mocked_requests(*args, **kwargs): + with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: + c2workoutdata = json.load(infile) + + with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: + c2strokedata = json.load(infile) + + polar_json = { + 'available-user-data': [] + } + + c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) + + c2uploadjson = { + "data": { + "id": 339, + "user_id": 1, + "date": "2015-08-05 13:15:41", + "timezone": "Europe/London", + "date_utc": "2015-08-05 12:15:41", + "distance": 5649, + "type": "rower", + "time": 8649, + "time_formatted": "14:24.9", + "workout_type": "JustRow", + "source": "ErgData", + "weight_class": "H", + "verified": True, + "ranked": False + } + } + + stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) + sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) + + rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) + uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) + + stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) + + stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) + stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) + + stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) + + stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) + stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) + stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) + stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) + + uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) + + tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) + + stravastreamjson = { + 'time':stravatimejson, + 'velocity_smooth':stravavelojson, + 'distance':stravadistancejson, + 'latlng':stravalatlongjson, + 'heartrate':stravahrjson, + 'cadence':stravaspmjson, + 'power':stravapowerjson, + } + + ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) + + rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) + + uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) + uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) + + class MockResponse: + def __init__(self, json_data, status_code): + self.json_data = json_data + self.status_code = status_code + + def json(self): + return self.json_data + + + class MockHeaderResponse: + def __init__(self, header_data, status_code): + self.headers = header_data + self.status_code = status_code + + class MockSession: + def send(self,prepped): + # prepped.url + # prepped.body (post data) + # prepped.headers + # prepped.method + + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + + return MockResponse(json_data,200) + + if not args: + return MockSession() + + print args[0],'aap' + + polartester = re.compile('.*?polaraccesslink\.com') + c2tester = re.compile('.*?log\.concept2\.com') + stravatester = re.compile('.*?strava\.com') + sttester = re.compile('.*?sporttracks\.mobi') + rktester = re.compile('.*?runkeeper\.com') + uatester = re.compile('.*?mapmyfitness\.com') + tptester = re.compile('.*?trainingpeaks\.com') + + c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' + c2importtester = re.compile(c2importregex) + + c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' + c2uploadtester = re.compile(c2uploadregex) + + c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' + c2strokestester = re.compile(c2strokesregex) + + c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' + c2workoutlisttester = re.compile(c2workoutlistregex) + + stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' + stravaworkoutlisttester = re.compile(stravaworkoutlistregex) + + stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' + stravastreamtester = re.compile(stravastreamregex) + + stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' + stravasummarytester = re.compile(stravasummaryregex) + + stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' + stuploadtester = re.compile(stuploadregex) + + stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' + stworkoutlisttester = re.compile(stworkoutlistregex) + + ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' + ststrokestester = re.compile(ststrokesregex) + + rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' + rkuploadtester = re.compile(rkuploadregex) + rkuserregex = '.*?api\.runkeeper\.com\/user$' + rkusertester = re.compile(rkuserregex) + rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' + rkstrokestester = re.compile(rkstrokesregex) + + uaapiregex = '.*?api\.ua\.com' + uaapitester = re.compile(uaapiregex) + + uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' + uauploadtester = re.compile(uauploadregex) + + uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' + uastrokestester = re.compile(uastrokesregex) + + ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' + ualisttester = re.compile(ualistregex) + + uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' + uausertester = re.compile(uauserregex) + + tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' + tpuploadtester = re.compile(tpuploadregex) + + if polartester.match(args[0]): + json_data = polar_json + return MockResponse(json_data,200) + + if tptester.match(args[0]): + if 'token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif tpuploadtester.match(args[0]): + return MockResponse(tpuploadresponse,200) + + if uaapitester.match(args[0]): + if 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif uauploadtester.match(args[0]): + if 'data' in kwargs: + return MockResponse(uapostworkoutjson,200) + elif uastrokestester.match(args[0]): + return MockResponse(uastrokesjson,200) + elif ualisttester.match(args[0]): + return MockResponse(uaworkoutlistjson,200) + elif uausertester.match(args[0]): + return MockResponse(uauserjson,200) + + + if uatester.match(args[0]): + if 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + + + if rktester.match(args[0]): + if 'token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif rkuploadtester.match(args[0]): + if 'data' in kwargs: + # post + header_data = { + 'Location': '/fitnessActivities/12' + } + return MockHeaderResponse(header_data,200) + else: + json_data = rkworkoutlistjson + return MockResponse(json_data,200) + elif rkusertester.match(args[0]): + json_data = { + "userID": 1234567890, + "profile": "/profile", + "settings": "/settings", + "fitness_activities": "/fitnessActivities", + "strength_training_activities": "/strengthTrainingActivities", + "background_activities": "/backgroundActivities", + "sleep": "/sleep", + "nutrition": "/nutrition", + "weight": "/weight", + "general_measurements": "/generalMeasurements", + "diabetes": "/diabetes", + "records": "/records", + "team": "/team" + } + return MockResponse(json_data, 200) + elif rkstrokestester.match(args[0]): + return MockResponse(rkstrokesjson,200) + + if sttester.match(args[0]): + if 'oauth2/token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + if ststrokestester.match(args[0]): + return MockResponse(ststrokesjson,200) + if stuploadtester.match(args[0]): + json_data = { + "uris": [ + "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" + ] + } + return MockResponse(json_data, 200) + if stworkoutlisttester.match(args[0]): + return MockResponse(sporttracksworkoutlist,200) + + + if stravatester.match(args[0]): + if stravaworkoutlisttester.match(args[0]): + return MockResponse(stravaworkoutlist,200) + if stravastreamtester.match(args[0]): + metric = stravastreamtester.match(args[0]).group(1) + json_data = stravastreamjson[metric] + return MockResponse(json_data,200) + elif stravasummarytester.match(args[0]): + return MockResponse(stravasummaryjson,200) + elif 'token' in args[0]: + json_data = { + "token_type": "Bearer", + "access_token": "987654321234567898765432123456789", + "refresh_token": "1234567898765432112345678987654321", + "expires_at": 1531385304 + } + return MockResponse(json_data,200) + + + if c2tester.match(args[0]): + if c2uploadtester.match(args[0]): + return MockResponse(c2uploadjson,201) + if c2strokestester.match(args[0]): + return MockResponse(c2strokedata,200) + elif c2importtester.match(args[0]): + return MockResponse(c2workoutdata,200) + elif c2workoutlisttester.match(args[0]): + return MockResponse(c2workoutlist,200) + elif 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif 'users/me' in args[0]: + json_data = { + 'data': { + 'username': 'john', + 'id': 1234, + } + } + return MockResponse(json_data,200) + elif 'results' in args[0]: + json_data = { + 'data': { + 'id': 1223, + } + } + else: + return MockResponse(c2workoutdata,200) + + return MockResponse(None,412) + +#@pytest.mark.django_db +class C2Objects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + self.r.c2token = '12' + self.r.c2refreshtoken = 'ab' + self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.save() + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + + @patch('rowers.c2stuff.requests.Session', side_effect=mocked_requests) + def test_c2_callback(self, mock_Session): + response = self.c.get('/call_back?code=dsdoij232s',follow=True) + + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.c2stuff.Session', side_effect=mocked_requests) + def test_c2_token_refresh(self, mock_post): + response = self.c.get('/rowers/me/c2refresh/',follow=True) + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_upload(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/1/c2uploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.status_code, 302) + + @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_list(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/c2list',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_import(self, mock_get): + + response = self.c.get('/rowers/workout/c2import/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/2/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + + def test_strokedata(self): + with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile: + res = json.load(infile) + + strokedata = pd.DataFrame.from_dict(res['data']) + + with open('rowers/tests/testdata/c2testdata.txt','r') as infile: + res = json.load(infile) + + data = res['data'] + + from rowers.views import add_workout_from_strokedata + + res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') + + def test_strokedatanohr(self): + with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile: + res = json.load(infile) + + strokedata = pd.DataFrame.from_dict(res['data']) + + with open('rowers/tests/testdata/c2testdata.txt','r') as infile: + res = json.load(infile) + + data = res['data'] + + from rowers.views import add_workout_from_strokedata + + + res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') + +class C2ObjectsTokenExpired(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + self.r.c2token = '12' + self.r.c2refreshtoken = 'ab' + self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) + self.r.save() + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + + + @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_list(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/c2list',follow=True) + + self.assertEqual(response.status_code,404) + + @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) + def test_c2_import(self, mock_get): + + response = self.c.get('/rowers/workout/c2import/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/list-workouts/', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + + +#@pytest.mark.django_db +class StravaObjects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + self.r.stravatoken = '12' + + self.r.save() + self.c.login(username='john',password='koeinsloot') + + @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) + def test_strava_list(self, mock_get): + response = self.c.get('/rowers/workout/stravaimport/',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.utils.requests.get', side_effect=mocked_requests) + def test_strava_import(self, mock_get): + + response = self.c.get('/rowers/workout/stravaimport/12',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/1/edit', + status_code=301,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + + +#@pytest.mark.django_db +class STObjects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + + self.r.sporttrackstoken = '12' + self.r.sporttracksrefreshtoken = '12' + self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.save() + + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) + def test_sporttracks_callback(self, mock_post): + response = self.c.get('/sporttracks_callback?code=dsdoij232s',follow=True) + + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) + def test_sporttracks_token_refresh(self, mock_post): + response = self.c.get('/rowers/me/sporttracksrefresh/',follow=True) + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) + @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) + def test_sporttracks_upload(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/1/sporttracksuploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.status_code, 302) + + @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) + def test_sporttracks_list(self, mock_get): + response = self.c.get('/rowers/workout/sporttracksimport',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.imports.requests.get', side_effect=mocked_requests) + def test_sporttracks_import(self, mock_get): + + response = self.c.get('/rowers/workout/sporttracksimport/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/2/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + def test_strokedata(self): + with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile: + data = json.load(infile) + + from rowers.sporttracksstuff import add_workout_from_data + + res = add_workout_from_data(self.u,1,data,data) + + def test_strokedatanohr(self): + with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile: + data = json.load(infile) + + from rowers.sporttracksstuff import add_workout_from_data + + + + res = add_workout_from_data(self.u,1,data,data) + +#@pytest.mark.django_db +class RunKeeperObjects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + + self.r.runkeepertoken = '12' + + self.r.save() + + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) + def test_runkeeper_callback(self, mock_post): + response = self.c.get('/runkeeper_callback?code=dsdoij232s',follow=True) + + self.assertEqual(response.status_code, 200) + + @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) + @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) + def test_runkeeper_upload(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/1/runkeeperuploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.status_code, 302) + + @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) + def test_runkeeper_list(self, mock_get): + response = self.c.get('/rowers/workout/runkeeperimport',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.imports.requests.get', side_effect=mocked_requests) + def test_runkeeper_import(self, mock_get): + + response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/2/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + + +#@pytest.mark.django_db +class UAObjects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + + self.r.underarmourtoken = '12' + self.r.underarmourrefreshtoken = '12' + self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.save() + + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + @patch('rowers.imports.requests.post', side_effect=mocked_requests) + def test_underarmour_callback(self, mock_post): + response = self.c.get('/underarmour_callback?code=dsdoij232s',follow=True) + + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) + def test_underarmour_token_refresh(self, mock_post): + response = self.c.get('/rowers/me/underarmourrefresh/',follow=True) + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) + @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) + def test_underarmour_upload(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/1/underarmouruploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.status_code, 302) + + @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) + def test_underarmour_list(self, mock_get): + response = self.c.get('/rowers/workout/underarmourimport',follow=True) + + self.assertEqual(response.status_code,200) + + @patch('rowers.imports.requests.get', side_effect=mocked_requests) + def test_underarmour_import(self, mock_get): + + response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) + + self.assertRedirects(response, + expected_url='/rowers/workout/2/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + +#@pytest.mark.django_db +class TPObjects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True, + gdproptindate=timezone.now() + ) + + + self.r.tptoken = '12' + self.r.tprefreshtoken = '12' + self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.save() + + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + @patch('rowers.imports.requests.post', side_effect=mocked_requests) + def test_tp_callback(self, mock_post): + response = self.c.get('/tp_callback?code=dsdoij232s',follow=True) + + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) + def test_tp_token_refresh(self, mock_post): + response = self.c.get('/rowers/me/tprefresh/',follow=True) + + self.assertEqual(response.status_code, 200) + + + @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) + @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) + def test_tp_upload(self, mock_get, mock_post): + response = self.c.get('/rowers/workout/1/tpuploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.status_code, 302) + + +#@pytest.mark.django_db +class AutoExportTests(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u,gdproptin=True, + gdproptindate=timezone.now() + ) + + r.c2_auto_export = True + r.sporttracks_auto_export = True + r.mapmyfitness_auto_export = True + r.trainingpeaks_auto_export = True + + r.save() + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + workoutsbox.save() + failbox = Mailbox.objects.create(name='Failed') + failbox.save() + + filename = 'testdata.csv' + + m = Message(mailbox=workoutsbox, + from_header = u.email, + subject = filename, + body=""" +--- +workouttype: water +boattype: 2x +... + """) + m.save() + a2 = 'media/mailbox_attachments/'+filename + copyfile('rowers/tests/testdata/'+filename,a2) + a = MessageAttachment(message=m,document=a2[6:]) + a.save() + + def tearDown(self): + for filename in os.listdir('media/mailbox_attachments'): + path = os.path.join('media/mailbox_attachments/',filename) + if not os.path.isdir(path): + try: + os.remove(path) + except WindowsError: + pass + + @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) + @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) + def test_emailprocessing(self, mock_post, mock_get): + out = StringIO() + call_command('processemail', stdout=out, testing=True) + self.assertIn('Successfully processed email attachments',out.getvalue()) diff --git a/rowers/tests/test_models.py b/rowers/tests/test_models.py index 42f9bf71..a054bbb7 100644 --- a/rowers/tests/test_models.py +++ b/rowers/tests/test_models.py @@ -2,13 +2,47 @@ from django.test import TestCase from rowers.models import * class FormTests(TestCase): - def SetUp(self): + def setUp(self): self.u = User.objects.create_user('john', 'sander@ds.ds', 'koeinsloot') - r = Rower.objects.create(user=u) + r = Rower.objects.create(user=self.u) def test_form(self): form = TeamInviteForm() + + +class ModelTests(TestCase): + def setUp(self): + self.u = User.objects.create_user('john', + 'Sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'Sander' + self.u.last_name = 'Roosendaal' + self.u.save() + + self.r = Rower.objects.create(user=self.u) + + def create_team(self): + return Team.objects.create( + name = 'test team', + manager = self.u, + ) + + def create_paidplan(self): + return PaidPlan.objects.create( + name = 'test plan', + shortname = 'pro', + price = 15.0, + ) + + def test_models(self): + pp = self.create_paidplan() + team = self.create_team() + self.assertEqual(u'%s' % pp,u'test plan - pro at 15.00 EURO (single payment)') + self.assertEqual(u'%s' % self.r, u'Sander Roosendaal') + self.assertEqual('%s' % self.r, 'Sander Roosendaal') + self.assertEqual(self.r.clean_email(),'sander@ds.ds') diff --git a/rowers/tests/test_urls.py b/rowers/tests/test_urls.py new file mode 100644 index 00000000..012a8bc4 --- /dev/null +++ b/rowers/tests/test_urls.py @@ -0,0 +1,294 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import error500_view,error404_view,error400_view,error403_view + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + + +#@pytest.mark.django_db +class URLTests(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot', + ) + r = Rower.objects.create(user=u,rowerplan='coach') + self.c = Client() + self.c.login(username='john',password='koeinsloot') + + self.nu = datetime.datetime.now() + filename = 'rowers/tests/testdata/testdata.csv' + self.wotw = Workout.objects.create(name='testworkout', + workouttype='water', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=filename) + + self.wote = Workout.objects.create(name='testworkout', + workouttype='Indoor Rower', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=filename) + + powerperc = 100*np.array([r.pw_ut2, + r.pw_ut1, + r.pw_at, + r.pw_tr,r.pw_an])/r.ftp + + + self.hrdata = { + 'hrmax':r.max, + 'hrut2':r.ut2, + 'hrut1':r.ut1, + 'hrat':r.at, + 'hrtr':r.tr, + 'hran':r.an, + 'ftp':r.ftp, + 'powerperc':serialize_list(powerperc), + 'powerzones':serialize_list(r.powerzones), + } + + urlstotest = [ + '/rowers/400/', + '/rowers/403/', + '/rowers/404/', + '/rowers/500/', + '/rowers/502/', + '/rowers/1/list-workouts/', + '/rowers/1/list-workouts/2016-01-01/2016-12-31', + '/rowers/1/ote-bests/', + '/rowers/1/ote-bests2/2016-01-01/2016-12-31', + '/rowers/about', + '/rowers/addmanual/', + '/rowers/agegroupcp/30', + '/rowers/agegroupcp/30/1', + '/rowers/agegrouprecords/male/hwt', + '/rowers/agegrouprecords/male/hwt/2000m', + '/rowers/agegrouprecords/male/hwt/2000min', + '/rowers/ajax_agegroup/45/hwt/male/1', + '/rowers/analysis/', + '/rowers/analysis/user/1', + '/rowers/brochure', + '/rowers/courses/upload', + '/rowers/createplan/', + '/rowers/createplan/user/1/', + '/rowers/cumstats/', + '/rowers/cumstats/2016-01-01/2016-12-31', + '/rowers/cumstats/user/1', + '/rowers/cumstats/user/1/2016-01-01/2016-12-31', + '/rowers/developers', + '/rowers/email/', + '/rowers/email/thankyou/', + '/rowers/fitness-progress/', + '/rowers/fitness-progress/user/1', + '/rowers/fitness-progress/user/1/rower', + '/rowers/flexall/', + '/rowers/flexall/spm/hr/None/', + '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/', + '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1', + '/rowers/flexall/user/1/', + '/rowers/flexalldata/', + '/rowers/help', + '/rowers/histo/', + '/rowers/histo/user/1', + '/rowers/histo/user/1/2016-01-01/2016-12-31', + '/rowers/histodata', + '/rowers/job-kill/1', + '/rowers/jobs-status/', + '/rowers/laboratory/', + '/rowers/laboratory/user/1', + '/rowers/legal', + '/rowers/list-courses/', + '/rowers/list-graphs/', + '/rowers/list-jobs/', + '/rowers/list-workouts/', + '/rowers/list-workouts/2016-01-01/2016-12-31', + '/rowers/list-workouts/2016-01-01/2016-12-31/user/1/', + '/rowers/list-workouts/ranking', + '/rowers/list-workouts/user/1/', + '/rowers/me/calcdps/', + '/rowers/me/edit/', + '/rowers/me/edit/user/1', + '/rowers/me/exportsettings/', + '/rowers/me/exportsettings/user/1', + '/rowers/me/favoritecharts/', + '/rowers/me/favoritecharts/user/1', + '/rowers/me/invitation/', + '/rowers/me/preferences/', + '/rowers/me/preferences/user/1', + '/rowers/me/request/', + '/rowers/me/teams/', + '/rowers/me/workflowconfig2/', + '/rowers/me/workflowconfig2/user/1', + '/rowers/me/workflowdefault', + '/rowers/multi-compare', + '/rowers/ote-bests/', + '/rowers/ote-bests/2016-01-01/2016-12-31', + '/rowers/ote-bests/user/1', + '/rowers/ote-bests/user/1/2016-01-01/2016-12-31', + '/rowers/ote-bests2/', + '/rowers/ote-bests2/2016-01-01/2016-12-31', + '/rowers/ote-bests2/user/1', + '/rowers/ote-ranking/', + '/rowers/ote-ranking/2016-01-01/2016-12-31', + '/rowers/ote-ranking/user/1/', + '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31', + '/rowers/otw-bests/', + '/rowers/otw-bests/2016-01-01/2016-12-31', + '/rowers/otw-bests/user/1/2016-01-01/2016-12-31', + '/rowers/partners', + '/rowers/physics', + '/rowers/planrequired', + '/rowers/promembership', + '/rowers/register', + '/rowers/register/thankyou/', + '/rowers/sessions/', + '/rowers/sessions/2016-01-01/2016-12-31', + '/rowers/sessions/2016-01-01/2016-12-31/user/1', + '/rowers/sessions/coach/', + '/rowers/sessions/coach/user/1/', + '/rowers/sessions/create/', + '/rowers/sessions/create/user/1', + '/rowers/sessions/manage/', + '/rowers/sessions/manage/user/1/', + '/rowers/sessions/multiclone/', + '/rowers/sessions/multiclone/user/1/', + '/rowers/sessions/multicreate/', + '/rowers/sessions/multicreate/user/1/', + '/rowers/sessions/print/', + '/rowers/sessions/print/user/1', + '/rowers/sessions/teamcreate/', + '/rowers/sessions/user/1', + '/rowers/team-compare-select/', + '/rowers/team-compare-select/workout/1', + '/rowers/team-compare-select/2016-01-01/2016-12-31', + '/rowers/test-job/2', + '/rowers/test-job2/2', + '/rowers/test_callback', + '/rowers/updatefitness', + '/rowers/updatefitness/rower', + '/rowers/updatefitness/rower/50', + '/rowers/user-boxplot', + '/rowers/user-boxplot-data', + '/rowers/user-boxplot-select/', + '/rowers/user-boxplot-select/user/1/', + '/rowers/user-boxplot/user/1', + '/rowers/user-multiflex-data', + '/rowers/user-multiflex-select/', + '/rowers/user-multiflex-select/2016-01-01/2016-12-31', + '/rowers/user-multiflex-select/user/1/', + '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31', + '/rowers/user-multiflex/', + '/rowers/user-multiflex/user/1', + '/rowers/workout/1/', + '/rowers/workout/1/adddistanceplot', + '/rowers/workout/1/adddistanceplot2', + '/rowers/workout/1/addotwpowerplot', + '/rowers/workout/1/addpiechart', + '/rowers/workout/1/addpowerpiechart', + '/rowers/workout/1/addstatic', + '/rowers/workout/1/addstatic/3', + '/rowers/workout/1/addtimeplot', + '/rowers/workout/1/addtimeplot2', + '/rowers/workout/1/comment', + '/rowers/workout/1/darkskywind', + '/rowers/workout/1/data', + '/rowers/workout/1/edit', + '/rowers/workout/1/editintervals', + '/rowers/workout/1/flexchart', + '/rowers/workout/1/flexchart/spm/hr/None', + '/rowers/workout/1/flexchart/spm/hr/None/scatter', + '/rowers/workout/1/flexchart/spm/hr/None/scatter/', + '/rowers/workout/1/forcecurve', + '/rowers/workout/1/get-testscript', + '/rowers/workout/1/get-thumbnails', + '/rowers/workout/1/histo', + '/rowers/workout/1/image', + '/rowers/workout/1/instroke', + '/rowers/workout/1/interactiveotwplot', + '/rowers/workout/1/map', + '/rowers/workout/1/otwsetpower', + '/rowers/workout/1/recalcsummary/', + '/rowers/workout/1/restore', + '/rowers/workout/1/smoothenpace', + '/rowers/workout/1/split', + '/rowers/workout/1/stats', + '/rowers/workout/1/stream', + '/rowers/workout/1/task', + '/rowers/workout/1/test_strokedata', + '/rowers/workout/1/toggle-ranking', + '/rowers/workout/1/undosmoothenpace', + '/rowers/workout/1/unsubscribe', + '/rowers/workout/1/updatecp', + '/rowers/workout/1/view', + '/rowers/workout/1/wind', + '/rowers/workout/1/workflow', + '/rowers/workout/compare/1/2016-01-01/2016-12-31', + '/rowers/workout/fusion/1/', + '/rowers/workout/fusion/1/2016-01-01/2016-12-31', + '/rowers/workout/upload/', + '/rowers/workout/upload/team/', + '/rowers/workouts-join', + '/rowers/workouts-join-select/', + '/rowers/workouts-join-select/2016-01-01/2016-12-31', + ] + + lijst = [] + for url in urlstotest: + lijst.append( + (url,200) + ) + + @parameterized.expand(lijst) + def test_url_generator(self,url,expected): + response = self.c.get(url,follow=True) + if response.status_code != expected: + print response.status_code + self.assertEqual(response.status_code, + expected, + msg=url+' response status code not 200') + + diff --git a/rowers/tests/test_user.py b/rowers/tests/test_user.py index 3a91de7d..e7426321 100644 --- a/rowers/tests/test_user.py +++ b/rowers/tests/test_user.py @@ -19,6 +19,8 @@ import rowers.dataprep as dataprep from redis import StrictRedis redis_connection = StrictRedis() +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower from rowers.models import User,Rower, Workout @@ -27,51 +29,48 @@ class UserMiddleWareTest(TestCase): u = User.objects.create_user('john', 'sander@ds.ds', 'koeinsloot') - r = Rower.objects.create(user=u) + self.r = Rower.objects.create(user=u) self.c = Client() self.c.login(username='john',password='koeinsloot') - nu = datetime.datetime.now() + self.nu = datetime.datetime.now() - response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', - title='sample') + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - newworkoutid = response[0] - self.w = Workout.objects.get(id=newworkoutid) + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) def test_middleware(self): response = self.c.get('/rowers/list-workouts',follow=True) self.assertEqual(response.status_code,200) -class UserExpireTest(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - yesterday_dt = timezone.now()-datetime.timedelta(days=1) - yesterday = yesterday_dt.date() - - r = Rower.objects.create(user=self.u,planexpires = yesterday,rowerplan='pro', - paymenttype='single') - - self.c = Client() - self.c.login(username='john',password='koeinsloot') - nu = datetime.datetime.now() - - response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', - title='sample') - - newworkoutid = response[0] - self.w = Workout.objects.get(id=newworkoutid) - - - def test_expire(self): - response = self.c.get('/rowers/list-workouts',follow=True) - self.assertEqual(response.status_code,200) - self.assertEqual(self.u.rower.rowerplan,'basic') class UserTestsNoRower(TestCase): def setUp(self): diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index ee207208..e51b9a7f 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -44,984 +44,6 @@ from rowers.dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() -#@pytest.mark.django_db -class DjangoTestCase(TestCase, MockTestCase): - def _pre_setup(self): - MockTestCase.setUp(self) - TestCase._pre_setup(self) - self.client = Client() - - def _post_teardown(self): - TestCase._post_teardown(self) - MockTestCase.tearDown(self) - delete_strokedata(1) - -# to be done add polar mocks (for email processing) -def mocked_requests(*args, **kwargs): - with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: - c2workoutdata = json.load(infile) - - with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: - c2strokedata = json.load(infile) - - polar_json = { - 'available-user-data': [] - } - - c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) - - c2uploadjson = { - "data": { - "id": 339, - "user_id": 1, - "date": "2015-08-05 13:15:41", - "timezone": "Europe/London", - "date_utc": "2015-08-05 12:15:41", - "distance": 5649, - "type": "rower", - "time": 8649, - "time_formatted": "14:24.9", - "workout_type": "JustRow", - "source": "ErgData", - "weight_class": "H", - "verified": True, - "ranked": False - } - } - - stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) - sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) - - rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) - uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) - - stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) - - stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) - stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) - - stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) - - stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) - stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) - stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) - stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) - - uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) - - tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) - - stravastreamjson = { - 'time':stravatimejson, - 'velocity_smooth':stravavelojson, - 'distance':stravadistancejson, - 'latlng':stravalatlongjson, - 'heartrate':stravahrjson, - 'cadence':stravaspmjson, - 'power':stravapowerjson, - } - - ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) - - rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) - - uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) - uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) - - class MockResponse: - def __init__(self, json_data, status_code): - self.json_data = json_data - self.status_code = status_code - - def json(self): - return self.json_data - - - class MockHeaderResponse: - def __init__(self, header_data, status_code): - self.headers = header_data - self.status_code = status_code - - class MockSession: - def send(self,prepped): - # prepped.url - # prepped.body (post data) - # prepped.headers - # prepped.method - - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - - return MockResponse(json_data,200) - - if not args: - return MockSession() - - polartester = re.compile('.*?polaraccesslink\.com') - c2tester = re.compile('.*?log\.concept2\.com') - stravatester = re.compile('.*?strava\.com') - sttester = re.compile('.*?sporttracks\.mobi') - rktester = re.compile('.*?runkeeper\.com') - uatester = re.compile('.*?mapmyfitness\.com') - tptester = re.compile('.*?trainingpeaks\.com') - - c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' - c2importtester = re.compile(c2importregex) - - c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' - c2uploadtester = re.compile(c2uploadregex) - - c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' - c2strokestester = re.compile(c2strokesregex) - - c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' - c2workoutlisttester = re.compile(c2workoutlistregex) - - stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' - stravaworkoutlisttester = re.compile(stravaworkoutlistregex) - - stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' - stravastreamtester = re.compile(stravastreamregex) - - stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' - stravasummarytester = re.compile(stravasummaryregex) - - stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' - stuploadtester = re.compile(stuploadregex) - - stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' - stworkoutlisttester = re.compile(stworkoutlistregex) - - ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' - ststrokestester = re.compile(ststrokesregex) - - rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' - rkuploadtester = re.compile(rkuploadregex) - rkuserregex = '.*?api\.runkeeper\.com\/user$' - rkusertester = re.compile(rkuserregex) - rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' - rkstrokestester = re.compile(rkstrokesregex) - - uaapiregex = '.*?api\.ua\.com' - uaapitester = re.compile(uaapiregex) - - uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' - uauploadtester = re.compile(uauploadregex) - - uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' - uastrokestester = re.compile(uastrokesregex) - - ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' - ualisttester = re.compile(ualistregex) - - uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' - uausertester = re.compile(uauserregex) - - tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' - tpuploadtester = re.compile(tpuploadregex) - - if polartester.match(args[0]): - json_data = polar_json - return MockResponse(json_data,200) - - if tptester.match(args[0]): - if 'token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif tpuploadtester.match(args[0]): - return MockResponse(tpuploadresponse,200) - - if uaapitester.match(args[0]): - if 'access_token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif uauploadtester.match(args[0]): - if 'data' in kwargs: - return MockResponse(uapostworkoutjson,200) - elif uastrokestester.match(args[0]): - return MockResponse(uastrokesjson,200) - elif ualisttester.match(args[0]): - return MockResponse(uaworkoutlistjson,200) - elif uausertester.match(args[0]): - return MockResponse(uauserjson,200) - - - if uatester.match(args[0]): - if 'access_token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - - - if rktester.match(args[0]): - if 'token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif rkuploadtester.match(args[0]): - if 'data' in kwargs: - # post - header_data = { - 'Location': '/fitnessActivities/12' - } - return MockHeaderResponse(header_data,200) - else: - json_data = rkworkoutlistjson - return MockResponse(json_data,200) - elif rkusertester.match(args[0]): - json_data = { - "userID": 1234567890, - "profile": "/profile", - "settings": "/settings", - "fitness_activities": "/fitnessActivities", - "strength_training_activities": "/strengthTrainingActivities", - "background_activities": "/backgroundActivities", - "sleep": "/sleep", - "nutrition": "/nutrition", - "weight": "/weight", - "general_measurements": "/generalMeasurements", - "diabetes": "/diabetes", - "records": "/records", - "team": "/team" - } - return MockResponse(json_data, 200) - elif rkstrokestester.match(args[0]): - return MockResponse(rkstrokesjson,200) - - if sttester.match(args[0]): - if 'oauth2/token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - if ststrokestester.match(args[0]): - return MockResponse(ststrokesjson,200) - if stuploadtester.match(args[0]): - json_data = { - "uris": [ - "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" - ] - } - return MockResponse(json_data, 200) - if stworkoutlisttester.match(args[0]): - return MockResponse(sporttracksworkoutlist,200) - - - if stravatester.match(args[0]): - if stravaworkoutlisttester.match(args[0]): - return MockResponse(stravaworkoutlist,200) - if stravastreamtester.match(args[0]): - metric = stravastreamtester.match(args[0]).group(1) - json_data = stravastreamjson[metric] - return MockResponse(json_data,200) - elif stravasummarytester.match(args[0]): - return MockResponse(stravasummaryjson,200) - elif 'token' in args[0]: - json_data = { - "token_type": "Bearer", - "access_token": "987654321234567898765432123456789", - "refresh_token": "1234567898765432112345678987654321", - "expires_at": 1531385304 - } - return MockResponse(json_data,200) - - - if c2tester.match(args[0]): - if c2uploadtester.match(args[0]): - return MockResponse(c2uploadjson,201) - if c2strokestester.match(args[0]): - return MockResponse(c2strokedata,200) - elif c2importtester.match(args[0]): - return MockResponse(c2workoutdata,200) - elif c2workoutlisttester.match(args[0]): - return MockResponse(c2workoutlist,200) - elif 'access_token' in args[0]: - print 'aap' - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif 'users/me' in args[0]: - json_data = { - 'data': { - 'username': 'john', - 'id': 1234, - } - } - return MockResponse(json_data,200) - elif 'results' in args[0]: - json_data = { - 'data': { - 'id': 1223, - } - } - else: - return MockResponse(c2workoutdata,200) - - return MockResponse(None,404) - -#@pytest.mark.django_db -class C2Objects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - self.r.c2token = '12' - self.r.c2refreshtoken = 'ab' - self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) - self.r.save() - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - - @patch('rowers.c2stuff.requests.Session', side_effect=mocked_requests) - def test_c2_callback(self, mock_Session): - response = self.c.get('/call_back?code=dsdoij232s',follow=True) - - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.c2stuff.Session', side_effect=mocked_requests) - def test_c2_token_refresh(self, mock_post): - response = self.c.get('/rowers/me/c2refresh/',follow=True) - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/1/c2uploadw/') - - self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.url, '/rowers/workout/1/edit') - self.assertEqual(response.status_code, 302) - - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_list(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/c2list',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_import(self, mock_get): - - response = self.c.get('/rowers/workout/c2import/12/',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - - def test_strokedata(self): - with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile: - res = json.load(infile) - - strokedata = pd.DataFrame.from_dict(res['data']) - - with open('rowers/tests/testdata/c2testdata.txt','r') as infile: - res = json.load(infile) - - data = res['data'] - - from rowers.views import add_workout_from_strokedata - - res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') - - def test_strokedatanohr(self): - with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile: - res = json.load(infile) - - strokedata = pd.DataFrame.from_dict(res['data']) - - with open('rowers/tests/testdata/c2testdata.txt','r') as infile: - res = json.load(infile) - - data = res['data'] - - from rowers.views import add_workout_from_strokedata - - - res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') - -class C2ObjectsTokenExpired(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - self.r.c2token = '12' - self.r.c2refreshtoken = 'ab' - self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) - self.r.save() - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - - - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_list(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/c2list',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_import(self, mock_get): - - response = self.c.get('/rowers/workout/c2import/12/',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - - -#@pytest.mark.django_db -class StravaObjects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - self.r.stravatoken = '12' - - self.r.save() - self.c.login(username='john',password='koeinsloot') - - @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) - def test_strava_list(self, mock_get): - response = self.c.get('/rowers/workout/stravaimport/',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.utils.requests.get', side_effect=mocked_requests) - def test_strava_import(self, mock_get): - - response = self.c.get('/rowers/workout/stravaimport/12',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/1/edit', - status_code=301,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - - -#@pytest.mark.django_db -class STObjects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - - self.r.sporttrackstoken = '12' - self.r.sporttracksrefreshtoken = '12' - self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) - self.r.save() - - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) - def test_sporttracks_callback(self, mock_post): - response = self.c.get('/sporttracks_callback?code=dsdoij232s',follow=True) - - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) - def test_sporttracks_token_refresh(self, mock_post): - response = self.c.get('/rowers/me/sporttracksrefresh/',follow=True) - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) - def test_sporttracks_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/1/sporttracksuploadw/') - - self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.url, '/rowers/workout/1/edit') - self.assertEqual(response.status_code, 302) - - @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) - def test_sporttracks_list(self, mock_get): - response = self.c.get('/rowers/workout/sporttracksimport',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.imports.requests.get', side_effect=mocked_requests) - def test_sporttracks_import(self, mock_get): - - response = self.c.get('/rowers/workout/sporttracksimport/12/',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - def test_strokedata(self): - with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile: - data = json.load(infile) - - from rowers.sporttracksstuff import add_workout_from_data - - res = add_workout_from_data(self.u,1,data,data) - - def test_strokedatanohr(self): - with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile: - data = json.load(infile) - - from rowers.sporttracksstuff import add_workout_from_data - - - - res = add_workout_from_data(self.u,1,data,data) - -#@pytest.mark.django_db -class RunKeeperObjects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - - self.r.runkeepertoken = '12' - - self.r.save() - - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) - def test_runkeeper_callback(self, mock_post): - response = self.c.get('/runkeeper_callback?code=dsdoij232s',follow=True) - - self.assertEqual(response.status_code, 200) - - @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) - def test_runkeeper_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/1/runkeeperuploadw/') - - self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.url, '/rowers/workout/1/edit') - self.assertEqual(response.status_code, 302) - - @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) - def test_runkeeper_list(self, mock_get): - response = self.c.get('/rowers/workout/runkeeperimport',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.imports.requests.get', side_effect=mocked_requests) - def test_runkeeper_import(self, mock_get): - - response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - - -#@pytest.mark.django_db -class UAObjects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - - self.r.underarmourtoken = '12' - self.r.underarmourrefreshtoken = '12' - self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) - self.r.save() - - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - @patch('rowers.imports.requests.post', side_effect=mocked_requests) - def test_underarmour_callback(self, mock_post): - response = self.c.get('/underarmour_callback?code=dsdoij232s',follow=True) - - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) - def test_underarmour_token_refresh(self, mock_post): - response = self.c.get('/rowers/me/underarmourrefresh/',follow=True) - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) - def test_underarmour_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/1/underarmouruploadw/') - - self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.url, '/rowers/workout/1/edit') - self.assertEqual(response.status_code, 302) - - @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) - def test_underarmour_list(self, mock_get): - response = self.c.get('/rowers/workout/underarmourimport',follow=True) - - self.assertEqual(response.status_code,200) - - @patch('rowers.imports.requests.get', side_effect=mocked_requests) - def test_underarmour_import(self, mock_get): - - response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) - - self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - -#@pytest.mark.django_db -class TPObjects(DjangoTestCase): - def setUp(self): - self.c = Client() - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - - self.u.first_name = 'John' - self.u.last_name = 'Sander' - self.u.save() - self.r = Rower.objects.create(user=self.u,gdproptin=True, - gdproptindate=timezone.now() - ) - - - self.r.tptoken = '12' - self.r.tprefreshtoken = '12' - self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) - self.r.save() - - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - - filename = 'rowers/tests/testdata/testdata.csv' - - rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, - hrut1=self.r.ut1,hrat=self.r.at, - hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - self.w = Workout.objects.create( - name='testworkout',workouttype='water', - user=self.r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - startdatetime=row.rowdatetime, - duration=duration,distance=totaldist, - csvfilename=filename - ) - - @patch('rowers.imports.requests.post', side_effect=mocked_requests) - def test_tp_callback(self, mock_post): - response = self.c.get('/tp_callback?code=dsdoij232s',follow=True) - - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) - def test_tp_token_refresh(self, mock_post): - response = self.c.get('/rowers/me/tprefresh/',follow=True) - - self.assertEqual(response.status_code, 200) - - - @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) - def test_tp_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/1/tpuploadw/') - - self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.url, '/rowers/workout/1/edit') - self.assertEqual(response.status_code, 302) - - #@pytest.mark.django_db @@ -1070,170 +92,6 @@ class NewUserRegistrationTest(TestCase): expected_url='/rowers/me/gdpr-optin/?next=/rowers/list-workouts/', status_code=302,target_status_code=200) -from django_mailbox.models import Mailbox,MessageAttachment,Message - -#@pytest.mark.django_db -class AutoExportTests(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True, - gdproptindate=timezone.now() - ) - - r.c2_auto_export = True - r.sporttracks_auto_export = True - r.mapmyfitness_auto_export = True - r.trainingpeaks_auto_export = True - - r.save() - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - filename = 'testdata.csv' - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = filename, - body=""" ---- -workouttype: water -boattype: 2x -... - """) - m.save() - a2 = 'media/mailbox_attachments/'+filename - copyfile('rowers/tests/testdata/'+filename,a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except WindowsError: - pass - - @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) - def test_emailprocessing(self, mock_post, mock_get): - out = StringIO() - call_command('processemail', stdout=out, testing=True) - self.assertIn('Successfully processed email attachments',out.getvalue()) - -#@pytest.mark.django_db -class UploadTests(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True, - gdproptindate=timezone.now() - ) - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "3x(5min/2min)/r2 \r2", - body = """ -workout run - """) - m.save() - a2 = 'media/mailbox_attachments/colin2.csv' - copyfile('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,WindowsError): - pass - - @patch('requests.get', side_effect=mocked_requests) - def test_email_workouttype(self, mock_get): - out = StringIO() - call_command('processemail', stdout=out, testing=True) - w = Workout.objects.get(id=1) - self.assertEqual(w.workouttype,'Run') - -#@pytest.mark.django_db -class EmailTests(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True, - gdproptindate=timezone.now() - ) - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - for filename in os.listdir(u'rowers/tests/testdata/emails'): - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = filename, - body=""" ---- -workouttype: water -boattype: 4x -... - """) - m.save() - a2 = 'media/mailbox_attachments/'+filename - copyfile(u'rowers/tests/testdata/emails/'+filename,a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "3x(5min/2min)/r2 \r2", - body = """ -workout water - """) - m.save() - a2 = 'media/mailbox_attachments/colin2.csv' - copyfile('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,WindowsError): - pass - - @patch('requests.get', side_effect=mocked_requests) - def test_emailprocessing(self, mock_get): - out = StringIO() - call_command('processemail', stdout=out,testing=True) - self.assertIn('Successfully processed email attachments',out.getvalue()) - #@pytest.mark.django_db class WorkoutTests(TestCase): @@ -2225,252 +1083,6 @@ class ViewTest(TestCase): # f_to_be_deleted = w.csvfilename # os.remove(f_to_be_deleted+'.gz') -#@pytest.mark.django_db -class URLTests(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot', - ) - r = Rower.objects.create(user=u,rowerplan='coach') - self.c = Client() - self.c.login(username='john',password='koeinsloot') - - self.nu = datetime.datetime.now() - filename = 'rowers/tests/testdata/testdata.csv' - self.wotw = Workout.objects.create(name='testworkout', - workouttype='water', - user=r,date=self.nu.strftime('%Y-%m-%d'), - starttime=self.nu.strftime('%H:%M:%S'), - duration="0:55:00",distance=8000, - csvfilename=filename) - - self.wote = Workout.objects.create(name='testworkout', - workouttype='Indoor Rower', - user=r,date=self.nu.strftime('%Y-%m-%d'), - starttime=self.nu.strftime('%H:%M:%S'), - duration="0:55:00",distance=8000, - csvfilename=filename) - - powerperc = 100*np.array([r.pw_ut2, - r.pw_ut1, - r.pw_at, - r.pw_tr,r.pw_an])/r.ftp - - - self.hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - 'ftp':r.ftp, - 'powerperc':serialize_list(powerperc), - 'powerzones':serialize_list(r.powerzones), - } - - urlstotest = [ - '/rowers/400/', - '/rowers/403/', - '/rowers/404/', - '/rowers/500/', - '/rowers/502/', - '/rowers/1/list-workouts/', - '/rowers/1/list-workouts/2016-01-01/2016-12-31', - '/rowers/1/ote-bests/', - '/rowers/1/ote-bests2/2016-01-01/2016-12-31', - '/rowers/about', - '/rowers/addmanual/', - '/rowers/agegroupcp/30', - '/rowers/agegroupcp/30/1', - '/rowers/agegrouprecords/male/hwt', - '/rowers/agegrouprecords/male/hwt/2000m', - '/rowers/agegrouprecords/male/hwt/2000min', - '/rowers/ajax_agegroup/45/hwt/male/1', - '/rowers/analysis/', - '/rowers/analysis/user/1', - '/rowers/brochure', - '/rowers/courses/upload', - '/rowers/createplan/', - '/rowers/createplan/user/1/', - '/rowers/cumstats/', - '/rowers/cumstats/2016-01-01/2016-12-31', - '/rowers/cumstats/user/1', - '/rowers/cumstats/user/1/2016-01-01/2016-12-31', - '/rowers/developers', - '/rowers/email/', - '/rowers/email/thankyou/', - '/rowers/fitness-progress/', - '/rowers/fitness-progress/user/1', - '/rowers/fitness-progress/user/1/rower', - '/rowers/flexall/', - '/rowers/flexall/spm/hr/None/', - '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/', - '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1', - '/rowers/flexall/user/1/', - '/rowers/flexalldata/', - '/rowers/help', - '/rowers/histo/', - '/rowers/histo/user/1', - '/rowers/histo/user/1/2016-01-01/2016-12-31', - '/rowers/histodata', - '/rowers/job-kill/1', - '/rowers/jobs-status/', - '/rowers/laboratory/', - '/rowers/laboratory/user/1', - '/rowers/legal', - '/rowers/list-courses/', - '/rowers/list-graphs/', - '/rowers/list-jobs/', - '/rowers/list-workouts/', - '/rowers/list-workouts/2016-01-01/2016-12-31', - '/rowers/list-workouts/2016-01-01/2016-12-31/user/1/', - '/rowers/list-workouts/ranking', - '/rowers/list-workouts/user/1/', - '/rowers/me/calcdps/', - '/rowers/me/edit/', - '/rowers/me/edit/user/1', - '/rowers/me/exportsettings/', - '/rowers/me/exportsettings/user/1', - '/rowers/me/favoritecharts/', - '/rowers/me/favoritecharts/user/1', - '/rowers/me/invitation/', - '/rowers/me/preferences/', - '/rowers/me/preferences/user/1', - '/rowers/me/request/', - '/rowers/me/teams/', - '/rowers/me/workflowconfig2/', - '/rowers/me/workflowconfig2/user/1', - '/rowers/me/workflowdefault', - '/rowers/multi-compare', - '/rowers/ote-bests/', - '/rowers/ote-bests/2016-01-01/2016-12-31', - '/rowers/ote-bests/user/1', - '/rowers/ote-bests/user/1/2016-01-01/2016-12-31', - '/rowers/ote-bests2/', - '/rowers/ote-bests2/2016-01-01/2016-12-31', - '/rowers/ote-bests2/user/1', - '/rowers/ote-ranking/', - '/rowers/ote-ranking/2016-01-01/2016-12-31', - '/rowers/ote-ranking/user/1/', - '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31', - '/rowers/otw-bests/', - '/rowers/otw-bests/2016-01-01/2016-12-31', - '/rowers/otw-bests/user/1/2016-01-01/2016-12-31', - '/rowers/partners', - '/rowers/physics', - '/rowers/planrequired', - '/rowers/promembership', - '/rowers/register', - '/rowers/register/thankyou/', - '/rowers/sessions/', - '/rowers/sessions/2016-01-01/2016-12-31', - '/rowers/sessions/2016-01-01/2016-12-31/user/1', - '/rowers/sessions/coach/', - '/rowers/sessions/coach/user/1/', - '/rowers/sessions/create/', - '/rowers/sessions/create/user/1', - '/rowers/sessions/manage/', - '/rowers/sessions/manage/user/1/', - '/rowers/sessions/multiclone/', - '/rowers/sessions/multiclone/user/1/', - '/rowers/sessions/multicreate/', - '/rowers/sessions/multicreate/user/1/', - '/rowers/sessions/print/', - '/rowers/sessions/print/user/1', - '/rowers/sessions/teamcreate/', - '/rowers/sessions/user/1', - '/rowers/team-compare-select/', - '/rowers/team-compare-select/workout/1', - '/rowers/team-compare-select/2016-01-01/2016-12-31', - '/rowers/test-job/2', - '/rowers/test-job2/2', - '/rowers/test_callback', - '/rowers/updatefitness', - '/rowers/updatefitness/rower', - '/rowers/updatefitness/rower/50', - '/rowers/user-boxplot', - '/rowers/user-boxplot-data', - '/rowers/user-boxplot-select/', - '/rowers/user-boxplot-select/user/1/', - '/rowers/user-boxplot/user/1', - '/rowers/user-multiflex-data', - '/rowers/user-multiflex-select/', - '/rowers/user-multiflex-select/2016-01-01/2016-12-31', - '/rowers/user-multiflex-select/user/1/', - '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31', - '/rowers/user-multiflex/', - '/rowers/user-multiflex/user/1', - '/rowers/workout/1/', - '/rowers/workout/1/adddistanceplot', - '/rowers/workout/1/adddistanceplot2', - '/rowers/workout/1/addotwpowerplot', - '/rowers/workout/1/addpiechart', - '/rowers/workout/1/addpowerpiechart', - '/rowers/workout/1/addstatic', - '/rowers/workout/1/addstatic/3', - '/rowers/workout/1/addtimeplot', - '/rowers/workout/1/addtimeplot2', - '/rowers/workout/1/comment', - '/rowers/workout/1/darkskywind', - '/rowers/workout/1/data', - '/rowers/workout/1/edit', - '/rowers/workout/1/editintervals', - '/rowers/workout/1/flexchart', - '/rowers/workout/1/flexchart/spm/hr/None', - '/rowers/workout/1/flexchart/spm/hr/None/scatter', - '/rowers/workout/1/flexchart/spm/hr/None/scatter/', - '/rowers/workout/1/forcecurve', - '/rowers/workout/1/get-testscript', - '/rowers/workout/1/get-thumbnails', - '/rowers/workout/1/histo', - '/rowers/workout/1/image', - '/rowers/workout/1/instroke', - '/rowers/workout/1/interactiveotwplot', - '/rowers/workout/1/map', - '/rowers/workout/1/otwsetpower', - '/rowers/workout/1/recalcsummary/', - '/rowers/workout/1/restore', - '/rowers/workout/1/smoothenpace', - '/rowers/workout/1/split', - '/rowers/workout/1/stats', - '/rowers/workout/1/stream', - '/rowers/workout/1/task', - '/rowers/workout/1/test_strokedata', - '/rowers/workout/1/toggle-ranking', - '/rowers/workout/1/undosmoothenpace', - '/rowers/workout/1/unsubscribe', - '/rowers/workout/1/updatecp', - '/rowers/workout/1/view', - '/rowers/workout/1/wind', - '/rowers/workout/1/workflow', - '/rowers/workout/compare/1/2016-01-01/2016-12-31', - '/rowers/workout/fusion/1/', - '/rowers/workout/fusion/1/2016-01-01/2016-12-31', - '/rowers/workout/upload/', - '/rowers/workout/upload/team/', - '/rowers/workouts-join', - '/rowers/workouts-join-select/', - '/rowers/workouts-join-select/2016-01-01/2016-12-31', - ] - - lijst = [] - for url in urlstotest: - lijst.append( - (url,200) - ) - - @parameterized.expand(lijst) - def test_url_generator(self,url,expected): - response = self.c.get(url,follow=True) - if response.status_code != expected: - print response.status_code - self.assertEqual(response.status_code, - expected, - msg=url+' response status code not 200') - #@pytest.mark.django_db class subroutinetests(TestCase): diff --git a/rowers/views.py b/rowers/views.py index 63c691da..77299f11 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11812,6 +11812,14 @@ def workout_getimportview(request,externalid,source = 'c2'): # Now works only for C2 + try: + if strokedata == 0: + messages.error(request,'An error occurred importing the workout from Concept2') + url = reverse(workouts_view) + return HttpResponseRedirect(url) + except ValueError: + pass + if strokedata.empty: distance = data['distance'] c2id = data['id'] From f442e179baeebdf85f07bfde8b086e4c060c6e1e Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 00:18:59 +0100 Subject: [PATCH 04/18] renamed emails --- rowers/management/commands/processemail.py | 2 +- rowers/tests/test_imports.py | 9 ++++----- rowers/tests/test_emails.py => test_zemails.py | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) rename rowers/tests/test_emails.py => test_zemails.py (97%) diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 36f3553c..8a891e60 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -98,7 +98,7 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False): imagename=imagename ) try: - if workoutid: + if workoutid and not testing: if rower.getemailnotifications and not rower.emailbounced: email_sent = send_confirm( rower.user, title, link, diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index b550cb71..7b0afb3d 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -162,8 +162,6 @@ def mocked_requests(*args, **kwargs): if not args: return MockSession() - print args[0],'aap' - polartester = re.compile('.*?polaraccesslink\.com') c2tester = re.compile('.*?log\.concept2\.com') stravatester = re.compile('.*?strava\.com') @@ -439,7 +437,7 @@ class C2Objects(DjangoTestCase): ) - @patch('rowers.c2stuff.requests.Session', side_effect=mocked_requests) + @patch('rowers.c2stuff.Session', side_effect=mocked_requests) def test_c2_callback(self, mock_Session): response = self.c.get('/call_back?code=dsdoij232s',follow=True) @@ -448,7 +446,7 @@ class C2Objects(DjangoTestCase): @patch('rowers.c2stuff.Session', side_effect=mocked_requests) - def test_c2_token_refresh(self, mock_post): + def test_c2_token_refresh(self, mock_Session): response = self.c.get('/rowers/me/c2refresh/',follow=True) self.assertEqual(response.status_code, 200) @@ -573,7 +571,8 @@ class C2ObjectsTokenExpired(DjangoTestCase): @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_list(self, mock_get, mock_post): + @patch('rowers.c2stuff.Session',side_effect=mocked_requests) + def test_c2_list(self, mock_get, mock_post, mock_Session): response = self.c.get('/rowers/workout/c2list',follow=True) self.assertEqual(response.status_code,404) diff --git a/rowers/tests/test_emails.py b/test_zemails.py similarity index 97% rename from rowers/tests/test_emails.py rename to test_zemails.py index ed0d5530..d339236d 100644 --- a/rowers/tests/test_emails.py +++ b/test_zemails.py @@ -58,7 +58,8 @@ class UploadTests(TestCase): 'sander@ds.ds', 'koeinsloot') r = Rower.objects.create(user=u,gdproptin=True, - gdproptindate=timezone.now() + gdproptindate=timezone.now(), + getemailnotifications = False, ) nu = datetime.datetime.now() From c7a293b35bb47fb90e983497bf49ce0747fdb28d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 00:22:22 +0100 Subject: [PATCH 05/18] test_zemails moved to tests folder --- test_zemails.py => rowers/tests/test_zemails.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test_zemails.py => rowers/tests/test_zemails.py (100%) diff --git a/test_zemails.py b/rowers/tests/test_zemails.py similarity index 100% rename from test_zemails.py rename to rowers/tests/test_zemails.py From d86329ad2e4d2589e25f3c129ebd6cf5c56adf90 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 00:25:32 +0100 Subject: [PATCH 06/18] token refresh test --- rowers/tests/test_imports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 7b0afb3d..091663d1 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -380,7 +380,7 @@ def mocked_requests(*args, **kwargs): else: return MockResponse(c2workoutdata,200) - return MockResponse(None,412) + return MockResponse(None,404) #@pytest.mark.django_db class C2Objects(DjangoTestCase): @@ -575,7 +575,7 @@ class C2ObjectsTokenExpired(DjangoTestCase): def test_c2_list(self, mock_get, mock_post, mock_Session): response = self.c.get('/rowers/workout/c2list',follow=True) - self.assertEqual(response.status_code,404) + self.assertEqual(response.status_code,200) @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) def test_c2_import(self, mock_get): From c006c0599a8c3ea9773958676b7fb8ade2b1ff7b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 09:03:50 +0100 Subject: [PATCH 07/18] patching sqlalchemy to make tests work --- rowers/tests/mocks.py | 418 +++++++++++++++++++++++++++++++++++ rowers/tests/test_imports.py | 353 +---------------------------- rowers/tests/test_zemails.py | 7 +- 3 files changed, 435 insertions(+), 343 deletions(-) create mode 100644 rowers/tests/mocks.py diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py new file mode 100644 index 00000000..afd73bb1 --- /dev/null +++ b/rowers/tests/mocks.py @@ -0,0 +1,418 @@ +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import ( + error500_view,error404_view,error400_view,error403_view + ) + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +from django_mailbox.models import Mailbox,MessageAttachment,Message + +def mocked_sqlalchemy(*args, **kwargs): + # return object with method + + class MockEngine: + def connect(self): + return MockConnection() + + def dispose(self): + return True + + def raw_connection(self): + return True + + class MockConnection: + def begin(self): + return True + + def execute(self): + return True + + def execute(self): + return True + + def close(self): + return True + + def __exit__(self, *args, **kwargs): + return True + + def __enter__(self, *args, **kwargs): + return True + + return MockEngine() + +#@pytest.mark.django_db +class DjangoTestCase(TestCase, MockTestCase): + def _pre_setup(self): + MockTestCase.setUp(self) + TestCase._pre_setup(self) + self.client = Client() + + def _post_teardown(self): + TestCase._post_teardown(self) + MockTestCase.tearDown(self) + delete_strokedata(1) + +# to be done add polar mocks (for email processing) +def mocked_requests(*args, **kwargs): + with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: + c2workoutdata = json.load(infile) + + with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: + c2strokedata = json.load(infile) + + polar_json = { + 'available-user-data': [] + } + + c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) + + c2uploadjson = { + "data": { + "id": 339, + "user_id": 1, + "date": "2015-08-05 13:15:41", + "timezone": "Europe/London", + "date_utc": "2015-08-05 12:15:41", + "distance": 5649, + "type": "rower", + "time": 8649, + "time_formatted": "14:24.9", + "workout_type": "JustRow", + "source": "ErgData", + "weight_class": "H", + "verified": True, + "ranked": False + } + } + + stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) + sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) + + rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) + uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) + + stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) + + stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) + stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) + + stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) + + stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) + stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) + stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) + stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) + + uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) + + tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) + + stravastreamjson = { + 'time':stravatimejson, + 'velocity_smooth':stravavelojson, + 'distance':stravadistancejson, + 'latlng':stravalatlongjson, + 'heartrate':stravahrjson, + 'cadence':stravaspmjson, + 'power':stravapowerjson, + } + + ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) + + rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) + + uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) + uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) + + class MockResponse: + def __init__(self, json_data, status_code): + self.json_data = json_data + self.status_code = status_code + + def json(self): + return self.json_data + + + class MockHeaderResponse: + def __init__(self, header_data, status_code): + self.headers = header_data + self.status_code = status_code + + class MockSession: + def send(self,prepped): + # prepped.url + # prepped.body (post data) + # prepped.headers + # prepped.method + + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + + return MockResponse(json_data,200) + + if not args: + return MockSession() + + polartester = re.compile('.*?polaraccesslink\.com') + c2tester = re.compile('.*?log\.concept2\.com') + stravatester = re.compile('.*?strava\.com') + sttester = re.compile('.*?sporttracks\.mobi') + rktester = re.compile('.*?runkeeper\.com') + uatester = re.compile('.*?mapmyfitness\.com') + tptester = re.compile('.*?trainingpeaks\.com') + + c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' + c2importtester = re.compile(c2importregex) + + c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' + c2uploadtester = re.compile(c2uploadregex) + + c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' + c2strokestester = re.compile(c2strokesregex) + + c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' + c2workoutlisttester = re.compile(c2workoutlistregex) + + stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' + stravaworkoutlisttester = re.compile(stravaworkoutlistregex) + + stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' + stravastreamtester = re.compile(stravastreamregex) + + stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' + stravasummarytester = re.compile(stravasummaryregex) + + stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' + stuploadtester = re.compile(stuploadregex) + + stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' + stworkoutlisttester = re.compile(stworkoutlistregex) + + ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' + ststrokestester = re.compile(ststrokesregex) + + rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' + rkuploadtester = re.compile(rkuploadregex) + rkuserregex = '.*?api\.runkeeper\.com\/user$' + rkusertester = re.compile(rkuserregex) + rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' + rkstrokestester = re.compile(rkstrokesregex) + + uaapiregex = '.*?api\.ua\.com' + uaapitester = re.compile(uaapiregex) + + uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' + uauploadtester = re.compile(uauploadregex) + + uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' + uastrokestester = re.compile(uastrokesregex) + + ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' + ualisttester = re.compile(ualistregex) + + uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' + uausertester = re.compile(uauserregex) + + tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' + tpuploadtester = re.compile(tpuploadregex) + + if polartester.match(args[0]): + json_data = polar_json + return MockResponse(json_data,200) + + if tptester.match(args[0]): + if 'token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif tpuploadtester.match(args[0]): + return MockResponse(tpuploadresponse,200) + + if uaapitester.match(args[0]): + if 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif uauploadtester.match(args[0]): + if 'data' in kwargs: + return MockResponse(uapostworkoutjson,200) + elif uastrokestester.match(args[0]): + return MockResponse(uastrokesjson,200) + elif ualisttester.match(args[0]): + return MockResponse(uaworkoutlistjson,200) + elif uausertester.match(args[0]): + return MockResponse(uauserjson,200) + + + if uatester.match(args[0]): + if 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + + + if rktester.match(args[0]): + if 'token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif rkuploadtester.match(args[0]): + if 'data' in kwargs: + # post + header_data = { + 'Location': '/fitnessActivities/12' + } + return MockHeaderResponse(header_data,200) + else: + json_data = rkworkoutlistjson + return MockResponse(json_data,200) + elif rkusertester.match(args[0]): + json_data = { + "userID": 1234567890, + "profile": "/profile", + "settings": "/settings", + "fitness_activities": "/fitnessActivities", + "strength_training_activities": "/strengthTrainingActivities", + "background_activities": "/backgroundActivities", + "sleep": "/sleep", + "nutrition": "/nutrition", + "weight": "/weight", + "general_measurements": "/generalMeasurements", + "diabetes": "/diabetes", + "records": "/records", + "team": "/team" + } + return MockResponse(json_data, 200) + elif rkstrokestester.match(args[0]): + return MockResponse(rkstrokesjson,200) + + if sttester.match(args[0]): + if 'oauth2/token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + if ststrokestester.match(args[0]): + return MockResponse(ststrokesjson,200) + if stuploadtester.match(args[0]): + json_data = { + "uris": [ + "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" + ] + } + return MockResponse(json_data, 200) + if stworkoutlisttester.match(args[0]): + return MockResponse(sporttracksworkoutlist,200) + + + if stravatester.match(args[0]): + if stravaworkoutlisttester.match(args[0]): + return MockResponse(stravaworkoutlist,200) + if stravastreamtester.match(args[0]): + metric = stravastreamtester.match(args[0]).group(1) + json_data = stravastreamjson[metric] + return MockResponse(json_data,200) + elif stravasummarytester.match(args[0]): + return MockResponse(stravasummaryjson,200) + elif 'token' in args[0]: + json_data = { + "token_type": "Bearer", + "access_token": "987654321234567898765432123456789", + "refresh_token": "1234567898765432112345678987654321", + "expires_at": 1531385304 + } + return MockResponse(json_data,200) + + + if c2tester.match(args[0]): + if c2uploadtester.match(args[0]): + return MockResponse(c2uploadjson,201) + if c2strokestester.match(args[0]): + return MockResponse(c2strokedata,200) + elif c2importtester.match(args[0]): + return MockResponse(c2workoutdata,200) + elif c2workoutlisttester.match(args[0]): + return MockResponse(c2workoutlist,200) + elif 'access_token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + elif 'users/me' in args[0]: + json_data = { + 'data': { + 'username': 'john', + 'id': 1234, + } + } + return MockResponse(json_data,200) + elif 'results' in args[0]: + json_data = { + 'data': { + 'id': 1223, + } + } + else: + return MockResponse(c2workoutdata,200) + + return MockResponse(None,404) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 091663d1..1e84168c 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -37,7 +37,9 @@ import json import numpy as np from rowers import urls -from rowers.views import error500_view,error404_view,error400_view,error403_view +from rowers.views import ( + error500_view,error404_view,error400_view,error403_view + ) from rowers.dataprep import delete_strokedata @@ -46,343 +48,9 @@ redis_connection = StrictRedis() from django_mailbox.models import Mailbox,MessageAttachment,Message -#@pytest.mark.django_db -class DjangoTestCase(TestCase, MockTestCase): - def _pre_setup(self): - MockTestCase.setUp(self) - TestCase._pre_setup(self) - self.client = Client() +from rowers.tests.mocks import * - def _post_teardown(self): - TestCase._post_teardown(self) - MockTestCase.tearDown(self) - delete_strokedata(1) - -# to be done add polar mocks (for email processing) -def mocked_requests(*args, **kwargs): - with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: - c2workoutdata = json.load(infile) - - with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: - c2strokedata = json.load(infile) - - polar_json = { - 'available-user-data': [] - } - - c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) - - c2uploadjson = { - "data": { - "id": 339, - "user_id": 1, - "date": "2015-08-05 13:15:41", - "timezone": "Europe/London", - "date_utc": "2015-08-05 12:15:41", - "distance": 5649, - "type": "rower", - "time": 8649, - "time_formatted": "14:24.9", - "workout_type": "JustRow", - "source": "ErgData", - "weight_class": "H", - "verified": True, - "ranked": False - } - } - - stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) - sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) - - rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) - uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) - - stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) - - stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) - stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) - - stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) - - stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) - stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) - stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) - stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) - - uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) - - tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) - - stravastreamjson = { - 'time':stravatimejson, - 'velocity_smooth':stravavelojson, - 'distance':stravadistancejson, - 'latlng':stravalatlongjson, - 'heartrate':stravahrjson, - 'cadence':stravaspmjson, - 'power':stravapowerjson, - } - - ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) - - rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) - - uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) - uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) - - class MockResponse: - def __init__(self, json_data, status_code): - self.json_data = json_data - self.status_code = status_code - - def json(self): - return self.json_data - - - class MockHeaderResponse: - def __init__(self, header_data, status_code): - self.headers = header_data - self.status_code = status_code - - class MockSession: - def send(self,prepped): - # prepped.url - # prepped.body (post data) - # prepped.headers - # prepped.method - - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - - return MockResponse(json_data,200) - - if not args: - return MockSession() - - polartester = re.compile('.*?polaraccesslink\.com') - c2tester = re.compile('.*?log\.concept2\.com') - stravatester = re.compile('.*?strava\.com') - sttester = re.compile('.*?sporttracks\.mobi') - rktester = re.compile('.*?runkeeper\.com') - uatester = re.compile('.*?mapmyfitness\.com') - tptester = re.compile('.*?trainingpeaks\.com') - - c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' - c2importtester = re.compile(c2importregex) - - c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' - c2uploadtester = re.compile(c2uploadregex) - - c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' - c2strokestester = re.compile(c2strokesregex) - - c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' - c2workoutlisttester = re.compile(c2workoutlistregex) - - stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' - stravaworkoutlisttester = re.compile(stravaworkoutlistregex) - - stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' - stravastreamtester = re.compile(stravastreamregex) - - stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' - stravasummarytester = re.compile(stravasummaryregex) - - stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' - stuploadtester = re.compile(stuploadregex) - - stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' - stworkoutlisttester = re.compile(stworkoutlistregex) - - ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' - ststrokestester = re.compile(ststrokesregex) - - rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' - rkuploadtester = re.compile(rkuploadregex) - rkuserregex = '.*?api\.runkeeper\.com\/user$' - rkusertester = re.compile(rkuserregex) - rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' - rkstrokestester = re.compile(rkstrokesregex) - - uaapiregex = '.*?api\.ua\.com' - uaapitester = re.compile(uaapiregex) - - uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' - uauploadtester = re.compile(uauploadregex) - - uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' - uastrokestester = re.compile(uastrokesregex) - - ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' - ualisttester = re.compile(ualistregex) - - uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' - uausertester = re.compile(uauserregex) - - tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' - tpuploadtester = re.compile(tpuploadregex) - - if polartester.match(args[0]): - json_data = polar_json - return MockResponse(json_data,200) - - if tptester.match(args[0]): - if 'token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif tpuploadtester.match(args[0]): - return MockResponse(tpuploadresponse,200) - - if uaapitester.match(args[0]): - if 'access_token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif uauploadtester.match(args[0]): - if 'data' in kwargs: - return MockResponse(uapostworkoutjson,200) - elif uastrokestester.match(args[0]): - return MockResponse(uastrokesjson,200) - elif ualisttester.match(args[0]): - return MockResponse(uaworkoutlistjson,200) - elif uausertester.match(args[0]): - return MockResponse(uauserjson,200) - - - if uatester.match(args[0]): - if 'access_token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - - - if rktester.match(args[0]): - if 'token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif rkuploadtester.match(args[0]): - if 'data' in kwargs: - # post - header_data = { - 'Location': '/fitnessActivities/12' - } - return MockHeaderResponse(header_data,200) - else: - json_data = rkworkoutlistjson - return MockResponse(json_data,200) - elif rkusertester.match(args[0]): - json_data = { - "userID": 1234567890, - "profile": "/profile", - "settings": "/settings", - "fitness_activities": "/fitnessActivities", - "strength_training_activities": "/strengthTrainingActivities", - "background_activities": "/backgroundActivities", - "sleep": "/sleep", - "nutrition": "/nutrition", - "weight": "/weight", - "general_measurements": "/generalMeasurements", - "diabetes": "/diabetes", - "records": "/records", - "team": "/team" - } - return MockResponse(json_data, 200) - elif rkstrokestester.match(args[0]): - return MockResponse(rkstrokesjson,200) - - if sttester.match(args[0]): - if 'oauth2/token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - if ststrokestester.match(args[0]): - return MockResponse(ststrokesjson,200) - if stuploadtester.match(args[0]): - json_data = { - "uris": [ - "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" - ] - } - return MockResponse(json_data, 200) - if stworkoutlisttester.match(args[0]): - return MockResponse(sporttracksworkoutlist,200) - - - if stravatester.match(args[0]): - if stravaworkoutlisttester.match(args[0]): - return MockResponse(stravaworkoutlist,200) - if stravastreamtester.match(args[0]): - metric = stravastreamtester.match(args[0]).group(1) - json_data = stravastreamjson[metric] - return MockResponse(json_data,200) - elif stravasummarytester.match(args[0]): - return MockResponse(stravasummaryjson,200) - elif 'token' in args[0]: - json_data = { - "token_type": "Bearer", - "access_token": "987654321234567898765432123456789", - "refresh_token": "1234567898765432112345678987654321", - "expires_at": 1531385304 - } - return MockResponse(json_data,200) - - - if c2tester.match(args[0]): - if c2uploadtester.match(args[0]): - return MockResponse(c2uploadjson,201) - if c2strokestester.match(args[0]): - return MockResponse(c2strokedata,200) - elif c2importtester.match(args[0]): - return MockResponse(c2workoutdata,200) - elif c2workoutlisttester.match(args[0]): - return MockResponse(c2workoutlist,200) - elif 'access_token' in args[0]: - json_data = { - 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', - 'expires_in': 604800, - 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' - } - return MockResponse(json_data,200) - elif 'users/me' in args[0]: - json_data = { - 'data': { - 'username': 'john', - 'id': 1234, - } - } - return MockResponse(json_data,200) - elif 'results' in args[0]: - json_data = { - 'data': { - 'id': 1223, - } - } - else: - return MockResponse(c2workoutdata,200) - - return MockResponse(None,404) - -#@pytest.mark.django_db +@pytest.mark.django_db class C2Objects(DjangoTestCase): def setUp(self): self.c = Client() @@ -472,7 +140,8 @@ class C2Objects(DjangoTestCase): self.assertEqual(response.status_code,200) @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_import(self, mock_get): + @patch('rowers.dataprep.create_engine') + def test_c2_import(self, mock_get, mocked_sqlalchemy): response = self.c.get('/rowers/workout/c2import/12/',follow=True) @@ -578,7 +247,8 @@ class C2ObjectsTokenExpired(DjangoTestCase): self.assertEqual(response.status_code,200) @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - def test_c2_import(self, mock_get): + @patch('rowers.dataprep.create_engine') + def test_c2_import(self, mock_get, mocked_sqlalchemy): response = self.c.get('/rowers/workout/c2import/12/',follow=True) @@ -839,7 +509,7 @@ class RunKeeperObjects(DjangoTestCase): -#@pytest.mark.django_db +@pytest.mark.django_db class UAObjects(DjangoTestCase): def setUp(self): self.c = Client() @@ -929,7 +599,8 @@ class UAObjects(DjangoTestCase): self.assertEqual(response.status_code,200) @patch('rowers.imports.requests.get', side_effect=mocked_requests) - def test_underarmour_import(self, mock_get): + @patch('rowers.dataprep.create_engine') + def test_underarmour_import(self, mock_get, mocked_sqlalchemy): response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) diff --git a/rowers/tests/test_zemails.py b/rowers/tests/test_zemails.py index d339236d..3d17c8ce 100644 --- a/rowers/tests/test_zemails.py +++ b/rowers/tests/test_zemails.py @@ -49,8 +49,10 @@ from rowers.tests.test_imports import mocked_requests from django_mailbox.models import Mailbox,MessageAttachment,Message +from rowers.tests.mocks import mocked_sqlalchemy -#@pytest.mark.django_db + +@pytest.mark.django_db class UploadTests(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') @@ -151,7 +153,8 @@ workout water pass @patch('requests.get', side_effect=mocked_requests) - def test_emailprocessing(self, mock_get): + @patch('rowers.dataprep.create_engine') + def test_emailprocessing(self, mock_get, mocked_sqlalchemy): out = StringIO() call_command('processemail', stdout=out,testing=True) self.assertIn('Successfully processed email attachments',out.getvalue()) From 331b6c0049ef8db375376310b88c9deb46a45176 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 12:32:24 +0100 Subject: [PATCH 08/18] mocking sqlalchemy --- rowers/management/commands/processemail.py | 27 ++++++---- rowers/tests/mocks.py | 5 +- rowers/tests/test_zemails.py | 4 +- rowers/tests/tests.py | 58 ++++++++++++++-------- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 8a891e60..23b640b7 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -196,18 +196,23 @@ class Command(BaseCommand): rowers = [] for rower in rowers: if extension == 'zip': - zip_file = zipfile.ZipFile(attachment.document) - for id,filename in enumerate(zip_file.namelist()): - datafile = zip_file.extract(filename, path='media/') - if id>0: - title = name+' ('+str(id+1)+')' - else: - title = name + try: + zip_file = zipfile.ZipFile(attachment.document) + for id,filename in enumerate(zip_file.namelist()): + datafile = zip_file.extract( + filename, path='media/') + if id>0: + title = name+' ('+str(id+1)+')' + else: + title = name - workoutid = processattachment( - rower, datafile, title, uploadoptions, - testing=testing - ) + workoutid = processattachment( + rower, datafile, title, uploadoptions, + testing=testing + ) + except: + print "Bad ZIP file" + print attachment.document.name else: # move attachment and make workout if testing: diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index afd73bb1..3f445c1b 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -91,8 +91,11 @@ class DjangoTestCase(TestCase, MockTestCase): def _post_teardown(self): TestCase._post_teardown(self) MockTestCase.tearDown(self) - delete_strokedata(1) + # delete_strokedata(1) +def mocked_polar_notifications(*args, **kwargs): + return [] + # to be done add polar mocks (for email processing) def mocked_requests(*args, **kwargs): with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: diff --git a/rowers/tests/test_zemails.py b/rowers/tests/test_zemails.py index 3d17c8ce..bed7a8ec 100644 --- a/rowers/tests/test_zemails.py +++ b/rowers/tests/test_zemails.py @@ -154,7 +154,9 @@ workout water @patch('requests.get', side_effect=mocked_requests) @patch('rowers.dataprep.create_engine') - def test_emailprocessing(self, mock_get, mocked_sqlalchemy): + @patch('rowers.polarstuff.get_polar_notifications') + def test_emailprocessing( + self, mock_get, mocked_sqlalchemy,mocked_polar_notifications): out = StringIO() call_command('processemail', stdout=out,testing=True) self.assertIn('Successfully processed email attachments',out.getvalue()) diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index e51b9a7f..b1ad33b0 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -345,7 +345,8 @@ class ViewTest(TestCase): self.assertEqual(response.status_code, 200) - def test_upload_view_sled(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/testdata.csv' @@ -421,7 +422,8 @@ class ViewTest(TestCase): self.assertEqual(response.status_code, 200) - def test_upload_view_sled_negativetime(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_negativetime(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/tim.csv' @@ -468,8 +470,8 @@ class ViewTest(TestCase): - - def test_upload_view_sled_noname(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_noname(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/testdata.csv' @@ -504,7 +506,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_logcard(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_logcard(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/logcard.csv' @@ -536,7 +539,8 @@ class ViewTest(TestCase): - def test_upload_view_TCX_CN(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_CN(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/crewnerddata.tcx' @@ -583,7 +587,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_TCX_SpeedCoach2a(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_SpeedCoach2a(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/Speedcoach2example.csv' @@ -617,7 +622,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_TCX_SpeedCoach2b(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_SpeedCoach2b(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/Speedcoach2example.csv' @@ -653,7 +659,8 @@ class ViewTest(TestCase): - def test_upload_view_TCX_SpeedCoach2c(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_SpeedCoach2c(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/speedcoach3test3.csv' @@ -688,7 +695,8 @@ class ViewTest(TestCase): pass - def test_upload_view_SpeedCoach2v127(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_SpeedCoach2v127(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/SpeedCoach2Linkv1.27.csv' @@ -724,7 +732,8 @@ class ViewTest(TestCase): - def test_upload_view_SpeedCoach2v127intervals(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_SpeedCoach2v127intervals(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/SpeedCoach2Link_interval.csv' @@ -760,7 +769,8 @@ class ViewTest(TestCase): - def test_upload_view_TCX_NoHR(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_NoHR(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/NoHR.tcx' @@ -795,7 +805,8 @@ class ViewTest(TestCase): pass - def test_upload_view_TCX_CN(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_TCX_CN(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/rowinginmotionexample.tcx' @@ -827,7 +838,8 @@ class ViewTest(TestCase): pass - def test_upload_view_RP(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_RP(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/RP_testdata.csv' @@ -859,7 +871,8 @@ class ViewTest(TestCase): pass - def test_upload_view_Mystery(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_Mystery(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/mystery.csv' @@ -891,7 +904,8 @@ class ViewTest(TestCase): pass - def test_upload_view_RP_interval(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_RP_interval(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/RP_interval.csv' @@ -924,7 +938,8 @@ class ViewTest(TestCase): - def test_upload_view_sled_desktop(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_desktop(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/painsled_desktop_example.csv' @@ -955,7 +970,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_sled_ergdata(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_ergdata(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/ergdata_example.csv' @@ -986,7 +1002,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_sled_boatcoach(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_boatcoach(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/boatcoach.csv' @@ -1017,7 +1034,8 @@ class ViewTest(TestCase): except WindowsError: pass - def test_upload_view_sled_ergstick(self): + @patch('rowers.dataprep.create_engine') + def test_upload_view_sled_ergstick(self, mocked_sqlalchemy): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/ergstick.csv' From 8ff24d3fae4f6034a0019a9ceaff8da165b31ab9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 16:06:47 +0100 Subject: [PATCH 09/18] faking some more sql calls --- rowers/tests/mocks.py | 64 ++++++++ rowers/tests/testdata/fake_strokedata.csv | 192 ++++++++++++++++++++++ rowers/tests/tests.py | 185 ++++++++++++++------- 3 files changed, 386 insertions(+), 55 deletions(-) create mode 100644 rowers/tests/testdata/fake_strokedata.csv diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 3f445c1b..2436af15 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -34,6 +34,7 @@ import rowers.c2stuff as c2stuff import json import numpy as np +from rowingdata import rowingdata, figure from rowers import urls from rowers.views import ( @@ -93,8 +94,71 @@ class DjangoTestCase(TestCase, MockTestCase): MockTestCase.tearDown(self) # delete_strokedata(1) +def mocked_tcx_parser(*args, **kwargs): + df = pd.read_csv('rowers/tests/testdata/fake_strokedata.csv') + + return rowingdata(df=df) + def mocked_polar_notifications(*args, **kwargs): return [] + + +class mocked_canvas(): + def print_figure(*args, **kwargs): + return True + +import pandas as pd +def mocked_read_df_sql(id): + df = pd.read_csv('rowers/tests/testdata/fake_strokedata.csv') + + return df + + + +class mocked_rowingdata(rowingdata): + def __init__(self, *args, **kwargs): + super(mocked_rowingdata).__init__(*args, **kwargs) + + def get_metersplot_erg(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_timeplot_erg(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_piechart(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_timeplot_otwempower(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_timeplot_otw(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_metersplot_otwempower(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_metersplot_erg2(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_timeplot_erg2(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_time_otwpower(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + + def get_power_piechart(self, title): + fig1 = figure.Figure(figsize(12,10)) + return fig1 + # to be done add polar mocks (for email processing) def mocked_requests(*args, **kwargs): diff --git a/rowers/tests/testdata/fake_strokedata.csv b/rowers/tests/testdata/fake_strokedata.csv new file mode 100644 index 00000000..558cb86c --- /dev/null +++ b/rowers/tests/testdata/fake_strokedata.csv @@ -0,0 +1,192 @@ +,id,time,hr,pace,spm,cumdist,ftime,fpace,driveenergy,power,averageforce,drivelength,peakforce,forceratio,distance,drivespeed,workoutid,equivergpower,ergpace,fergpace,fnowindpace,hr_an,hr_at,hr_bottom,hr_max,hr_tr,hr_ut1,hr_ut2,nowindpace,x_right,workoutstate,catch,finish,peakforceangle,wash,slip,rhythm,effectiveangle,totalangle,efficiency,distanceperstroke,velo +0,39799136,0.0,126.976190476,267517.544209,1.33333333333,5.4,05:50.0,04:27.5,88.1806760867,19.35721935,102.30906,0.826870748299,209.06634,0.499922562048,5.4,0.85119047619,3252,50.0,191293.118277,03:11.2,04:27.5,0,0,0,0,0,127,0,267517.544209,3.5326e+11,4,0.0,0.0,0.0,0.0,0.0,37.7952755906,0.0,0.0,94.4426720529,84.1066333294,1.86903629621 +1,39799137,3240.00000954,127.095238095,230263.518558,15.5714285714,13.1,00:03.2,03:50.2,220.103927167,25.6355755264,188.604528,1.21267573696,299.810028,0.600977358387,13.1,0.8736913205,3252,50.0,191293.118277,03:11.2,03:50.2,0,0,0,0,0,127,0,230263.518558,6500000000.0,4,0.0,0.0,0.0,0.0,0.0,44.6202531646,0.0,0.0,111.827743719,8.36695937183,2.17142517031 +2,39799138,6150.00009537,127.880952381,201258.643579,21.4285714286,21.0,00:06.1,03:21.2,273.846587402,44.6485827564,195.276858,1.36636621315,310.485756,0.641492073477,21.0,1.29492362983,3252,50.0,191293.118277,03:11.2,03:21.2,0,0,0,0,0,128,0,201258.643579,9020000000.0,4,0.0,0.0,0.0,0.0,0.0,37.7224199288,0.0,0.0,96.1605065241,6.95622297311,2.48436534754 +3,39799139,9269.99998093,129.0,180582.4977,21.9047619048,30.3,00:09.2,03:00.5,278.525981193,64.2054260988,201.059544,1.37036281179,322.49595,0.643049698939,30.3,1.38929798724,3252,50.0,191293.118277,03:11.2,03:00.5,0,0,0,0,0,129,0,180582.4977,12420000000.0,4,0.0,0.0,0.0,0.0,0.0,34.1549295775,0.0,0.0,92.5698041753,7.58415258861,2.76881761171 +4,39799140,12150.0000954,129.952380952,168216.324384,20.380952381,39.0,00:12.1,02:48.2,271.853383897,73.72570625,206.84223,1.32583900227,323.830416,0.627589324063,39.0,1.40372670807,3252,50.0,191293.118277,03:11.2,02:48.2,0,0,0,0,0,130,0,168216.324384,15020000000.0,4,0.0,0.0,0.0,0.0,0.0,33.9483394834,0.0,0.0,99.7343324777,8.75041481387,2.97236312725 +5,39799141,15150.0000954,130.761904762,163348.980307,20.2380952381,48.2,00:15.1,02:43.3,271.598579567,80.0701191136,201.949188,1.29342403628,323.385594,0.628837587302,48.2,1.40838509317,3252,50.0,191293.118277,03:11.2,02:43.3,0,0,0,0,0,131,0,163348.980307,18130000000.0,4,0.0,0.0,0.0,0.0,0.0,32.7402135231,0.0,0.0,100.287842053,9.07476090999,3.06093125932 +6,39799142,18150.0000954,131.380952381,161595.916202,20.4285714286,57.6,00:18.1,02:41.5,272.398664053,82.9313928352,221.521356,1.28757369615,354.967956,0.633692860915,57.6,1.4380952381,3252,50.0,191293.118277,03:11.2,02:41.5,0,0,0,0,0,131,0,161595.916202,21140000000.0,4,0.0,0.0,0.0,0.0,0.0,32.1428571429,0.0,0.0,100.013342349,9.08767686119,3.09413759798 +7,39799143,20910.0000858,131.761904762,160946.930227,20.3333333333,66.4,00:20.9,02:40.9,269.06750204,86.6028089332,214.404204,1.29693877551,334.950966,0.632028077529,66.4,1.50830564784,3252,50.0,191293.118277,03:11.2,02:40.9,0,0,0,0,0,132,0,160946.930227,23710000000.0,4,0.0,0.0,0.0,0.0,0.0,31.1594202899,0.0,0.0,96.9366423557,9.16705794878,3.10661408264 +8,39799144,23819.9999332,131.857142857,160556.046845,20.1904761905,75.5,00:23.8,02:40.5,301.07501704,85.9423518548,215.293848,1.31319727891,337.619898,0.630773850875,75.5,1.48376623377,3252,50.0,191293.118277,03:11.2,02:40.5,0,0,0,0,0,132,0,160556.046845,26730000000.0,4,0.0,0.0,0.0,0.0,0.0,32.1167883212,0.0,0.0,98.396762766,9.25439487206,3.11417732203 +9,39799145,26940.0000572,132.047619048,156621.552107,20.7619047619,85.1,00:26.9,02:36.6,346.52959188,87.8502695392,234.866016,1.34163265306,381.657276,0.623563414808,85.1,1.50240770465,3252,50.0,191293.118277,03:11.2,02:36.6,0,0,0,0,0,132,0,156621.552107,29930000000.0,4,0.0,0.0,0.0,0.0,0.0,32.962962963,0.0,0.0,103.69799887,9.22576815896,3.19240866453 +10,39799146,29640.0001049,132.285714286,150480.356059,21.0952380952,95.0,00:29.6,02:30.4,395.87381738,99.6207143932,324.72006,1.37176870748,532.007112,0.612977608416,95.0,1.60465116279,3252,50.0,191293.118277,03:11.2,02:30.4,0,0,0,0,0,132,0,150480.356059,32470000000.0,4,0.0,0.0,0.0,0.0,0.0,32.5757575758,0.0,0.0,103.104818509,9.45054845301,3.32269282911 +11,39799147,32369.9998856,132.952380952,143847.653479,21.1904761905,105.0,00:32.3,02:23.8,441.03471892,126.436932947,314.044332,1.39544217687,521.331384,0.594869267431,105.0,1.70731707317,3252,50.0,191293.118277,03:11.2,02:23.8,0,0,0,0,0,133,0,143847.653479,35110000000.0,4,0.0,0.0,0.0,0.0,0.0,31.5384615385,0.0,0.0,93.0005991502,9.84187300133,3.47589959174 +12,39799148,35190.0000572,133.904761905,138421.986347,21.2857142857,115.3,00:35.1,02:18.4,462.78370054,134.706308388,312.709866,1.40442176871,529.783002,0.585113064034,115.3,1.773960217,3252,50.0,191293.118277,03:11.2,02:18.4,0,0,0,0,0,134,0,138421.986347,38010000000.0,4,0.0,0.0,0.0,0.0,0.0,30.0380228137,0.0,0.0,97.9636321096,10.1818794134,3.61214293477 +13,39799149,38009.9999905,134.904761905,135418.044204,21.1904761905,125.8,00:38.0,02:15.4,462.60068806,138.97288125,338.06472,1.40095238095,608.961318,0.572328332569,125.8,1.7967032967,3252,50.0,191293.118277,03:11.2,02:15.4,0,0,0,0,0,135,0,135418.044204,40820000000.0,4,0.0,0.0,0.0,0.0,0.0,30.0,0.0,0.0,101.416442286,10.4545176782,3.69227013238 +14,39799150,40890.0001049,136.047619048,134197.799472,21.3333333333,136.6,00:40.8,02:14.1,467.18302038,146.360682773,335.395788,1.39530612245,576.04449,0.573372604334,136.6,1.8107606679,3252,50.0,191293.118277,03:11.2,02:14.1,0,0,0,0,0,136,0,134197.799472,43770000000.0,4,0.0,0.0,0.0,0.0,0.0,29.8449612403,0.0,0.0,98.9480942562,10.4789348673,3.72584350838 +15,39799151,43680.0000668,137.428571429,133465.452616,21.5238095238,147.2,00:43.6,02:13.4,462.1348051,149.79272233,342.068118,1.38816326531,601.844166,0.577043192957,147.2,1.77838827839,3252,50.0,191293.118277,03:11.2,02:13.4,0,0,0,0,0,137,0,133465.452616,46480000000.0,4,0.0,0.0,0.0,0.0,0.0,29.8850574713,0.0,0.0,98.2812654729,10.4431917205,3.74628782355 +16,39799152,46470.0000286,138.619047619,133276.640695,21.7619047619,157.6,00:46.4,02:13.2,463.22873436,152.311202593,319.382196,1.37918367347,535.120866,0.577917524111,157.6,1.84380952381,3252,50.0,191293.118277,03:11.2,02:13.2,0,0,0,0,0,139,0,133276.640695,49260000000.0,4,0.0,0.0,0.0,0.0,0.0,28.8461538462,0.0,0.0,97.0675536464,10.3435665207,3.75159515871 +17,39799153,49200.0000477,139.714285714,133039.90291,21.7142857143,167.8,00:49.2,02:13.0,461.2763289,145.54018967,332.726856,1.37448979592,587.609862,0.573139687516,167.8,1.82857142857,3252,50.0,191293.118277,03:11.2,02:13.0,0,0,0,0,0,140,0,133039.90291,51900000000.0,4,0.0,0.0,0.0,0.0,0.0,29.8804780876,0.0,0.0,102.126712018,10.3846959983,3.75827093273 +18,39799154,51960.0000381,140.380952381,133170.997419,21.2857142857,178.5,00:51.9,02:13.1,461.2964518,149.554325469,360.30582,1.37319727891,644.102256,0.573214309195,178.5,1.8007518797,3252,50.0,191293.118277,03:11.2,02:13.1,0,0,0,0,0,140,0,133170.997419,54760000000.0,4,0.0,0.0,0.0,0.0,0.0,29.0076335878,0.0,0.0,99.0923455439,10.5833552385,3.75457126319 +19,39799155,54660.0000858,140.80952381,133152.931686,21.2380952381,188.5,00:54.6,02:13.1,467.16277644,154.735851561,320.716662,1.37183673469,551.134458,0.566265126248,188.5,1.83619047619,3252,50.0,191293.118277,03:11.2,02:13.1,0,0,0,0,0,141,0,133152.931686,57340000000.0,4,0.0,0.0,0.0,0.0,0.0,28.7356321839,0.0,0.0,95.8131009692,10.6085238675,3.75508067055 +20,39799156,57539.9999619,141.19047619,132699.130953,21.4761904762,199.3,00:57.5,02:12.6,460.85166006,147.538156497,338.06472,1.37285714286,587.16504,0.580181755545,199.3,1.78478664193,3252,50.0,191293.118277,03:11.2,02:12.6,0,0,0,0,0,141,0,132699.130953,60400000000.0,4,0.0,0.0,0.0,0.0,0.0,29.8449612403,0.0,0.0,101.521834232,10.5267892646,3.76792218917 +21,39799157,60269.9999809,141.714285714,132964.959531,21.5714285714,209.4,01:00.2,02:12.9,451.775748,150.748843213,337.619898,1.37,588.054684,0.586801841858,209.4,1.84555984556,3252,50.0,191293.118277,03:11.2,02:12.9,0,0,0,0,0,142,0,132964.959531,62950000000.0,4,0.0,0.0,0.0,0.0,0.0,29.718875502,0.0,0.0,98.7648569306,10.4593607348,3.76038921655 +22,39799158,62849.9999046,142.238095238,133493.269817,21.8571428571,219.4,01:02.8,02:13.4,456.8960426,150.868643612,327.833814,1.36394557823,537.344976,0.590718880399,219.4,1.82285714286,3252,50.0,191293.118277,03:11.2,02:13.4,0,0,0,0,0,142,0,133493.269817,65500000000.0,4,0.0,0.0,0.0,0.0,0.0,30.0,0.0,0.0,97.5193832126,10.2817844037,3.74550717565 +23,39799159,65730.0000191,143.142857143,133423.241182,22.1428571429,230.2,01:05.7,02:13.4,450.13396144,148.010908576,332.726856,1.3562585034,574.265202,0.587126683943,230.2,1.80761904762,3252,50.0,191293.118277,03:11.2,02:13.4,0,0,0,0,0,143,0,133423.241182,68620000000.0,4,0.0,0.0,0.0,0.0,0.0,28.9575289575,0.0,0.0,99.5588474118,10.1544430916,3.7474730457 +24,39799160,68400.0000954,143.952380952,133559.338288,22.3333333333,240.2,01:08.4,02:13.5,451.23542544,147.06641215,336.730254,1.34823129252,572.485914,0.581344675244,240.2,1.8,3252,50.0,191293.118277,03:11.2,02:13.5,0,0,0,0,0,144,0,133559.338288,71060000000.0,4,0.0,0.0,0.0,0.0,0.0,30.487804878,0.0,0.0,99.8922443414,10.0575788957,3.74365436675 +25,39799161,71039.9999619,144.714285714,133228.128188,22.7619047619,250.1,01:11.0,02:13.2,448.59990048,150.0313724,332.726856,1.34,596.951124,0.572068554427,250.1,1.83170254403,3252,50.0,191293.118277,03:11.2,02:13.2,0,0,0,0,0,145,0,133228.128188,73670000000.0,4,0.0,0.0,0.0,0.0,0.0,29.9180327869,0.0,0.0,98.650248521,9.89274299446,3.75296123123 +26,39799162,73500.0,145.142857143,132852.649371,22.9047619048,259.6,01:13.5,02:12.8,447.82781658,151.46859775,340.733652,1.33578231293,588.054684,0.573409353633,259.6,1.85515873016,3252,50.0,191293.118277,03:11.2,02:12.8,0,0,0,0,0,145,0,132852.649371,75990000000.0,4,0.0,0.0,0.0,0.0,0.0,29.6296296296,0.0,0.0,98.5450423905,9.85882717413,3.76356815139 +27,39799163,76349.9999046,144.952380952,132705.854989,22.6666666667,270.3,01:16.3,02:12.7,445.93296564,152.311202593,325.609704,1.33557823129,566.258406,0.568538870911,270.3,1.82974559687,3252,50.0,191293.118277,03:11.2,02:12.7,0,0,0,0,0,145,0,132705.854989,79190000000.0,4,0.0,0.0,0.0,0.0,0.0,28.8537549407,0.0,0.0,98.3254503049,9.97340631186,3.76773127337 +28,39799164,79079.9999237,144.714285714,133013.725151,22.4761904762,280.6,01:19.0,02:13.0,446.46711516,149.43522195,341.623296,1.33843537415,600.954522,0.574029662749,280.6,1.80694980695,3252,50.0,191293.118277,03:11.2,02:13.0,0,0,0,0,0,145,0,133013.725151,81820000000.0,4,0.0,0.0,0.0,0.0,0.0,29.0196078431,0.0,0.0,99.5235141066,10.0346468847,3.75901057903 +29,39799165,81750.0,144.666666667,133278.99447,22.3333333333,290.7,01:21.7,02:13.2,453.9702032,149.79272233,332.282034,1.33891156463,593.392548,0.562905554475,290.7,1.83953033268,3252,50.0,191293.118277,03:11.2,02:13.2,0,0,0,0,0,144,0,133278.99447,84420000000.0,4,0.0,0.0,0.0,0.0,0.0,29.5546558704,0.0,0.0,98.6943311289,10.0787343679,3.75152890362 +30,39799166,84450.0000477,144.714285714,132845.542123,22.3333333333,300.8,01:24.4,02:12.8,461.67512544,149.316181683,341.623296,1.34027210884,594.727014,0.561184618018,300.8,1.83561643836,3252,50.0,191293.118277,03:11.2,02:12.8,0,0,0,0,0,145,0,132845.542123,87140000000.0,4,0.0,0.0,0.0,0.0,0.0,29.0836653386,0.0,0.0,99.9816299192,10.1116195592,3.76376950261 +31,39799167,87180.0000668,144.761904762,132433.757101,22.1428571429,311.1,01:27.1,02:12.4,462.93860148,152.070140328,357.636888,1.34319727891,661.450314,0.558028598825,311.1,1.80888030888,3252,50.0,191293.118277,03:11.2,02:12.4,0,0,0,0,0,145,0,132433.757101,89860000000.0,4,0.0,0.0,0.0,0.0,0.0,29.6,0.0,0.0,99.0895822785,10.2303124168,3.77547243954 +32,39799168,89789.9999619,145.142857143,132296.93032,21.8571428571,321.2,01:29.7,02:12.2,463.39797854,156.571128627,336.730254,1.34659863946,588.499506,0.560523315593,321.2,1.87301587302,3252,50.0,191293.118277,03:11.2,02:12.2,0,0,0,0,0,145,0,132296.93032,92460000000.0,4,0.0,0.0,0.0,0.0,0.0,29.0322580645,0.0,0.0,96.5399478842,10.374760898,3.77937718428 +33,39799169,92670.0000763,145.333333333,132417.814657,21.5714285714,331.9,01:32.6,02:12.4,459.09860748,150.150792431,340.28883,1.35204081633,612.075072,0.565722937216,331.9,1.83011583012,3252,50.0,191293.118277,03:11.2,02:12.4,0,0,0,0,0,145,0,132417.814657,95510000000.0,4,0.0,0.0,0.0,0.0,0.0,29.1338582677,0.0,0.0,100.39247635,10.502578376,3.77592698757 +34,39799170,95339.9999142,145.571428571,132644.156173,21.7142857143,342.0,01:35.3,02:12.6,457.32419134,150.988507466,334.950966,1.35741496599,579.158244,0.570439059313,342.0,1.83204633205,3252,50.0,191293.118277,03:11.2,02:12.6,0,0,0,0,0,146,0,132644.156173,98030000000.0,4,0.0,0.0,0.0,0.0,0.0,29.718875502,0.0,0.0,99.3252778037,10.4156789656,3.76948381613 +35,39799171,98069.9999332,146.0,132824.170064,21.8571428571,352.4,01:38.0,02:12.8,465.83169956,150.868643612,341.178474,1.35972789116,592.058082,0.573613897901,352.4,1.83783783784,3252,50.0,191293.118277,03:11.2,02:12.8,0,0,0,0,0,146,0,132824.170064,1.008e+11,4,0.0,0.0,0.0,0.0,0.0,29.1338582677,0.0,0.0,99.0005769733,10.3335787375,3.76437511153 +36,39799172,100859.999895,146.428571429,132399.04606,22.0952380952,363.0,01:40.8,02:12.3,469.36640042,153.399135658,346.96116,1.36340136054,621.416334,0.570446901224,363.0,1.84362934363,3252,50.0,191293.118277,03:11.2,02:12.3,0,0,0,0,0,146,0,132399.04606,1.0364e+11,4,0.0,0.0,0.0,0.0,0.0,28.5714285714,0.0,0.0,98.3083854908,10.255048364,3.77646225467 +37,39799173,103619.999886,146.666666667,132245.976211,22.0952380952,373.4,01:43.6,02:12.2,468.9419434,152.4318292,347.405982,1.36897959184,592.502904,0.567916935654,373.4,1.84555984556,3252,50.0,191293.118277,03:11.2,02:12.2,0,147,0,0,0,0,0,132245.976211,1.0637e+11,4,0.0,0.0,0.0,0.0,0.0,28.90625,0.0,0.0,99.2761628163,10.266918205,3.78083337072 +38,39799174,106380.000114,146.857142857,132500.471593,21.8571428571,383.9,01:46.3,02:12.5,470.1816956,152.914972515,337.619898,1.37258503401,619.192224,0.565878523172,383.9,1.80827067669,3252,50.0,191293.118277,03:11.2,02:12.5,0,147,0,0,0,0,0,132500.471593,1.0915e+11,4,0.0,0.0,0.0,0.0,0.0,29.4573643411,0.0,0.0,98.3933531887,10.3588236563,3.7735714748 +39,39799175,109230.000019,147.142857143,132775.418655,21.7142857143,394.6,01:49.2,02:12.7,466.5370299,151.46859775,334.061322,1.37394557823,574.265202,0.565880568251,394.6,1.83619047619,3252,50.0,191293.118277,03:11.2,02:12.7,0,147,0,0,0,0,0,132775.418655,1.121e+11,4,0.0,0.0,0.0,0.0,0.0,28.1954887218,0.0,0.0,98.7171028208,10.4053819703,3.76575728448 +40,39799176,111960.000038,147.333333333,132878.01379,21.7619047619,405.0,01:51.9,02:12.8,468.16105384,148.603267434,350.519736,1.37340136054,627.643842,0.56601972006,405.0,1.8045112782,3252,50.0,191293.118277,03:11.2,02:12.8,0,147,0,0,0,0,0,132878.01379,1.1469e+11,4,0.0,0.0,0.0,0.0,0.0,29.6875,0.0,0.0,100.38765333,10.3745966648,3.7628497427 +41,39799177,114690.000057,147.666666667,133014.526935,21.5714285714,415.3,01:54.6,02:13.0,461.97357982,151.82933255,334.061322,1.37108843537,586.275396,0.572604512571,415.3,1.85135135135,3252,50.0,191293.118277,03:11.2,02:13.0,0,148,0,0,0,0,0,133014.526935,1.1741e+11,4,0.0,0.0,0.0,0.0,0.0,29.2490118577,0.0,0.0,97.9524129494,10.4554630901,3.7589879205 +42,39799178,117630.000114,147.857142857,133297.852527,21.5714285714,426.0,01:57.6,02:13.2,467.13796324,150.509432707,343.402584,1.36891156463,590.723616,0.576219283059,426.0,1.85135135135,3252,50.0,191293.118277,03:11.2,02:13.2,0,148,0,0,0,0,0,133297.852527,1.2046e+11,4,0.0,0.0,0.0,0.0,0.0,28.0303030303,0.0,0.0,98.182676506,10.4332399244,3.75099816329 +43,39799179,120329.999924,148.142857143,133012.600446,21.7619047619,436.5,02:00.3,02:13.0,468.43324254,149.316181683,326.054526,1.37163265306,572.485914,0.574708892977,436.5,1.78107606679,3252,50.0,191293.118277,03:11.2,02:13.0,0,148,0,0,0,0,0,133012.600446,1.2316e+11,4,0.0,0.0,0.0,0.0,0.0,29.5019157088,0.0,0.0,99.605384492,10.3640992963,3.75904236383 +44,39799180,123150.000095,148.238095238,132741.318404,21.7142857143,446.9,02:03.1,02:12.7,473.53595608,148.603267434,365.643684,1.37421768707,627.19902,0.56297996655,446.9,1.85328185328,3252,50.0,191293.118277,03:11.2,02:12.7,0,148,0,0,0,0,0,132741.318404,1.2586e+11,4,0.0,0.0,0.0,0.0,0.0,29.1338582677,0.0,0.0,100.698106743,10.408055035,3.76672467933 +45,39799181,125670.000076,148.714285714,132116.286996,21.9523809524,456.9,02:05.6,02:12.1,480.02140032,156.448327748,339.399186,1.37891156463,636.985104,0.552002776041,456.9,1.84380952381,3252,50.0,191293.118277,03:11.2,02:12.1,0,149,0,0,0,0,0,132116.286996,1.2827e+11,4,0.0,0.0,0.0,0.0,0.0,29.4117647059,0.0,0.0,97.0125766755,10.3438750147,3.78454474744 +46,39799182,128490.00001,149.285714286,131446.06373,22.0476190476,467.6,02:08.4,02:11.4,480.97186692,155.223848632,342.068118,1.38394557823,624.97491,0.553015355989,467.6,1.86486486486,3252,50.0,191293.118277,03:11.2,02:11.4,0,149,0,0,0,0,0,131446.06373,1.3133e+11,4,0.0,0.0,0.0,0.0,0.0,29.2490118577,0.0,0.0,99.2811596511,10.3517070508,3.80384155913 +47,39799183,131369.999886,149.761904762,131579.319767,21.5714285714,478.5,02:11.3,02:11.5,468.43309124,155.590518989,351.854202,1.38789115646,628.978308,0.551216571488,478.5,1.80333951763,3252,50.0,191293.118277,03:11.2,02:11.5,0,150,0,0,0,0,0,131579.319767,1.3423e+11,4,0.0,0.0,0.0,0.0,0.0,28.624535316,0.0,0.0,98.7465666185,10.5695065097,3.79998924517 +48,39799184,134190.000057,150.047619048,132379.219894,21.380952381,489.0,02:14.1,02:12.3,470.22868938,154.370525725,329.16828,1.38278911565,575.599668,0.565640526729,489.0,1.84761904762,3252,50.0,191293.118277,03:11.2,02:12.3,0,150,0,0,0,0,0,132379.219894,1.3698e+11,4,0.0,0.0,0.0,0.0,0.0,28.9575289575,0.0,0.0,97.7336703229,10.5992318221,3.77702784771 +49,39799185,136799.999952,150.047619048,132686.986271,21.380952381,499.1,02:16.8,02:12.6,472.07330872,148.366134605,337.619898,1.37421768707,615.633648,0.55548126898,499.1,1.78849721707,3252,50.0,191293.118277,03:11.2,02:12.6,0,150,0,0,0,0,0,132686.986271,1.3944e+11,4,0.0,0.0,0.0,0.0,0.0,29.5019157088,0.0,0.0,100.983000825,10.5746469908,3.7682670626 +50,39799186,139710.000038,149.666666667,132806.105783,21.5714285714,510.0,02:19.7,02:12.8,463.49638406,150.748843213,351.854202,1.35707482993,620.971512,0.552332697655,510.0,1.82818532819,3252,50.0,191293.118277,03:11.2,02:12.8,0,150,0,0,0,0,0,132806.105783,1.4262e+11,4,0.0,0.0,0.0,0.0,0.0,28.6821705426,0.0,0.0,99.1196886936,10.47187152,3.7648871417 +51,39799187,142319.999933,149.428571429,132924.920461,21.9523809524,519.9,02:22.3,02:12.9,467.38403756,152.79409112,351.40938,1.34034013605,670.791576,0.553274143388,519.9,1.86706349206,3252,50.0,191293.118277,03:11.2,02:12.9,0,149,0,0,0,0,0,132924.920461,1.4491e+11,4,0.0,0.0,0.0,0.0,0.0,28.125,0.0,0.0,97.5309057756,10.2809492407,3.76152190474 +52,39799188,145200.000048,149.0,132760.275263,22.0952380952,530.6,02:25.2,02:12.7,452.0791045,151.2284256,329.16828,1.33054421769,567.592872,0.55928136473,530.6,1.81604696673,3252,50.0,191293.118277,03:11.2,02:12.7,0,149,0,0,0,0,0,132760.275263,1.4807e+11,4,0.0,0.0,0.0,0.0,0.0,28.6274509804,0.0,0.0,98.9077177669,10.2271452662,3.76618682818 +53,39799189,147869.999886,148.666666667,133445.996984,22.0,540.8,02:27.8,02:13.4,441.90542016,147.774406503,347.405982,1.33142857143,610.740606,0.57052466683,540.8,1.81996086106,3252,50.0,191293.118277,03:11.2,02:13.4,0,149,0,0,0,0,0,133445.996984,1.5058e+11,4,0.0,0.0,0.0,0.0,0.0,28.9682539683,0.0,0.0,99.6671795686,10.2186382092,3.74683401003 +54,39799190,150569.999933,148.285714286,133974.160675,22.0,550.8,02:30.5,02:13.9,439.90544598,148.8406528,310.930578,1.33653061224,547.575882,0.579100196408,550.8,1.81081081081,3252,50.0,191293.118277,03:11.2,02:13.9,0,148,0,0,0,0,0,133974.160675,1.5324e+11,4,0.0,0.0,0.0,0.0,0.0,29.8387096774,0.0,0.0,97.7875000321,10.1783534733,3.73206294022 +55,39799191,153210.000038,147.714285714,133996.497711,22.0,560.8,02:33.2,02:13.9,447.03488354,144.373384534,338.06472,1.34952380952,574.265202,0.563329080487,560.8,1.8,3252,50.0,191293.118277,03:11.2,02:13.9,0,148,0,0,0,0,0,133996.497711,1.5589e+11,4,0.0,0.0,0.0,0.0,0.0,30.1204819277,0.0,0.0,100.762878325,10.1766567555,3.73144081033 +56,39799192,155910.000086,147.238095238,133634.43276,22.0,571.0,02:35.9,02:13.6,445.222945,149.078290838,333.171678,1.35891156463,610.295784,0.562404477497,571.0,1.80761904762,3252,50.0,191293.118277,03:11.2,02:13.6,0,147,0,0,0,0,0,133634.43276,1.586e+11,4,0.0,0.0,0.0,0.0,0.0,30.0,0.0,0.0,98.3781192719,10.2042290708,3.74155065931 +57,39799193,158460.000038,147.047619048,133400.917518,21.9047619048,580.7,02:38.4,02:13.4,456.42734546,150.270275814,330.502746,1.36496598639,607.18203,0.554919999296,580.7,1.82666666667,3252,50.0,191293.118277,03:11.2,02:13.4,0,147,0,0,0,0,0,133400.917518,1.6102e+11,4,0.0,0.0,0.0,0.0,0.0,30.0,0.0,0.0,98.1111826798,10.2665352149,3.74810015781 +58,39799194,161250.0,146.904761905,132778.406555,22.0476190476,591.2,02:41.2,02:12.7,447.8955082,150.748843213,325.164882,1.36598639456,564.034296,0.554629386616,591.2,1.81904761905,3252,50.0,191293.118277,03:11.2,02:12.7,0,147,0,0,0,0,0,132778.406555,1.6404e+11,4,0.0,0.0,0.0,0.0,0.0,30.2419354839,0.0,0.0,99.1817344353,10.247834569,3.76567254399 +59,39799195,163950.000048,147.0,132807.06861,22.4285714286,601.4,02:43.9,02:12.8,451.54855592,150.270275814,338.954364,1.36346938776,613.85436,0.570959970779,601.4,1.79511278195,3252,50.0,191293.118277,03:11.2,02:12.8,0,147,0,0,0,0,0,132807.06861,1.6664e+11,4,0.0,0.0,0.0,0.0,0.0,30.4,0.0,0.0,99.4331936049,10.0715995905,3.76485984694 +60,39799196,166619.999886,147.0,132572.347555,22.619047619,611.4,02:46.6,02:12.5,457.20073054,153.277999204,324.72006,1.35414965986,551.134458,0.586617053679,611.4,1.85518590998,3252,50.0,191293.118277,03:11.2,02:12.5,0,147,0,0,0,0,0,132572.347555,1.6927e+11,4,0.0,0.0,0.0,0.0,0.0,29.5546558704,0.0,0.0,98.0007459534,10.0044678542,3.77152557995 +61,39799197,169380.000114,146.904761905,132377.004331,22.5238095238,621.8,02:49.3,02:12.3,462.75156442,151.108434789,352.743846,1.34925170068,590.278794,0.589285589269,621.8,1.82432432432,3252,50.0,191293.118277,03:11.2,02:12.3,0,147,0,0,0,0,0,132377.004331,1.7212e+11,4,0.0,0.0,0.0,0.0,0.0,29.0196078431,0.0,0.0,99.8485335066,10.0615956434,3.77709106295 +62,39799198,172049.999952,147.047619048,132122.128079,22.4761904762,632.1,02:52.0,02:12.1,470.00379706,154.8577548,350.519736,1.34394557823,582.71682,0.595205660521,632.1,1.85912698413,3252,50.0,191293.118277,03:11.2,02:12.1,0,147,0,0,0,0,0,132122.128079,1.7475e+11,4,0.0,0.0,0.0,0.0,0.0,28.6852589641,0.0,0.0,97.9960127045,10.1023634884,3.78437743374 +63,39799199,174720.000029,147.333333333,131614.148435,22.380952381,642.3,02:54.7,02:11.6,480.06373406,154.127294899,349.18527,1.34401360544,607.626852,0.589862706687,642.3,1.82239382239,3252,50.0,191293.118277,03:11.2,02:11.6,0,147,0,0,0,0,0,131614.148435,1.7739e+11,4,0.0,0.0,0.0,0.0,0.0,29.718875502,0.0,0.0,99.6049114541,10.1845094001,3.79898366511 +64,39799200,177299.999952,147.571428571,130772.700382,22.6666666667,652.0,02:57.3,02:10.7,480.81046008,157.3092836,366.088506,1.34333333333,620.52669,0.586295170744,652.0,1.8893360161,3252,50.0,191293.118277,03:11.2,02:10.7,0,148,0,0,0,0,0,130772.700382,1.798e+11,4,0.0,0.0,0.0,0.0,0.0,28.8617886179,0.0,0.0,99.486102197,10.120838737,3.82342796731 +65,39799201,180180.000067,148.0,130148.629,22.9047619048,662.7,03:00.1,02:10.1,485.54760256,162.163914945,357.636888,1.34693877551,607.18203,0.583353561525,662.7,1.87301587302,3252,50.0,191293.118277,03:11.2,02:10.1,0,148,0,0,0,0,0,130148.629,1.8297e+11,4,0.0,0.0,0.0,0.0,0.0,29.0322580645,0.0,0.0,97.9027816141,10.063658141,3.84176156016 +66,39799202,182670.000076,148.428571429,129649.404112,22.7619047619,673.1,03:02.6,02:09.6,489.00093428,162.541430374,362.52993,1.34544217687,621.861156,0.587668878441,673.1,1.8893360161,3252,50.0,191293.118277,03:11.2,02:09.6,0,148,0,0,0,0,0,129649.404112,1.8535e+11,4,0.0,0.0,0.0,0.0,0.0,28.5140562249,0.0,0.0,98.8080644551,10.1658132625,3.85655455513 +67,39799203,185430.000067,148.571428571,129434.345963,22.2380952381,683.6,03:05.4,02:09.4,483.88687324,162.793432547,360.30582,1.34448979592,622.305978,0.579260719162,683.6,1.87698412698,3252,50.0,191293.118277,03:11.2,02:09.4,0,149,0,0,0,0,0,129434.345963,1.8813e+11,4,0.0,0.0,0.0,0.0,0.0,28.8,0.0,0.0,99.1476815574,10.4225535544,3.86296230944 +68,39799204,188039.999962,149.0,129521.611571,22.1904761905,693.8,03:08.0,02:09.5,488.07812532,162.163914945,366.088506,1.33972789116,626.754198,0.574143842725,693.8,1.88329979879,3252,50.0,191293.118277,03:11.2,02:09.5,0,149,0,0,0,0,0,129521.611571,1.9069e+11,4,0.0,0.0,0.0,0.0,0.0,28.6290322581,0.0,0.0,99.3315255298,10.4378822505,3.86035962599 +69,39799205,190589.999914,149.333333333,129450.495129,22.0952380952,703.8,03:10.5,02:09.4,485.5135298,163.930665884,355.412778,1.33823129252,634.316172,0.577472776375,703.8,1.85714285714,3252,50.0,191293.118277,03:11.2,02:09.4,0,149,0,0,0,0,0,129450.495129,1.9313e+11,4,0.0,0.0,0.0,0.0,0.0,28.9156626506,0.0,0.0,98.4230215789,10.4886321163,3.8624803984 +70,39799206,193410.000086,149.714285714,129612.827283,22.4761904762,714.7,03:13.4,02:09.6,476.80902898,162.163914945,371.42637,1.33734693878,640.988502,0.575938050313,714.7,1.93581780538,3252,50.0,191293.118277,03:11.2,02:09.6,0,150,0,0,0,0,0,129612.827283,1.9624e+11,4,0.0,0.0,0.0,0.0,0.0,27.380952381,0.0,0.0,99.1219578243,10.2979449696,3.85764287749 +71,39799207,196079.999924,150.285714286,130078.623324,22.4761904762,724.9,03:16.0,02:10.0,475.99809124,162.415526871,346.516338,1.34476190476,588.944328,0.570178181642,724.9,1.84344422701,3252,50.0,191293.118277,03:11.2,02:10.0,0,150,0,0,0,0,0,130078.623324,1.9874e+11,4,0.0,0.0,0.0,0.0,0.0,29.5546558704,0.0,0.0,97.9090199034,10.2610692564,3.84382911828 +72,39799208,198779.999971,150.857142857,130276.140264,22.619047619,735.2,03:18.7,02:10.2,482.79696856,158.792546326,344.73705,1.35265306122,619.637046,0.57022048833,735.2,1.85127201566,3252,50.0,191293.118277,03:11.2,02:10.2,0,151,0,0,0,0,0,130276.140264,2.0146e+11,4,0.0,0.0,0.0,0.0,0.0,29.3172690763,0.0,0.0,99.6880916192,10.1808035361,3.83800133306 +73,39799209,201450.000048,150.904761905,130062.562971,22.4761904762,745.4,03:21.4,02:10.0,482.64500284,158.420860413,367.422972,1.35972789116,657.891738,0.565853991617,745.4,1.86692759295,3252,50.0,191293.118277,03:11.2,02:10.0,0,151,0,0,0,0,0,130062.562971,2.041e+11,4,0.0,0.0,0.0,0.0,0.0,29.5546558704,0.0,0.0,100.41503713,10.2623363112,3.84430376103 +74,39799210,204150.000095,150.761904762,129931.8979,22.380952381,756.0,03:24.1,02:09.9,486.11307118,164.310917277,362.52993,1.36333333333,631.64724,0.564496229892,756.0,1.89484126984,3252,50.0,191293.118277,03:11.2,02:09.9,0,151,0,0,0,0,0,129931.8979,2.0687e+11,4,0.0,0.0,0.0,0.0,0.0,28.4584980237,0.0,0.0,97.1078363282,10.3163699875,3.84816975723 +75,39799211,206789.999962,150.333333333,129650.504848,22.3333333333,766.3,03:26.7,02:09.6,488.3475301,163.171923972,346.516338,1.36959183673,607.626852,0.568695078615,766.3,1.87084148728,3252,50.0,191293.118277,03:11.2,02:09.6,0,150,0,0,0,0,0,129650.504848,2.0946e+11,4,0.0,0.0,0.0,0.0,0.0,29.435483871,0.0,0.0,98.4237648367,10.3608048705,3.8565218129 +76,39799212,209430.000067,150.047619048,129513.21174,22.3333333333,776.5,03:29.4,02:09.5,483.68482722,160.909752581,349.630092,1.37387755102,621.416334,0.56235824624,776.5,1.85328185328,3252,50.0,191293.118277,03:11.2,02:09.5,0,150,0,0,0,0,0,129513.21174,2.1206e+11,4,0.0,0.0,0.0,0.0,0.0,30.2040816327,0.0,0.0,100.125213958,10.3717880519,3.86060999709 +77,39799213,212069.999933,149.904761905,129546.612475,22.2857142857,786.9,03:32.0,02:09.5,484.31314586,162.91953125,361.640286,1.3762585034,648.105654,0.558736076474,786.9,1.92261904762,3252,50.0,191293.118277,03:11.2,02:09.5,0,150,0,0,0,0,0,129546.612475,2.1474e+11,4,0.0,0.0,0.0,0.0,0.0,29.1497975709,0.0,0.0,98.813597128,10.3912701416,3.85961462402 +78,39799214,214740.00001,150.0,129255.687853,22.7142857143,797.2,03:34.7,02:09.2,495.94269932,164.564744602,354.078312,1.37952380952,640.54368,0.564905581725,797.2,1.85907335907,3252,50.0,191293.118277,03:11.2,02:09.2,0,150,0,0,0,0,0,129255.687853,2.174e+11,4,0.0,0.0,0.0,0.0,0.0,29.95951417,0.0,0.0,98.4877588075,10.2181554941,3.86830172276 +79,39799215,217440.000057,150.0,128834.383844,22.6666666667,807.8,03:37.4,02:08.8,505.17584234,165.582667981,359.416176,1.3762585034,618.747402,0.573836119165,807.8,1.85328185328,3252,50.0,191293.118277,03:11.2,02:08.8,0,150,0,0,0,0,0,128834.383844,2.2014e+11,4,0.0,0.0,0.0,0.0,0.0,29.4820717131,0.0,0.0,98.8457074571,10.2731070098,3.88095153703 +80,39799216,220140.000105,149.904761905,128443.049826,22.5714285714,818.2,03:40.1,02:08.4,498.49600786,166.0932,378.543522,1.3662585034,646.771188,0.575927300163,818.2,1.96734693878,3252,50.0,191293.118277,03:11.2,02:08.4,0,150,0,0,0,0,0,128443.049826,2.2282e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,99.4453234055,10.3478851199,3.89277583084 +81,39799217,222690.000057,150.047619048,128455.953168,22.8571428571,828.4,03:42.6,02:08.4,505.13326652,167.888324643,373.65048,1.35843537415,653.88834,0.573408655065,828.4,1.85518590998,3252,50.0,191293.118277,03:11.2,02:08.4,0,150,0,0,0,0,0,128455.953168,2.2526e+11,4,0.0,0.0,0.0,0.0,0.0,28.6274509804,0.0,0.0,98.3523725736,10.2175101086,3.89238480327 +82,39799218,225480.000019,150.238095238,128266.252205,22.6666666667,839.2,03:45.4,02:08.2,509.2093793,169.049136108,354.523134,1.34931972789,640.54368,0.559644362835,839.2,1.86706349206,3252,50.0,191293.118277,03:11.2,02:08.2,0,150,0,0,0,0,0,128266.252205,2.2827e+11,4,0.0,0.0,0.0,0.0,0.0,28.9156626506,0.0,0.0,98.111038479,10.318609837,3.89814149399 +83,39799219,228119.999886,150.714285714,127899.526566,22.5238095238,849.6,03:48.1,02:07.8,505.09202214,165.582667981,395.001936,1.34285714286,705.932514,0.556293456915,849.6,1.98109243697,3252,50.0,191293.118277,03:11.2,02:07.8,0,151,0,0,0,0,0,127899.526566,2.3077e+11,4,0.0,0.0,0.0,0.0,0.0,27.6422764228,0.0,0.0,101.029070581,10.4138297132,3.90931861457 +84,39799220,230789.999962,151.285714286,127694.761218,22.3333333333,860.1,03:50.7,02:07.6,507.87618422,171.778477875,380.767632,1.34761904762,688.139634,0.559973575253,860.1,1.89134808853,3252,50.0,191293.118277,03:11.2,02:07.6,0,151,0,0,0,0,0,127694.761218,2.3344e+11,4,0.0,0.0,0.0,0.0,0.0,28.5140562249,0.0,0.0,97.8543312318,10.5194885779,3.91558741512 +85,39799221,233369.999886,151.761904762,127607.773874,22.1904761905,870.3,03:53.3,02:07.6,504.33697462,171.778477875,364.309218,1.34979591837,627.19902,0.577271613127,870.3,1.875,3252,50.0,191293.118277,03:11.2,02:07.6,0,152,0,0,0,0,0,127607.773874,2.3595e+11,4,0.0,0.0,0.0,0.0,0.0,28.8,0.0,0.0,98.0545829537,10.5944276703,3.91825658281 +86,39799222,236160.000086,151.952380952,127739.601229,22.1904761905,881.1,03:56.1,02:07.7,493.34893316,168.6616064,367.422972,1.34544217687,632.536884,0.586842804464,881.1,1.88293650794,3252,50.0,191293.118277,03:11.2,02:07.7,0,152,0,0,0,0,0,127739.601229,2.3894e+11,4,0.0,0.0,0.0,0.0,0.0,28.8,0.0,0.0,99.5577662158,10.5834942138,3.91421293937 +87,39799223,238890.000105,152.0,128505.455385,22.3333333333,891.7,03:58.8,02:08.5,490.76887478,166.860963965,362.52993,1.34027210884,596.06148,0.587689763157,891.7,1.91020408163,3252,50.0,191293.118277,03:11.2,02:08.5,0,152,0,0,0,0,0,128505.455385,2.4163e+11,4,0.0,0.0,0.0,0.0,0.0,27.4509803922,0.0,0.0,98.8436106307,10.4531249515,3.89088539861 +88,39799224,241559.999943,151.952380952,129358.03767,22.380952381,902.1,04:01.5,02:09.3,494.78014038,163.677491155,378.0987,1.3374829932,660.56067,0.58515412607,902.1,1.9,3252,50.0,191293.118277,03:11.2,02:09.3,0,152,0,0,0,0,0,129358.03767,2.4423e+11,4,0.0,0.0,0.0,0.0,0.0,27.4509803922,0.0,0.0,98.786779712,10.3621356358,3.86524107049 +89,39799225,244470.000029,152.380952381,129936.460364,22.0952380952,913.1,04:04.4,02:09.9,486.94870108,161.160065867,359.416176,1.34183673469,633.426528,0.575341883987,913.1,1.8893360161,3252,50.0,191293.118277,03:11.2,02:09.9,0,152,0,0,0,0,0,129936.460364,2.4735e+11,4,0.0,0.0,0.0,0.0,0.0,27.519379845,0.0,0.0,98.9959693609,10.4494044003,3.8480346363 +90,39799226,247259.99999,152.904761905,130664.59819,21.5714285714,923.9,04:07.2,02:10.6,487.4082597,157.802673571,365.198862,1.35659863946,622.305978,0.567196893235,923.9,1.86105675147,3252,50.0,191293.118277,03:11.2,02:10.6,0,153,0,0,0,0,0,130664.59819,2.5006e+11,4,0.0,0.0,0.0,0.0,0.0,27.969348659,0.0,0.0,99.4214002682,10.6434986683,3.82659118788 +91,39799227,250079.999924,153.666666667,131151.327866,21.3333333333,934.6,04:10.0,02:11.1,485.51861348,158.297094122,339.844008,1.36782312925,610.295784,0.576619566674,934.6,1.82476190476,3252,50.0,191293.118277,03:11.2,02:11.1,0,154,0,0,0,0,0,131151.327866,2.5291e+11,4,0.0,0.0,0.0,0.0,0.0,28.4090909091,0.0,0.0,98.0114977086,10.7223466425,3.81238991732 +92,39799228,252900.000095,154.285714286,131618.222937,21.0476190476,945.4,04:12.9,02:11.6,475.58301482,153.884319702,362.52993,1.3680952381,615.188826,0.592352808406,945.4,1.88258317025,3252,50.0,191293.118277,03:11.2,02:11.6,0,154,0,0,0,0,0,131618.222937,2.5572e+11,4,0.0,0.0,0.0,0.0,0.0,27.7566539924,0.0,0.0,99.752917618,10.829346687,3.79886606006 +93,39799229,255690.000057,154.80952381,132270.744011,20.9047619048,956.0,04:15.6,02:12.2,476.33364438,154.49223704,350.964558,1.36156462585,579.603066,0.5943440039,956.0,1.83783783784,3252,50.0,191293.118277,03:11.2,02:12.2,0,155,0,0,0,0,0,132270.744011,2.5849e+11,4,0.0,0.0,0.0,0.0,0.0,28.3524904215,0.0,0.0,97.8971375061,10.8495626707,3.78012540669 +94,39799230,258569.999933,155.285714286,132463.992308,21.0,966.7,04:18.5,02:12.4,483.659197,151.709024051,333.171678,1.35401360544,546.241416,0.595762918594,966.7,1.7980952381,3252,50.0,191293.118277,03:11.2,02:12.4,0,155,0,0,0,0,0,132463.992308,2.614e+11,4,0.0,0.0,0.0,0.0,0.0,28.4090909091,0.0,0.0,99.2574491048,10.7846019411,3.77461067939 +95,39799231,261329.999924,155.761904762,132090.300118,21.0,977.4,04:21.3,02:12.0,481.98781616,150.389822568,380.32281,1.34789115646,681.912126,0.571103232794,977.4,1.875,3252,50.0,191293.118277,03:11.2,02:12.0,0,156,0,0,0,0,0,132090.300118,2.6413e+11,4,0.0,0.0,0.0,0.0,0.0,27.5862068966,0.0,0.0,100.980337209,10.8151122928,3.78528930249 +96,39799232,264150.000095,155.952380952,131898.866612,21.0,988.1,04:24.1,02:11.8,482.59095848,157.062974746,357.636888,1.35081632653,636.985104,0.558185758971,988.1,1.85127201566,3252,50.0,191293.118277,03:11.2,02:11.8,0,156,0,0,0,0,0,131898.866612,2.6697e+11,4,0.0,0.0,0.0,0.0,0.0,27.7566539924,0.0,0.0,97.1115832126,10.8308089771,3.79078314198 +97,39799233,266970.000029,156.095238095,131929.48876,21.0952380952,998.8,04:26.9,02:11.9,482.413998,155.223848632,350.074914,1.35741496599,650.329764,0.562355052214,998.8,1.82818532819,3252,50.0,191293.118277,03:11.2,02:11.9,0,156,0,0,0,0,0,131929.48876,2.6979e+11,4,0.0,0.0,0.0,0.0,0.0,28.1368821293,0.0,0.0,98.1937754828,10.7794088307,3.78990326349 +98,39799234,269880.000114,156.0,132543.540936,20.8571428571,1009.6,04:29.8,02:12.5,465.7281801,151.2284256,338.06472,1.36204081633,567.14805,0.580949267827,1009.6,1.82285714286,3252,50.0,191293.118277,03:11.2,02:12.5,0,156,0,0,0,0,0,132543.540936,2.7276e+11,4,0.0,0.0,0.0,0.0,0.0,27.9850746269,0.0,0.0,99.3937113439,10.8519521526,3.77234527211 +99,39799235,272789.999962,156.095238095,133744.221874,20.8095238095,1020.6,04:32.7,02:13.7,466.41831992,147.420125978,347.405982,1.36789115646,583.161642,0.57806732818,1020.6,1.82476190476,3252,50.0,191293.118277,03:11.2,02:13.7,0,156,0,0,0,0,0,133744.221874,2.7573e+11,4,0.0,0.0,0.0,0.0,0.0,27.2727272727,0.0,0.0,99.2398687646,10.7791392933,3.73847926283 +100,39799236,275730.000019,155.952380952,134547.664928,20.5238095238,1031.5,04:35.7,02:14.5,473.61435974,145.189490569,338.509542,1.37292517007,591.61326,0.57139299945,1031.5,1.77551020408,3252,50.0,191293.118277,03:11.2,02:14.5,0,156,0,0,0,0,0,134547.664928,2.7864e+11,4,0.0,0.0,0.0,0.0,0.0,28.3088235294,0.0,0.0,98.9701817819,10.8639338939,3.7161551653 +101,39799237,278670.000076,155.666666667,134591.850827,20.5238095238,1042.5,04:38.6,02:14.5,480.52150734,144.489783388,349.18527,1.37204081633,657.446916,0.553762484655,1042.5,1.83428571429,3252,50.0,191293.118277,03:11.2,02:14.5,0,156,0,0,0,0,0,134591.850827,2.8163e+11,4,0.0,0.0,0.0,0.0,0.0,27.2727272727,0.0,0.0,99.3515411645,10.8603673133,3.71493516828 +102,39799238,281549.999952,155.333333333,134423.247406,20.4761904762,1053.3,04:41.5,02:14.4,472.94803454,144.606244787,356.747244,1.36782312925,633.87135,0.563911081988,1053.3,1.82857142857,3252,50.0,191293.118277,03:11.2,02:14.4,0,155,0,0,0,0,0,134423.247406,2.8444e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,99.6455359429,10.8992775233,3.71959471034 +103,39799239,284460.000038,155.047619048,134984.759451,20.380952381,1064.1,04:44.4,02:14.9,468.36794146,147.302158424,344.73705,1.35897959184,590.723616,0.58176866823,1064.1,1.76252319109,3252,50.0,191293.118277,03:11.2,02:14.9,0,155,0,0,0,0,0,134984.759451,2.8736e+11,4,0.0,0.0,0.0,0.0,0.0,28.3088235294,0.0,0.0,96.6061384746,10.9046578503,3.70412187296 +104,39799240,287490.00001,154.904761905,135735.508722,20.3333333333,1075.3,04:47.4,02:15.7,468.37251072,142.288881459,330.502746,1.34503401361,531.117468,0.602317043727,1075.3,1.79428571429,3252,50.0,191293.118277,03:11.2,02:15.7,0,155,0,0,0,0,0,135735.508722,2.9054e+11,4,0.0,0.0,0.0,0.0,0.0,26.6903914591,0.0,0.0,98.3595773926,10.8697410866,3.68363447936 +105,39799241,290430.000067,155.0,135982.562299,20.4285714286,1086.1,04:50.4,02:15.9,469.90348516,135.932254618,356.747244,1.33870748299,605.847564,0.602943727733,1086.1,1.78285714286,3252,50.0,191293.118277,03:11.2,02:15.9,0,155,0,0,0,0,0,135982.562299,2.9336e+11,4,0.0,0.0,0.0,0.0,0.0,26.4084507042,0.0,0.0,102.399034847,10.7994101869,3.67694203982 +106,39799242,293519.999981,155.0,136032.213736,20.2380952381,1097.5,04:53.5,02:16.0,476.17202572,140.910419686,370.981548,1.34136054422,621.416334,0.591585810569,1097.5,1.80308880309,3252,50.0,191293.118277,03:11.2,02:16.0,0,155,0,0,0,0,0,136032.213736,2.9661e+11,4,0.0,0.0,0.0,0.0,0.0,26.4285714286,0.0,0.0,98.673296846,10.8970728364,3.67559996467 +107,39799243,296460.000038,155.0,135481.330839,20.2857142857,1108.5,04:56.4,02:15.4,482.15046366,145.657214744,346.96116,1.34870748299,598.730412,0.581032083517,1108.5,1.80380952381,3252,50.0,191293.118277,03:11.2,02:15.4,0,155,0,0,0,0,0,135481.330839,2.9942e+11,4,0.0,0.0,0.0,0.0,0.0,27.1739130435,0.0,0.0,96.6268186374,10.9156976115,3.69054538292 +108,39799244,299339.999914,155.0,134935.69799,20.0476190476,1119.2,04:59.3,02:14.9,476.637364,142.63489588,347.405982,1.35278911565,609.850962,0.577901402085,1119.2,1.80952380952,3252,50.0,191293.118277,03:11.2,02:14.9,0,155,0,0,0,0,0,134935.69799,3.022e+11,4,0.0,0.0,0.0,0.0,0.0,27.1739130435,0.0,0.0,99.8761229337,11.0900012149,3.70546865988 +109,39799245,302460.000038,155.0,135043.604152,20.0476190476,1130.6,05:02.4,02:15.0,468.32061482,142.63489588,353.63349,1.34972789116,602.288988,0.576596521567,1130.6,1.78007518797,3252,50.0,191293.118277,03:11.2,02:15.0,0,155,0,0,0,0,0,135043.604152,3.0557e+11,4,0.0,0.0,0.0,0.0,0.0,27.0462633452,0.0,0.0,99.636897092,11.0811397846,3.70250781692 +110,39799246,305400.000095,155.095238095,135598.957647,20.2857142857,1141.3,05:05.4,02:15.5,466.61609928,142.63489588,350.074914,1.34136054422,615.188826,0.57950500723,1141.3,1.80694980695,3252,50.0,191293.118277,03:11.2,02:15.5,0,155,0,0,0,0,0,135598.957647,3.0828e+11,4,0.0,0.0,0.0,0.0,0.0,27.4074074074,0.0,0.0,98.4176977661,10.9062286695,3.68734397873 +111,39799247,308339.999914,154.952380952,135967.371232,20.2380952381,1152.4,05:08.3,02:15.9,467.18544118,142.288881459,342.51294,1.3368707483,584.496108,0.574952299315,1152.4,1.80115830116,3252,50.0,191293.118277,03:11.2,02:15.9,0,155,0,0,0,0,0,135967.371232,3.1135e+11,4,0.0,0.0,0.0,0.0,0.0,26.334519573,0.0,0.0,97.8572429727,10.9022696236,3.67735284921 +112,39799248,311309.999943,154.761904762,135961.143967,20.3333333333,1163.3,05:11.3,02:15.9,472.28473534,138.4064164,350.519736,1.33816326531,616.968114,0.565898195666,1163.3,1.81081081081,3252,50.0,191293.118277,03:11.2,02:15.9,0,155,0,0,0,0,0,135961.143967,3.1427e+11,4,0.0,0.0,0.0,0.0,0.0,26.714801444,0.0,0.0,100.616079279,10.8517021335,3.67752127858 +113,39799249,314099.999905,154.380952381,135472.697606,20.4761904762,1173.8,05:14.1,02:15.4,476.19886634,140.6815452,361.195464,1.34476190476,652.553874,0.567410171149,1173.8,1.79428571429,3252,50.0,191293.118277,03:11.2,02:15.4,0,154,0,0,0,0,0,135472.697606,3.169e+11,4,0.0,0.0,0.0,0.0,0.0,26.9784172662,0.0,0.0,100.063474348,10.8148453892,3.69078056934 +114,39799250,317039.999962,153.571428571,135069.827373,20.5714285714,1184.8,05:17.0,02:15.0,476.06675118,146.125942348,356.302422,1.34918367347,628.533486,0.568519165753,1184.8,1.8,3252,50.0,191293.118277,03:11.2,02:15.0,0,154,0,0,0,0,0,135069.827373,3.1997e+11,4,0.0,0.0,0.0,0.0,0.0,27.6752767528,0.0,0.0,97.199870211,10.7968845574,3.7017889911 +115,39799251,320039.999962,153.047619048,134758.406653,20.9523809524,1195.8,05:20.0,02:14.7,466.5308266,146.008666317,338.509542,1.35210884354,581.827176,0.566821772936,1195.8,1.82818532819,3252,50.0,191293.118277,03:11.2,02:14.7,0,153,0,0,0,0,0,134758.406653,3.2304e+11,4,0.0,0.0,0.0,0.0,0.0,27.4074074074,0.0,0.0,97.9539172087,10.6250750315,3.7103436618 +116,39799252,322980.000019,152.666666667,135247.376024,21.0952380952,1206.6,05:22.9,02:15.2,450.82037928,141.368913101,338.06472,1.35523809524,596.06148,0.563176694837,1206.6,1.77819548872,3252,50.0,191293.118277,03:11.2,02:15.2,0,152,0,0,0,0,0,135247.376024,3.2589e+11,4,0.0,0.0,0.0,0.0,0.0,27.9411764706,0.0,0.0,100.075456865,10.514968482,3.69692939485 +117,39799253,325950.000048,152.380952381,136052.446984,21.0,1217.3,05:25.9,02:16.0,459.2995944,141.02494996,331.39239,1.35605442177,616.523292,0.556395600922,1217.3,1.78759398496,3252,50.0,191293.118277,03:11.2,02:16.0,0,153,0,0,0,0,0,136052.446984,3.2886e+11,4,0.0,0.0,0.0,0.0,0.0,28.0442804428,0.0,0.0,98.549180766,10.5001524062,3.67505334217 +118,39799254,328710.000038,152.142857143,135654.45421,21.0952380952,1227.8,05:28.7,02:15.6,465.51163954,139.654676675,333.171678,1.35632653061,600.064878,0.553329814852,1227.8,1.78759398496,3252,50.0,191293.118277,03:11.2,02:15.6,0,152,0,0,0,0,0,135654.45421,3.3157e+11,4,0.0,0.0,0.0,0.0,0.0,28.4644194757,0.0,0.0,100.394607355,10.4834146762,3.68583547744 +119,39799255,331589.999914,151.80952381,135173.649715,20.8571428571,1238.7,05:31.5,02:15.1,464.95415956,142.519495485,373.205658,1.35496598639,667.233,0.543275865074,1238.7,1.82625482625,3252,50.0,191293.118277,03:11.2,02:15.1,0,152,0,0,0,0,0,135173.649715,3.3447e+11,4,0.0,0.0,0.0,0.0,0.0,27.6119402985,0.0,0.0,99.4300477765,10.6408029036,3.69894577127 +120,39799256,334500.0,151.333333333,135112.064898,20.7142857143,1249.5,05:34.5,02:15.1,466.40188874,148.721928541,328.278636,1.34945578231,595.616658,0.54902713476,1249.5,1.82818532819,3252,50.0,191293.118277,03:11.2,02:15.1,0,151,0,0,0,0,0,135112.064898,3.3743e+11,4,0.0,0.0,0.0,0.0,0.0,27.2058823529,0.0,0.0,95.4136790238,10.7190713365,3.70063177094 +121,39799257,337410.000086,150.904761905,134933.599238,20.7619047619,1260.1,05:37.4,02:14.9,464.5347257,140.795951439,336.730254,1.34741496599,648.105654,0.556663049463,1260.1,1.77255639098,3252,50.0,191293.118277,03:11.2,02:14.9,0,151,0,0,0,0,0,134933.599238,3.4029e+11,4,0.0,0.0,0.0,0.0,0.0,28.0442804428,0.0,0.0,101.185332369,10.7086310348,3.70552629458 +122,39799258,340319.999933,150.619047619,135170.211574,20.6666666667,1270.9,05:40.3,02:15.1,459.90080008,141.25419665,351.40938,1.35034013605,594.727014,0.561725982989,1270.9,1.79238095238,3252,50.0,191293.118277,03:11.2,02:15.1,0,151,0,0,0,0,0,135170.211574,3.4322e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,100.328357903,10.73914797,3.69903985633 +123,39799259,343230.000019,150.666666667,135602.343052,20.4285714286,1281.8,05:43.2,02:15.6,464.98638646,144.72276875,345.181872,1.35442176871,592.502904,0.569723096921,1281.8,1.85909980431,3252,50.0,191293.118277,03:11.2,02:15.6,0,150,0,0,0,0,0,135602.343052,3.4615e+11,4,0.0,0.0,0.0,0.0,0.0,26.7399267399,0.0,0.0,96.99058988,10.8296909587,3.68725192165 +124,39799260,346200.000048,150.714285714,135536.874693,20.4761904762,1292.7,05:46.2,02:15.5,467.51112956,142.173667796,342.068118,1.35965986395,613.85436,0.585593542607,1292.7,1.79323308271,3252,50.0,191293.118277,03:11.2,02:15.5,0,151,0,0,0,0,0,135536.874693,3.4917e+11,4,0.0,0.0,0.0,0.0,0.0,27.5362318841,0.0,0.0,98.8727185455,10.8097245298,3.68903297447 +125,39799261,349079.999924,150.761904762,135425.973283,20.4761904762,1303.4,05:49.0,02:15.4,466.74228348,140.910419686,331.837212,1.36217687075,572.485914,0.575030221445,1303.4,1.74542124542,3252,50.0,191293.118277,03:11.2,02:15.4,0,151,0,0,0,0,0,135425.973283,3.5198e+11,4,0.0,0.0,0.0,0.0,0.0,28.5714285714,0.0,0.0,100.004384112,10.8185766995,3.69205395302 +126,39799262,351990.00001,151.142857143,135481.539224,20.4285714286,1314.3,05:51.9,02:15.4,471.5936272,141.25419665,358.08171,1.36081632653,597.840768,0.576985128294,1314.3,1.78947368421,3252,50.0,191293.118277,03:11.2,02:15.4,0,151,0,0,0,0,0,135481.539224,3.5489e+11,4,0.0,0.0,0.0,0.0,0.0,27.9411764706,0.0,0.0,99.6383021711,10.8393473897,3.69053970648 +127,39799263,354960.000038,151.333333333,135051.927441,20.7619047619,1325.2,05:54.9,02:15.0,474.18336878,146.008666317,345.181872,1.35802721088,623.640444,0.572062929127,1325.2,1.83590733591,3252,50.0,191293.118277,03:11.2,02:15.0,0,151,0,0,0,0,0,135051.927441,3.5792e+11,4,0.0,0.0,0.0,0.0,0.0,26.714801444,0.0,0.0,97.3166274991,10.699248473,3.70227963033 +128,39799264,357869.999886,151.666666667,134819.049813,20.619047619,1336.1,05:57.8,02:14.8,467.4154777,142.865883521,348.295626,1.36115646259,608.071674,0.564547005389,1336.1,1.81333333333,3252,50.0,191293.118277,03:11.2,02:14.8,0,152,0,0,0,0,0,134819.049813,3.6078e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,99.9736911607,10.7919864439,3.70867470652 +129,39799265,360779.999971,151.952380952,135272.90821,20.5238095238,1346.9,06:00.7,02:15.2,455.47560794,144.373384534,335.84061,1.36503401361,610.740606,0.563426030056,1346.9,1.76437847866,3252,50.0,191293.118277,03:11.2,02:15.2,0,152,0,0,0,0,0,135272.90821,3.637e+11,4,0.0,0.0,0.0,0.0,0.0,28.0,0.0,0.0,97.937367391,10.8056887126,3.69623161517 +130,39799266,363690.000057,152.0,135946.220926,20.380952381,1357.4,06:03.6,02:15.9,458.91508058,141.25419665,320.716662,1.36170068027,550.244814,0.574332484059,1357.4,1.80639097744,3252,50.0,191293.118277,03:11.2,02:15.9,0,152,0,0,0,0,0,135946.220926,3.6655e+11,4,0.0,0.0,0.0,0.0,0.0,28.5714285714,0.0,0.0,98.6200609246,10.8275361154,3.67792496617 +131,39799267,366539.999962,152.142857143,135707.336479,20.5238095238,1368.1,06:06.5,02:15.7,453.16259406,138.18026217,342.51294,1.35258503401,590.278794,0.573720093413,1368.1,1.80952380952,3252,50.0,191293.118277,03:11.2,02:15.7,0,152,0,0,0,0,0,135707.336479,3.6945e+11,4,0.0,0.0,0.0,0.0,0.0,27.6752767528,0.0,0.0,101.34726938,10.7710973871,3.68439918557 +132,39799268,369450.000048,152.285714286,135871.183186,20.619047619,1379.0,06:09.4,02:15.8,455.26642056,141.943427083,352.299024,1.34517006803,610.295784,0.584665452957,1379.0,1.73283858998,3252,50.0,191293.118277,03:11.2,02:15.8,0,152,0,0,0,0,0,135871.183186,3.7236e+11,4,0.0,0.0,0.0,0.0,0.0,28.5185185185,0.0,0.0,98.3038859372,10.7084175161,3.67995617816 +133,39799269,372329.999924,152.333333333,135911.92446,20.7619047619,1389.5,06:12.3,02:15.9,454.40304224,144.72276875,323.385594,1.33952380952,565.813584,0.57809127753,1389.5,1.85714285714,3252,50.0,191293.118277,03:11.2,02:15.9,0,153,0,0,0,0,0,135911.92446,3.7519e+11,4,0.0,0.0,0.0,0.0,0.0,26.8656716418,0.0,0.0,96.3293202928,10.6315478511,3.67885306595 +134,39799270,375150.000095,152.380952381,136089.743077,20.5238095238,1399.9,06:15.1,02:16.0,446.34779998,137.615954692,339.399186,1.34727891156,568.927338,0.575237962562,1399.9,1.80380952381,3252,50.0,191293.118277,03:11.2,02:16.0,0,152,0,0,0,0,0,136089.743077,3.7798e+11,4,0.0,0.0,0.0,0.0,0.0,27.6752767528,0.0,0.0,100.907413543,10.7408310451,3.67404617493 +135,39799271,378089.999914,152.095238095,136630.270895,20.3333333333,1410.7,06:18.0,02:16.6,457.51715936,138.4064164,330.947568,1.36482993197,595.171836,0.572597794735,1410.7,1.74175824176,3252,50.0,191293.118277,03:11.2,02:16.6,0,152,0,0,0,0,0,136630.270895,3.8102e+11,4,0.0,0.0,0.0,0.0,0.0,28.1588447653,0.0,0.0,99.1450490667,10.7985574969,3.65951115171 +136,39799272,381150.000095,151.476190476,136418.047659,20.1904761905,1422.0,06:21.1,02:16.4,470.8275953,139.199899252,334.950966,1.37551020408,584.051286,0.576811197542,1422.0,1.76556776557,3252,50.0,191293.118277,03:11.2,02:16.4,0,152,0,0,0,0,0,136418.047659,3.8423e+11,4,0.0,0.0,0.0,0.0,0.0,28.1588447653,0.0,0.0,99.0406846396,10.8918803787,3.66520419093 +137,39799273,384029.999971,151.476190476,135619.718841,20.0952380952,1432.8,06:24.0,02:15.6,468.96106772,141.02494996,359.860998,1.37557823129,624.085266,0.570099974688,1432.8,1.84761904762,3252,50.0,191293.118277,03:11.2,02:15.6,0,151,0,0,0,0,0,135619.718841,3.8691e+11,4,0.0,0.0,0.0,0.0,0.0,27.8810408922,0.0,0.0,99.495530275,11.0079198513,3.68677950576 +138,39799274,387000.0,151.238095238,135248.659164,20.380952381,1443.6,06:27.0,02:15.2,471.66113726,145.657214744,335.395788,1.36843537415,569.37216,0.579103403429,1443.6,1.81904761905,3252,50.0,191293.118277,03:11.2,02:15.2,0,151,0,0,0,0,0,135248.659164,3.8992e+11,4,0.0,0.0,0.0,0.0,0.0,27.5735294118,0.0,0.0,97.1263656849,10.883380478,3.69689432109 +139,39799275,389880.000114,151.285714286,135020.184383,20.619047619,1454.4,06:29.8,02:15.0,474.42741568,142.750358554,339.844008,1.35217687075,611.63025,0.576122113145,1454.4,1.75139146568,3252,50.0,191293.118277,03:11.2,02:15.0,0,152,0,0,0,0,0,135020.184383,3.928e+11,4,0.0,0.0,0.0,0.0,0.0,28.3088235294,0.0,0.0,99.6081207115,10.7759100213,3.70315003112 +140,39799276,392789.999962,151.523809524,134604.605094,20.8095238095,1465.1,06:32.7,02:14.6,468.0654625,143.328606672,358.971354,1.33258503401,607.626852,0.574599185498,1465.1,1.85912698413,3252,50.0,191293.118277,03:11.2,02:14.6,0,151,0,0,0,0,0,134604.605094,3.9566e+11,4,0.0,0.0,0.0,0.0,0.0,26.8656716418,0.0,0.0,100.127969837,10.7102397889,3.71458316489 +141,39799277,395640.000105,151.857142857,134531.510854,20.9523809524,1475.9,06:35.6,02:14.5,467.13629894,145.3063276,364.75404,1.3274829932,641.878146,0.575502759115,1475.9,1.81409001957,3252,50.0,191293.118277,03:11.2,02:14.5,0,152,0,0,0,0,0,134531.510854,3.9851e+11,4,0.0,0.0,0.0,0.0,0.0,27.4436090226,0.0,0.0,98.9262300291,10.6429948844,3.71660138822 +142,39799278,398490.00001,152.095238095,134717.801846,21.0476190476,1486.6,06:38.4,02:14.7,465.17181974,148.129254179,339.844008,1.32952380952,587.16504,0.580404599147,1486.6,1.80626223092,3252,50.0,191293.118277,03:11.2,02:14.7,0,152,0,0,0,0,0,134717.801846,4.0137e+11,4,0.0,0.0,0.0,0.0,0.0,27.037037037,0.0,0.0,96.6389592792,10.5801857438,3.71146198313 +143,39799279,401430.000067,152.80952381,135058.857384,20.5714285714,1497.4,06:41.4,02:15.0,459.83634628,142.519495485,334.061322,1.33897959184,574.710024,0.572980352813,1497.4,1.82432432432,3252,50.0,191293.118277,03:11.2,02:15.0,0,153,0,0,0,0,0,135058.857384,4.0436e+11,4,0.0,0.0,0.0,0.0,0.0,27.1062271062,0.0,0.0,99.6837929441,10.797761521,3.70208966435 +144,39799280,404369.999886,153.380952381,135382.877147,20.4761904762,1508.2,06:44.3,02:15.3,462.27917556,139.427164349,353.63349,1.35387755102,619.192224,0.57310518315,1508.2,1.77819548872,3252,50.0,191293.118277,03:11.2,02:15.3,0,153,0,0,0,0,0,135382.877147,4.0729e+11,4,0.0,0.0,0.0,0.0,0.0,27.8388278388,0.0,0.0,101.164800904,10.8220205535,3.69322923651 +145,39799281,407309.999943,153.714285714,135730.342589,20.2380952381,1519.2,06:47.3,02:15.7,467.68470092,143.676303949,341.178474,1.36503401361,601.399344,0.577255450082,1519.2,1.77179962894,3252,50.0,191293.118277,03:11.2,02:15.7,0,154,0,0,0,0,0,135730.342589,4.1027e+11,4,0.0,0.0,0.0,0.0,0.0,27.8985507246,0.0,0.0,97.4208829178,10.9213084776,3.68377468489 +146,39799282,410279.999971,153.619047619,135519.060217,20.2857142857,1530.0,06:50.2,02:15.5,473.7156097,143.328606672,343.402584,1.36544217687,591.61326,0.578325132737,1530.0,1.85135135135,3252,50.0,191293.118277,03:11.2,02:15.5,0,154,0,0,0,0,0,135519.060217,4.1321e+11,4,0.0,0.0,0.0,0.0,0.0,27.0072992701,0.0,0.0,98.1146867082,10.9126586111,3.68951791136 +147,39799283,413160.000086,153.428571429,135030.376252,20.7142857143,1540.9,06:53.1,02:15.0,470.76256656,141.25419665,338.954364,1.36789115646,567.14805,0.582445358297,1540.9,1.77365491651,3252,50.0,191293.118277,03:11.2,02:15.0,0,153,0,0,0,0,0,135030.376252,4.1609e+11,4,0.0,0.0,0.0,0.0,0.0,28.2051282051,0.0,0.0,100.640376183,10.7255559991,3.7028705235 +148,39799284,415950.000048,153.142857143,135084.603998,20.7619047619,1551.3,06:55.9,02:15.0,463.76388246,143.328606672,357.192066,1.36448979592,628.088664,0.583689111117,1551.3,1.81523809524,3252,50.0,191293.118277,03:11.2,02:15.0,0,153,0,0,0,0,0,135084.603998,4.1871e+11,4,0.0,0.0,0.0,0.0,0.0,27.6752767528,0.0,0.0,99.0643976896,10.6966603571,3.70138406006 +149,39799285,419039.999962,152.857142857,135426.313714,20.4285714286,1562.6,06:59.0,02:15.4,464.7047869,145.89145305,331.39239,1.36265306122,568.927338,0.579244873232,1562.6,1.79887218045,3252,50.0,191293.118277,03:11.2,02:15.4,0,153,0,0,0,0,0,135426.313714,4.221e+11,4,0.0,0.0,0.0,0.0,0.0,27.5362318841,0.0,0.0,96.58930096,10.8437675682,3.69204467202 +150,39799286,421950.000048,152.666666667,135393.051047,20.4761904762,1573.3,07:01.9,02:15.3,469.49915104,140.910419686,329.613102,1.36176870748,571.151448,0.571828605124,1573.3,1.78571428571,3252,50.0,191293.118277,03:11.2,02:15.3,0,153,0,0,0,0,0,135393.051047,4.2488e+11,4,0.0,0.0,0.0,0.0,0.0,27.7372262774,0.0,0.0,100.077353187,10.8212073496,3.69295171453 +151,39799287,424890.000105,152.333333333,135335.644206,20.4761904762,1584.2,07:04.8,02:15.3,463.31385574,139.199899252,360.750642,1.35925170068,631.64724,0.574232861636,1584.2,1.79323308271,3252,50.0,191293.118277,03:11.2,02:15.3,0,152,0,0,0,0,0,135335.644206,4.2782e+11,4,0.0,0.0,0.0,0.0,0.0,27.7372262774,0.0,0.0,101.4360992,10.8257975027,3.69451819536 +152,39799288,427650.000095,152.047619048,135640.381081,20.4285714286,1594.6,07:07.6,02:15.6,462.32556414,145.3063276,345.626694,1.35578231293,609.850962,0.574948423137,1594.6,1.80761904762,3252,50.0,191293.118277,03:11.2,02:15.6,0,152,0,0,0,0,0,135640.381081,4.3043e+11,4,0.0,0.0,0.0,0.0,0.0,27.4725274725,0.0,0.0,96.5198223331,10.8266539568,3.68621789483 +153,39799289,430769.999981,151.904761905,135755.601608,20.6666666667,1606.0,07:10.7,02:15.7,463.34272378,143.328606672,325.164882,1.35476190476,558.696432,0.57418260892,1606.0,1.77819548872,3252,50.0,191293.118277,03:11.2,02:15.7,0,152,0,0,0,0,0,135755.601608,4.3388e+11,4,0.0,0.0,0.0,0.0,0.0,27.4368231047,0.0,0.0,97.6027129202,10.6928398242,3.68308927277 +154,39799290,433500.0,152.095238095,135778.261376,20.8571428571,1616.2,07:13.5,02:15.7,455.75194226,137.728693043,337.175076,1.35047619048,582.271998,0.570176939833,1616.2,1.80380952381,3252,50.0,191293.118277,03:11.2,02:15.7,0,152,0,0,0,0,0,135778.261376,4.3627e+11,4,0.0,0.0,0.0,0.0,0.0,27.1739130435,0.0,0.0,101.520298996,10.5934201087,3.68247460922 +155,39799291,436559.999943,151.857142857,136008.019233,20.6666666667,1627.4,07:16.5,02:16.0,462.31796888,139.882436364,356.302422,1.34870748299,638.764392,0.569221632348,1627.4,1.8,3252,50.0,191293.118277,03:11.2,02:16.0,0,152,0,0,0,0,0,136008.019233,4.3958e+11,4,0.0,0.0,0.0,0.0,0.0,27.5735294118,0.0,0.0,99.4514934249,10.6729949558,3.67625381812 +156,39799292,439440.000057,151.80952381,135665.72469,20.5238095238,1638.0,07:19.4,02:15.6,473.08898562,144.024563085,341.623296,1.34448979592,608.071674,0.567993168719,1638.0,1.76691729323,3252,50.0,191293.118277,03:11.2,02:15.6,0,152,0,0,0,0,0,135665.72469,4.4228e+11,4,0.0,0.0,0.0,0.0,0.0,27.8388278388,0.0,0.0,97.3242489105,10.7744011297,3.68552927531 +157,39799293,442440.000057,151.619047619,135182.475263,20.3333333333,1649.2,07:22.4,02:15.1,469.43076344,142.750358554,350.964558,1.34108843537,604.068276,0.56991134906,1649.2,1.8166023166,3252,50.0,191293.118277,03:11.2,02:15.1,0,151,0,0,0,0,0,135182.475263,4.4549e+11,4,0.0,0.0,0.0,0.0,0.0,26.8115942029,0.0,0.0,99.2498030347,10.9142093544,3.69870428121 +158,39799294,445380.000114,151.380952381,135350.796391,20.0952380952,1660.2,07:25.3,02:15.3,461.95330562,142.519495485,352.743846,1.34394557823,612.519894,0.577038136948,1660.2,1.80888030888,3252,50.0,191293.118277,03:11.2,02:15.3,0,152,0,0,0,0,0,135350.796391,4.4833e+11,4,0.0,0.0,0.0,0.0,0.0,26.8115942029,0.0,0.0,99.0401573532,11.0297909954,3.69410460323 +159,39799295,448259.99999,151.285714286,135812.873651,20.2380952381,1670.8,07:28.2,02:15.8,459.0357272,141.483691644,332.726856,1.35428571429,584.496108,0.573893979377,1670.8,1.77819548872,3252,50.0,191293.118277,03:11.2,02:15.8,0,151,0,0,0,0,0,135812.873651,4.5114e+11,4,0.0,0.0,0.0,0.0,0.0,28.4644194757,0.0,0.0,98.750395978,10.9146717931,3.68153612069 +160,39799296,451140.000105,151.095238095,136053.741379,20.6666666667,1681.4,07:31.1,02:16.0,454.00415492,140.224539997,332.726856,1.36387755102,579.603066,0.565565878403,1681.4,1.79887218045,3252,50.0,191293.118277,03:11.2,02:16.0,0,151,0,0,0,0,0,136053.741379,4.5402e+11,4,0.0,0.0,0.0,0.0,0.0,28.0442804428,0.0,0.0,99.1088765411,10.669408195,3.67501837828 +161,39799297,454049.999952,150.571428571,136050.158308,20.9523809524,1692.1,07:34.0,02:16.0,460.1101085,140.224539997,331.39239,1.36965986395,598.730412,0.557429377781,1692.1,1.76373626374,3252,50.0,191293.118277,03:11.2,02:16.0,0,151,0,0,0,0,0,136050.158308,4.5695e+11,4,0.0,0.0,0.0,0.0,0.0,28.7822878229,0.0,0.0,99.1167072582,10.5241934271,3.67511516501 +162,39799298,456839.999914,150.333333333,135508.685793,21.1904761905,1702.5,07:36.8,02:15.5,467.22011914,141.25419665,342.957762,1.36659863946,616.523292,0.560940991906,1702.5,1.79511278195,3252,50.0,191293.118277,03:11.2,02:15.5,0,150,0,0,0,0,0,135508.685793,4.5964e+11,4,0.0,0.0,0.0,0.0,0.0,28.2527881041,0.0,0.0,99.5784322917,10.4475246645,3.68980037756 +163,39799299,459839.999914,150.047619048,135121.507637,20.8571428571,1713.7,07:39.8,02:15.1,468.19403724,143.90841425,354.078312,1.35707482993,636.540282,0.562610728352,1713.7,1.80761904762,3252,50.0,191293.118277,03:11.2,02:15.1,0,150,0,0,0,0,0,135121.507637,4.6283e+11,4,0.0,0.0,0.0,0.0,0.0,27.8810408922,0.0,0.0,98.5844481751,10.6449090862,3.70037315852 +164,39799300,462750.0,149.904761905,135122.935,20.7142857143,1724.4,07:42.7,02:15.1,460.93820366,145.657214744,337.175076,1.34870748299,573.82038,0.566754084449,1724.4,1.82432432432,3252,50.0,191293.118277,03:11.2,02:15.1,0,150,0,0,0,0,0,135122.935,4.6566e+11,4,0.0,0.0,0.0,0.0,0.0,27.2058823529,0.0,0.0,97.397729605,10.7182090299,3.70033406986 +165,39799301,465690.000057,149.904761905,135409.984588,20.7619047619,1735.1,07:45.6,02:15.4,460.1344678,141.02494996,338.509542,1.34823129252,604.95792,0.574200782538,1735.1,1.76879699248,3252,50.0,191293.118277,03:11.2,02:15.4,0,150,0,0,0,0,0,135409.984588,4.6859e+11,4,0.0,0.0,0.0,0.0,0.0,28.0442804428,0.0,0.0,99.958567598,10.6709570408,3.69248989667 +166,39799302,468539.999962,150.142857143,135705.405237,20.4761904762,1745.6,07:48.5,02:15.7,451.04914488,140.338698368,329.16828,1.35238095238,580.937532,0.569293296429,1745.6,1.77819548872,3252,50.0,191293.118277,03:11.2,02:15.7,0,150,0,0,0,0,0,135705.405237,4.7139e+11,4,0.0,0.0,0.0,0.0,0.0,28.679245283,0.0,0.0,99.7927892396,10.7963000922,3.68445161877 +167,39799303,471390.000105,150.285714286,136086.491159,20.7142857143,1756.3,07:51.3,02:16.0,446.03839148,141.02494996,346.516338,1.35891156463,593.392548,0.56601285805,1756.3,1.83976833977,3252,50.0,191293.118277,03:11.2,02:16.0,0,150,0,0,0,0,0,136086.491159,4.7428e+11,4,0.0,0.0,0.0,0.0,0.0,27.4074074074,0.0,0.0,98.4752383869,10.642319085,3.67413396981 +168,39799304,474059.999943,150.333333333,136277.633993,20.9523809524,1766.2,07:54.0,02:16.2,440.85237216,141.483691644,308.706468,1.36414965986,565.368762,0.5702633677,1766.2,1.74908424908,3252,50.0,191293.118277,03:11.2,02:16.2,0,151,0,0,0,0,0,136277.633993,4.7673e+11,4,0.0,0.0,0.0,0.0,0.0,28.4671532847,0.0,0.0,97.7435046018,10.5066263617,3.66898063425 +169,39799305,477059.999943,150.285714286,136497.120011,21.1904761905,1777.1,07:57.0,02:16.4,442.06706908,137.728693043,319.827018,1.36027210884,551.134458,0.560617166152,1777.1,1.79323308271,3252,50.0,191293.118277,03:11.2,02:16.4,0,150,0,0,0,0,0,136497.120011,4.8006e+11,4,0.0,0.0,0.0,0.0,0.0,28.5714285714,0.0,0.0,99.9247691213,10.3718696553,3.66308094969 +170,39799306,479880.000114,150.238095238,136580.031401,21.4285714286,1787.5,07:59.8,02:16.5,432.87365744,137.728693043,330.057924,1.35183673469,588.499506,0.562084297404,1787.5,1.78195488722,3252,50.0,191293.118277,03:11.2,02:16.5,0,150,0,0,0,0,0,136580.031401,4.8271e+11,4,0.0,0.0,0.0,0.0,0.0,29.1187739464,0.0,0.0,99.7429005188,10.2504003377,3.66085726348 +171,39799307,482609.999895,149.857142857,136811.69351,21.4761904762,1797.7,08:02.6,02:16.8,449.45807408,139.76852559,336.730254,1.34448979592,614.744004,0.574192025951,1797.7,1.80888030888,3252,50.0,191293.118277,03:11.2,02:16.8,0,150,0,0,0,0,0,136811.69351,4.8534e+11,4,0.0,0.0,0.0,0.0,0.0,28.5714285714,0.0,0.0,97.7887746272,10.2103537446,3.65465836415 +172,39799308,485579.999924,149.666666667,136176.08526,21.3333333333,1808.4,08:05.5,02:16.1,450.0774055,140.224539997,318.492552,1.34136054422,534.231222,0.567041996588,1808.4,1.78857142857,3252,50.0,191293.118277,03:11.2,02:16.1,0,150,0,0,0,0,0,136176.08526,4.8854e+11,4,0.0,0.0,0.0,0.0,0.0,28.1954887218,0.0,0.0,98.841991041,10.3267030868,3.67171665307 +173,39799309,488279.999971,149.428571429,135744.803044,21.4285714286,1818.4,08:08.2,02:15.7,446.29018494,138.4064164,356.302422,1.34741496599,620.081868,0.570033589223,1818.4,1.79619047619,3252,50.0,191293.118277,03:11.2,02:15.7,0,149,0,0,0,0,0,135744.803044,4.9094e+11,4,0.0,0.0,0.0,0.0,0.0,28.1954887218,0.0,0.0,101.097911766,10.31347034,3.68338226429 +174,39799310,491069.999933,149.0,135655.993062,21.2380952381,1828.9,08:11.0,02:15.6,452.80389202,145.657214744,319.827018,1.35897959184,586.275396,0.57254419599,1828.9,1.78383458647,3252,50.0,191293.118277,03:11.2,02:15.6,0,149,0,0,0,0,0,135655.993062,4.9388e+11,4,0.0,0.0,0.0,0.0,0.0,29.2307692308,0.0,0.0,96.2540669287,10.4127803124,3.68579366613 +175,39799311,494039.999962,148.666666667,135300.864262,21.2857142857,1839.9,08:14.0,02:15.3,457.61477812,141.713435077,326.054526,1.36326530612,563.144652,0.568145934555,1839.9,1.80263157895,3252,50.0,191293.118277,03:11.2,02:15.3,0,149,0,0,0,0,0,135300.864262,4.9705e+11,4,0.0,0.0,0.0,0.0,0.0,28.2527881041,0.0,0.0,99.7138091099,10.4167551393,3.69546789466 +176,39799312,496890.000105,148.285714286,134976.811268,21.2380952381,1850.5,08:16.8,02:14.9,450.62353798,141.483691644,347.850804,1.36238095238,599.620056,0.571160947145,1850.5,1.82285714286,3252,50.0,191293.118277,03:11.2,02:14.9,0,148,0,0,0,0,0,134976.811268,4.9972e+11,4,0.0,0.0,0.0,0.0,0.0,28.4090909091,0.0,0.0,100.596800752,10.4651757627,3.7043399922 +177,39799313,499769.999981,147.619047619,135463.633431,20.8571428571,1861.2,08:19.7,02:15.4,456.67402498,144.839355293,330.502746,1.3587755102,574.710024,0.579918778356,1861.2,1.75510204082,3252,50.0,191293.118277,03:11.2,02:15.4,0,148,0,0,0,0,0,135463.633431,5.0265e+11,4,0.0,0.0,0.0,0.0,0.0,28.7313432836,0.0,0.0,97.2105277427,10.6180243948,3.69102752773 +178,39799314,502710.000038,147.19047619,135766.017193,20.5714285714,1871.9,08:22.7,02:15.7,451.3696588,142.519495485,330.947568,1.3568707483,584.496108,0.576471579536,1871.9,1.83204633205,3252,50.0,191293.118277,03:11.2,02:15.7,0,147,0,0,0,0,0,135766.017193,5.0564e+11,4,0.0,0.0,0.0,0.0,0.0,27.1062271062,0.0,0.0,98.1342334945,10.74151959,3.68280671656 +179,39799315,505680.000067,147.428571429,136042.640233,20.4761904762,1882.6,08:25.6,02:16.0,459.4732868,138.519585991,334.506144,1.36469387755,568.482516,0.575279416416,1882.6,1.81904761905,3252,50.0,191293.118277,03:11.2,02:16.0,0,147,0,0,0,0,0,136042.640233,5.0859e+11,4,0.0,0.0,0.0,0.0,0.0,27.6752767528,0.0,0.0,100.353310532,10.7695372316,3.67531826158 +180,39799316,508500.0,147.80952381,135635.192846,20.3333333333,1893.3,08:28.5,02:15.6,468.43714608,139.5408896,335.395788,1.37870748299,590.278794,0.567668322861,1893.3,1.74321880651,3252,50.0,191293.118277,03:11.2,02:15.6,0,148,0,0,0,0,0,135635.192846,5.1138e+11,4,0.0,0.0,0.0,0.0,0.0,29.3680297398,0.0,0.0,100.519284677,10.8777803541,3.68635889778 +181,39799317,511410.000086,148.571428571,135228.054118,20.2380952381,1904.3,08:31.4,02:15.2,469.18608108,144.373384534,358.971354,1.38632653061,637.874748,0.568806989976,1904.3,1.80705009276,3252,50.0,191293.118277,03:11.2,02:15.2,0,149,0,0,0,0,0,135228.054118,5.1434e+11,4,0.0,0.0,0.0,0.0,0.0,28.0,0.0,0.0,98.0348549052,10.9618743747,3.6974576264 +182,39799318,514440.000057,149.333333333,135091.590969,20.2857142857,1915.4,08:34.4,02:15.0,472.29378308,148.129254179,322.051128,1.38857142857,586.720218,0.558225432086,1915.4,1.80705009276,3252,50.0,191293.118277,03:11.2,02:15.0,0,149,0,0,0,0,0,135091.590969,5.1746e+11,4,0.0,0.0,0.0,0.0,0.0,27.4021352313,0.0,0.0,95.8389967843,10.9471894499,3.70119262355 +183,39799319,517410.000086,150.142857143,135165.185389,20.1428571429,1926.2,08:37.4,02:15.1,470.79285682,139.313500906,336.285432,1.38523809524,580.49271,0.552451093149,1926.2,1.81578947368,3252,50.0,191293.118277,03:11.2,02:15.1,0,150,0,0,0,0,0,135165.185389,5.2034e+11,4,0.0,0.0,0.0,0.0,0.0,27.8388278388,0.0,0.0,101.737322801,11.0188263186,3.69917740697 +184,39799320,520380.000114,150.857142857,135528.874331,19.9047619048,1937.3,08:40.3,02:15.5,462.43652756,140.338698368,350.519736,1.38006802721,656.557272,0.549901547877,1937.3,1.79220779221,3252,50.0,191293.118277,03:11.2,02:15.5,0,151,0,0,0,0,0,135528.874331,5.2335e+11,4,0.0,0.0,0.0,0.0,0.0,28.0,0.0,0.0,100.183247751,11.1207079741,3.68925074061 +185,39799321,523170.000076,151.761904762,135908.232418,19.9047619048,1947.8,08:43.1,02:15.9,469.9886368,144.1407744,335.84061,1.37489795918,609.850962,0.56103077658,1947.8,1.7866419295,3252,50.0,191293.118277,03:11.2,02:15.9,0,152,0,0,0,0,0,135908.232418,5.26e+11,4,0.0,0.0,0.0,0.0,0.0,28.0,0.0,0.0,96.726149754,11.0896669516,3.67895300457 +186,39799322,526230.000019,152.380952381,135536.044927,20.0476190476,1959.1,08:46.2,02:15.5,464.41203653,141.943427083,332.726856,1.37003401361,576.489312,0.578327192904,1959.1,1.80639097744,3252,50.0,191293.118277,03:11.2,02:15.5,0,152,0,0,0,0,0,135536.044927,5.293e+11,4,0.0,0.0,0.0,0.0,0.0,27.6363636364,0.0,0.0,99.0349148838,11.0408788706,3.68905555914 +187,39799323,529140.000105,152.666666667,135676.953847,20.3333333333,1969.8,08:49.1,02:15.6,463.23852347,140.11044355,347.850804,1.36343537415,569.37216,0.593066463629,1969.8,1.79135338346,3252,50.0,191293.118277,03:11.2,02:15.6,0,153,0,0,0,0,0,135676.953847,5.3203e+11,4,0.0,0.0,0.0,0.0,0.0,28.0442804428,0.0,0.0,100.018257266,10.8744322026,3.68522424644 +188,39799324,532049.999952,152.904761905,135784.677306,20.7380952381,1980.6,08:52.0,02:15.7,471.712087535,142.63489588,340.28883,1.35807823129,561.365364,0.594141310259,1980.6,1.78665413534,3252,50.0,191293.118277,03:11.2,02:15.7,0,153,0,0,0,0,0,135784.677306,5.3497e+11,4,0.0,0.0,0.0,0.0,0.0,27.8388278388,0.0,0.0,98.0144170752,10.6537285142,3.68230060946 +189,39799325,534960.000038,153.261904762,135356.212775,21.0238095238,1991.4,08:54.9,02:15.3,480.500726285,142.63489588,356.302422,1.35675170068,632.536884,0.591064693856,1991.4,1.81047619048,3252,50.0,191293.118277,03:11.2,02:15.3,0,153,0,0,0,0,0,135356.212775,5.3786e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,98.9481483694,10.5422096122,3.69395678078 +190,39799326,537240.00001,153.904761905,134031.309351,21.0238095238,2000.0,08:57.2,02:14.0,485.32090977,146.713264566,356.302422,1.36183673469,595.616658,0.587622263206,2000.0,1.81523809524,3252,50.0,191293.118277,03:11.2,02:14.0,0,154,0,0,0,0,0,134031.309351,5.3946e+11,4,0.0,0.0,0.0,0.0,0.0,27.7777777778,0.0,0.0,99.0786049127,10.6464196634,3.7304716519 diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index b1ad33b0..1511c6ab 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -250,7 +250,7 @@ class DataTest(TestCase): form = RowerForm(data=form_data) self.assertFalse(form.is_valid()) - def test_painsled(self): + def test_painsled_form(self): filename = 'rowers/tests/testdata/testdata.csv' f = open(filename,'rb') file_data = {'file': SimpleUploadedFile(f.name, f.read())} @@ -263,61 +263,122 @@ class DataTest(TestCase): form = DocumentsForm(form_data,file_data) self.assertTrue(form.is_valid()) - + f.close() +class InteractiveChartTest(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u,gdproptin=True, + gdproptindate=timezone.now() + ) + self.nu = datetime.datetime.now() + + self.filename = 'rowers/tests/testdata/testdata.csv' + self.wotw = Workout.objects.create(name='testworkout', + workouttype='water', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=self.filename) + + self.wote = Workout.objects.create(name='testworkout', + workouttype='Indoor Rower', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=self.filename) + + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_painsled(self, mocked_sqlalchemy, mocked_read_df_sql): u = User.objects.get(username='john') r = Rower.objects.get(user=u) rr = rrower(hrmax=r.max,hrut2=r.ut2, hrut1=r.ut1,hrat=r.at, hrtr=r.tr,hran=r.an,ftp=r.ftp) - row = rdata(filename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - w = Workout.objects.create(name='testworkout',workouttype='water', - user=r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - duration=duration,distance=totaldist, - csvfilename=filename) - + row = rdata(self.filename,rower=rr) fig1 = plots.mkplot(row,'test') - res = iplots.interactive_chart(w.id) - res = iplots.interactive_chart(w.id,promember=1) - res = iplots.interactive_bar_chart(w.id) - res = iplots.interactive_bar_chart(w.id,promember=1) - res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', - yparam1='pace',yparam2='spm') - res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', - yparam1='pace',yparam2='spm') - res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', - yparam1='pace',yparam2='spm') - res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', - yparam1='pace',yparam2='spm') + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart1(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_chart(self.wote.id) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart2(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_chart(self.wote.id,promember=1) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart3(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_bar_chart(self.wote.id) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart4(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_bar_chart(self.wote.id,promember=1) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart5(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id,promember=0, + xparam='time', + yparam1='pace',yparam2='hr') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart6(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id, + promember=0,xparam='distance', + yparam1='pace',yparam2='hr') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart7(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id,promember=0, + xparam='time', + yparam1='pace',yparam2='spm') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart8(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id, + promember=0,xparam='distance', + yparam1='pace',yparam2='spm') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart9(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id, + promember=1,xparam='time', + yparam1='pace',yparam2='hr') + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart10(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id, + promember=1,xparam='distance', + yparam1='pace',yparam2='hr') + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart11(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id, + promember=1,xparam='time', + yparam1='pace',yparam2='spm') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + def test_interactive_chart12(self, mocked_sqlalchemy,mocked_read_df_sql): + res = iplots.interactive_flex_chart2(self.wote.id,promember=1, + xparam='distance', + yparam1='pace',yparam2='spm') @@ -540,7 +601,8 @@ class ViewTest(TestCase): @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_CN(self, mocked_sqlalchemy): + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_CN(self, mocked_sqlalchemy, mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/crewnerddata.tcx' @@ -588,7 +650,9 @@ class ViewTest(TestCase): pass @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_SpeedCoach2a(self, mocked_sqlalchemy): + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_SpeedCoach2a(self, mocked_sqlalchemy, + mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/Speedcoach2example.csv' @@ -623,7 +687,9 @@ class ViewTest(TestCase): pass @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_SpeedCoach2b(self, mocked_sqlalchemy): + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_SpeedCoach2b(self, mocked_sqlalchemy, + mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/Speedcoach2example.csv' @@ -659,8 +725,10 @@ class ViewTest(TestCase): - @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_SpeedCoach2c(self, mocked_sqlalchemy): + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_SpeedCoach2c(self, mocked_sqlalchemy, + mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/speedcoach3test3.csv' @@ -770,7 +838,9 @@ class ViewTest(TestCase): @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_NoHR(self, mocked_sqlalchemy): + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_NoHR(self, mocked_sqlalchemy, + mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/NoHR.tcx' @@ -806,7 +876,9 @@ class ViewTest(TestCase): @patch('rowers.dataprep.create_engine') - def test_upload_view_TCX_CN(self, mocked_sqlalchemy): + @patch('rowers.dataprep.TCXParser') + def test_upload_view_TCX_CN(self, mocked_sqlalchemy, + mocked_tcx_parser): self.c.login(username='john',password='koeinsloot') filename = 'rowers/tests/testdata/rowinginmotionexample.tcx' @@ -1173,8 +1245,9 @@ class PlotTests(TestCase): 'powerzones':serialize_list(r.powerzones), } - - def test_ote_plots(self): + @patch('rowers.tasks.rdata') + @patch('rowers.tasks.FigureCanvas') + def test_ote_plots(self, mocked_rowingdata, mocked_canvas): w = self.wote f1 = 'testdata.csv'[:-4] timestr = strftime("%Y%m%d-%H%M%S") @@ -1311,7 +1384,9 @@ class PlotTests(TestCase): except WindowsError: pass - def test_otw_plots(self): + @patch('rowers.tasks.rdata') + @patch('rowers.tasks.FigureCanvas') + def test_otw_plots(self, mocked_rowingdata, mocked_canvas): w = self.wotw f1 = 'testdata.csv'[:-4] timestr = strftime("%Y%m%d-%H%M%S") From abceefa42c745780ba0d8649400a9c281089dab4 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 3 Jan 2019 18:11:19 +0100 Subject: [PATCH 10/18] non succeeeded in ajax test --- rowers/tests/donottest_ajax.py | 82 + rowers/tests/test_admin.py,cover | 47 - rowers/tests/test_imports.py | 12 +- rowers/tests/test_user.py,cover | 94 - rowers/tests/tests.py | 5 + rowers/tests/tests.py,cover | 2831 ------------------------------ rowers/views.py | 7 +- 7 files changed, 101 insertions(+), 2977 deletions(-) create mode 100644 rowers/tests/donottest_ajax.py delete mode 100644 rowers/tests/test_admin.py,cover delete mode 100644 rowers/tests/test_user.py,cover delete mode 100644 rowers/tests/tests.py,cover diff --git a/rowers/tests/donottest_ajax.py b/rowers/tests/donottest_ajax.py new file mode 100644 index 00000000..92d223de --- /dev/null +++ b/rowers/tests/donottest_ajax.py @@ -0,0 +1,82 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import error500_view,error404_view,error400_view,error403_view + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +class AjaxTests(TestCase): + def setUp(self): + redis_connection.publish('tasks','KILL') + u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + r = Rower.objects.create(user=u,gdproptin=True, + gdproptindate=timezone.now() + ) + self.nu = datetime.datetime.now() + + self.filename = 'rowers/tests/testdata/testdata.csv' + self.wotw = Workout.objects.create(name='testworkout', + workouttype='water', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=self.filename) + + self.wote = Workout.objects.create(name='testworkout', + workouttype='Indoor Rower', + user=r,date=self.nu.strftime('%Y-%m-%d'), + starttime=self.nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000, + csvfilename=self.filename) + + + self.c = Client() + + def test_toggle_ranking(self): + response = self.c.get( + '/rowers/workout/1/toggle-ranking/', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}) + + jsondata = json.loads(response.json()) + self.assertIn('result',jsondata) diff --git a/rowers/tests/test_admin.py,cover b/rowers/tests/test_admin.py,cover deleted file mode 100644 index 083f75f0..00000000 --- a/rowers/tests/test_admin.py,cover +++ /dev/null @@ -1,47 +0,0 @@ - #from __future__ import print_function -> import pytest - -> pytestmark = pytest.mark.django_db - -> from bs4 import BeautifulSoup -> import re -> from nose_parameterized import parameterized -> from django.test import TestCase, Client,override_settings -> from django.core.management import call_command -> from django.utils.six import StringIO -> from django.test.client import RequestFactory -> import datetime - -> import json -> import numpy as np - - -> from redis import StrictRedis -> redis_connection = StrictRedis() - -> from rowers.models import User,Rower - -> @pytest.mark.django_db -> class AdminTests(TestCase): -> def setUp(self): -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> r = Rower.objects.create(user=u) -> my_admin = User.objects.create_superuser('myuser', -> 'myemail@test.com', -> 'apensstaart') - -> self.c = Client() -> self.c.login(username='myuser',password='apensstaart') - -> def test_admin(self): -> response = self.c.get('/admin',follow=True) -> self.assertEqual(response.status_code,200) - - -> response = self.c.get('/admin/auth/user/',follow=True) -> self.assertEqual(response.status_code,200) - -> response = self.c.get('/admin/auth/user/77/change/',follow=True) -> self.assertEqual(response.status_code,200) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 1e84168c..ee537e2e 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -152,7 +152,8 @@ class C2Objects(DjangoTestCase): self.assertEqual(response.status_code, 200) - def test_strokedata(self): + @patch('rowers.dataprep.create_engine') + def test_strokedata(self, mocked_sqlalchemy): with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile: res = json.load(infile) @@ -167,7 +168,8 @@ class C2Objects(DjangoTestCase): res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') - def test_strokedatanohr(self): + @patch('rowers.dataprep.create_engine') + def test_strokedatanohr(self, mocked_sqlalchemy): with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile: res = json.load(infile) @@ -399,7 +401,8 @@ class STObjects(DjangoTestCase): self.assertEqual(response.status_code, 200) - def test_strokedata(self): + @patch('rowers.dataprep.create_engine') + def test_strokedata(self, mocked_sqlalchemy): with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile: data = json.load(infile) @@ -407,7 +410,8 @@ class STObjects(DjangoTestCase): res = add_workout_from_data(self.u,1,data,data) - def test_strokedatanohr(self): + @patch('rowers.dataprep.create_engine') + def test_strokedatanohr(self, mocked_sqlalchemy): with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile: data = json.load(infile) diff --git a/rowers/tests/test_user.py,cover b/rowers/tests/test_user.py,cover deleted file mode 100644 index 5ece6fa8..00000000 --- a/rowers/tests/test_user.py,cover +++ /dev/null @@ -1,94 +0,0 @@ - #from __future__ import print_function -> import pytest - -> pytestmark = pytest.mark.django_db - -> from bs4 import BeautifulSoup -> import re -> from nose_parameterized import parameterized -> from django.test import TestCase, Client,override_settings -> from django.core.management import call_command -> from django.utils.six import StringIO -> from django.test.client import RequestFactory -> import datetime -! from django.utils import timezone - -> import json -! import numpy as np - - -> from redis import StrictRedis -! redis_connection = StrictRedis() - -! from rowers.models import User,Rower, Workout - -> class UserMiddleWareTest(TestCase): -> def setUp(self): -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -! r = Rower.objects.create(user=u) - -> self.c = Client() -! self.c.login(username='john',password='koeinsloot') -> nu = datetime.datetime.now() - -> response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', -> title='sample') - -! newworkoutid = response[0] -! self.w = Workout.objects.get(id=newworkoutid) - - -! def test_middleware(self): -! response = self.c.get('/rowers/list-workouts',follow=True) -! self.assertEqual(response.status_code,200) - -! class UserExpireTest(TestCase): -! def setUp(self): -! redis_connection.publish('tasks','KILL') -! self.u = User.objects.create_user('john', -! 'sander@ds.ds', -! 'koeinsloot') - -! yesterday_dt = timezone.now()-datetime.timedelta(days=1) -! yesterday = yesterday_dt.date() - -! r = Rower.objects.create(user=self.u,planexpires = yesterday,rowerplan='pro', -! paymenttype='single') - -! self.c = Client() -! self.c.login(username='john',password='koeinsloot') -! nu = datetime.datetime.now() - -! response = dataprep.new_workout_from_file(r,'/media/testdata.csv.gz', -! title='sample') - -! newworkoutid = response[0] -! self.w = Workout.objects.get(id=newworkoutid) - - -! def test_expire(self): -! response = self.c.get('/rowers/list-workouts',follow=True) -! self.assertEqual(response.status_code,200) -! self.assertEqual(self.u.rower.rowerplan,'basic') - -! class UserTestsNoRower(TestCase): -! def setUp(self): -! u = User.objects.create_user('john', -! 'sander@ds.ds', -! 'koeinsloot') - -! self.c = Client() -! self.c.login(username='john',password='koeinsloot') -! nu = datetime.datetime.now() -! self.w = Workout.objects.create(name='testworkout', -! workouttype='water', -! user=self.r,date=nu.strftime('%Y-%m-%d'), -! starttime=nu.strftime('%H:%M:%S'), -! duration="0:55:00",distance=8000) - -! def test_user(self): -! response = self.c.get('/rowers/list-workouts',follow=True) -! self.assertEqual(response.status_code,200) - diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index 1511c6ab..9a298642 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -444,6 +444,11 @@ class ViewTest(TestCase): response = self.c.get('/rowers/workout/1/histo', form_data, follow=True) self.assertEqual(response.status_code, 200) + response = self.c.get('/rowers/workout/1/workflow', + follow=True) + + self.assertEqual(response.status_code, 200) + form_data = { 'name':'aap', 'date':'2016-11-05', diff --git a/rowers/tests/tests.py,cover b/rowers/tests/tests.py,cover deleted file mode 100644 index 3c9785cd..00000000 --- a/rowers/tests/tests.py,cover +++ /dev/null @@ -1,2831 +0,0 @@ - #from __future__ import print_function -> import pytest - -> pytestmark = pytest.mark.django_db - -> from bs4 import BeautifulSoup -> import re -> from nose_parameterized import parameterized -> from django.test import TestCase, Client,override_settings -> from django.core.management import call_command -> from django.utils.six import StringIO -> from django.test.client import RequestFactory -> from rowers.views import checkworkoutuser,c2_open -> from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage -> from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail -> import rowers.plots as plots -> import rowers.interactiveplots as iplots -> import datetime -> from rowingdata import rowingdata as rdata -> from rowingdata import rower as rrower -> from django.utils import timezone -> from rowers.rows import handle_uploaded_file -> from django.core.files.uploadedfile import SimpleUploadedFile -> from time import strftime,strptime,mktime,time,daylight -> import os -> from rowers.tasks import handle_makeplot -> from rowers.utils import serialize_list,deserialize_list -> from rowers.utils import NoTokenError -> from shutil import copyfile -> from nose.tools import assert_true -> from mock import Mock, patch -> from minimocktest import MockTestCase -> import pandas as pd -> import rowers.c2stuff as c2stuff - -> import json -> import numpy as np - -> from rowers import urls -> from rowers.views import error500_view,error404_view,error400_view,error403_view - -> from rowers.dataprep import delete_strokedata - -> from redis import StrictRedis -> redis_connection = StrictRedis() - - #@pytest.mark.django_db -> class DjangoTestCase(TestCase, MockTestCase): -> def _pre_setup(self): -> MockTestCase.setUp(self) -> TestCase._pre_setup(self) -> self.client = Client() - -> def _post_teardown(self): -> TestCase._post_teardown(self) -> MockTestCase.tearDown(self) -> delete_strokedata(1) - - # to be done add polar mocks (for email processing) -> def mocked_requests(*args, **kwargs): -> with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile: -> c2workoutdata = json.load(infile) - -> with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile: -> c2strokedata = json.load(infile) - -> polar_json = { -> 'available-user-data': [] -> } - -> c2workoutlist = json.load(open('rowers/tests/testdata/c2workoutlist.txt')) - -> c2uploadjson = { -> "data": { -> "id": 339, -> "user_id": 1, -> "date": "2015-08-05 13:15:41", -> "timezone": "Europe/London", -> "date_utc": "2015-08-05 12:15:41", -> "distance": 5649, -> "type": "rower", -> "time": 8649, -> "time_formatted": "14:24.9", -> "workout_type": "JustRow", -> "source": "ErgData", -> "weight_class": "H", -> "verified": True, -> "ranked": False -> } -> } - -> stravaworkoutlist = json.load(open('rowers/tests/testdata/stravaworkoutlist.txt')) -> sporttracksworkoutlist = json.load(open('rowers/tests/testdata/sporttracksworkouts.txt')) - -> rkworkoutlistjson = json.load(open('rowers/tests/testdata/rkworkoutslist.txt','r')) -> uaworkoutlistjson = json.load(open('rowers/tests/testdata/uaworkoutlist.txt','r')) - -> stravasummaryjson = json.load(open('rowers/tests/testdata/stravaworkoutsummary.txt','r')) - -> stravatimejson = json.load(open('rowers/tests/testdata/stravatimetestdata.txt','r')) -> stravavelojson = json.load(open('rowers/tests/testdata/stravavelotestdata.txt','r')) - -> stravapowerjson = json.load(open('rowers/tests/testdata/stravapowertestdata.txt','r')) - -> stravadistancejson = json.load(open('rowers/tests/testdata/stravadistancetestdata.txt','r')) -> stravalatlongjson = json.load(open('rowers/tests/testdata/stravalatlongtestdata.txt','r')) -> stravahrjson = json.load(open('rowers/tests/testdata/stravahrtestdata.txt','r')) -> stravaspmjson = json.load(open('rowers/tests/testdata/stravaspmtestdata.txt','r')) - -> uapostworkoutjson = json.load(open('rowers/tests/testdata/uapostworkoutresponse.txt','r')) - -> tpuploadresponse = json.load(open('rowers/tests/testdata/tpuploadresponse.txt','r')) - -> stravastreamjson = { -> 'time':stravatimejson, -> 'velocity_smooth':stravavelojson, -> 'distance':stravadistancejson, -> 'latlng':stravalatlongjson, -> 'heartrate':stravahrjson, -> 'cadence':stravaspmjson, -> 'power':stravapowerjson, -> } - -> ststrokesjson = json.load(open('rowers/tests/testdata/sporttracksstrokedata.txt','r')) - -> rkstrokesjson = json.load(open('rowers/tests/testdata/rkstrokes.txt','r')) - -> uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r')) -> uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r')) - -> class MockResponse: -> def __init__(self, json_data, status_code): -> self.json_data = json_data -> self.status_code = status_code - -> def json(self): -> return self.json_data - - -> class MockHeaderResponse: -> def __init__(self, header_data, status_code): -> self.headers = header_data -> self.status_code = status_code - -> class MockSession: -> def send(self,prepped): - # prepped.url - # prepped.body (post data) - # prepped.headers - # prepped.method - -> json_data = { -> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -> 'expires_in': 604800, -> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -> } - -> return MockResponse(json_data,200) - -> if not args: -> return MockSession() - -> polartester = re.compile('.*?polaraccesslink\.com') -> c2tester = re.compile('.*?log\.concept2\.com') -> stravatester = re.compile('.*?strava\.com') -> sttester = re.compile('.*?sporttracks\.mobi') -> rktester = re.compile('.*?runkeeper\.com') -> uatester = re.compile('.*?mapmyfitness\.com') -> tptester = re.compile('.*?trainingpeaks\.com') - -> c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' -> c2importtester = re.compile(c2importregex) - -> c2uploadregex = '.*?concept2.com\/api\/users\/\d+\/results$' -> c2uploadtester = re.compile(c2uploadregex) - -> c2strokesregex = '.*?concept2.com\/api\/users\/me\/results\/\d+\/strokes' -> c2strokestester = re.compile(c2strokesregex) - -> c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d' -> c2workoutlisttester = re.compile(c2workoutlistregex) - -> stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities' -> stravaworkoutlisttester = re.compile(stravaworkoutlistregex) - -> stravastreamregex = '.*?strava\.com\/api\/v3\/activities\/\d+\/streams\/(\w.*?)\?' -> stravastreamtester = re.compile(stravastreamregex) - -> stravasummaryregex = '.*?strava\.com\/api\/v3\/activities\/\d+$' -> stravasummarytester = re.compile(stravasummaryregex) - -> stuploadregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities.json$' -> stuploadtester = re.compile(stuploadregex) - -> stworkoutlistregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities$' -> stworkoutlisttester = re.compile(stworkoutlistregex) - -> ststrokesregex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/\d+$' -> ststrokestester = re.compile(ststrokesregex) - -> rkuploadregex = '.*?api\.runkeeper\.com\/fitnessActivities$' -> rkuploadtester = re.compile(rkuploadregex) -> rkuserregex = '.*?api\.runkeeper\.com\/user$' -> rkusertester = re.compile(rkuserregex) -> rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' -> rkstrokestester = re.compile(rkstrokesregex) - -> uaapiregex = '.*?api\.ua\.com' -> uaapitester = re.compile(uaapiregex) - -> uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$' -> uauploadtester = re.compile(uauploadregex) - -> uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+' -> uastrokestester = re.compile(uastrokesregex) - -> ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user' -> ualisttester = re.compile(ualistregex) - -> uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/' -> uausertester = re.compile(uauserregex) - -> tpuploadregex = '.*?trainingpeaks\.com\/v1\/file' -> tpuploadtester = re.compile(tpuploadregex) - -> if polartester.match(args[0]): -> json_data = polar_json -> return MockResponse(json_data,200) - -> if tptester.match(args[0]): -> if 'token' in args[0]: -> json_data = { -> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -> 'expires_in': 604800, -> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -> } -> return MockResponse(json_data,200) -> elif tpuploadtester.match(args[0]): -> return MockResponse(tpuploadresponse,200) - -> if uaapitester.match(args[0]): -> if 'access_token' in args[0]: -> json_data = { -> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -> 'expires_in': 604800, -> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -> } -> return MockResponse(json_data,200) -> elif uauploadtester.match(args[0]): -> if 'data' in kwargs: -> return MockResponse(uapostworkoutjson,200) -> elif uastrokestester.match(args[0]): -> return MockResponse(uastrokesjson,200) -> elif ualisttester.match(args[0]): -> return MockResponse(uaworkoutlistjson,200) -> elif uausertester.match(args[0]): -> return MockResponse(uauserjson,200) - - -> if uatester.match(args[0]): -! if 'access_token' in args[0]: -! json_data = { -! 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -! 'expires_in': 604800, -! 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -! } -! return MockResponse(json_data,200) - - -> if rktester.match(args[0]): -> if 'token' in args[0]: -> json_data = { -> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -> 'expires_in': 604800, -> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -> } -> return MockResponse(json_data,200) -> elif rkuploadtester.match(args[0]): -> if 'data' in kwargs: - # post -> header_data = { -> 'Location': '/fitnessActivities/12' -> } -> return MockHeaderResponse(header_data,200) -> else: -> json_data = rkworkoutlistjson -> return MockResponse(json_data,200) -> elif rkusertester.match(args[0]): -> json_data = { -> "userID": 1234567890, -> "profile": "/profile", -> "settings": "/settings", -> "fitness_activities": "/fitnessActivities", -> "strength_training_activities": "/strengthTrainingActivities", -> "background_activities": "/backgroundActivities", -> "sleep": "/sleep", -> "nutrition": "/nutrition", -> "weight": "/weight", -> "general_measurements": "/generalMeasurements", -> "diabetes": "/diabetes", -> "records": "/records", -> "team": "/team" -> } -> return MockResponse(json_data, 200) -> elif rkstrokestester.match(args[0]): -> return MockResponse(rkstrokesjson,200) - -> if sttester.match(args[0]): -> if 'oauth2/token' in args[0]: -> json_data = { -> 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -> 'expires_in': 604800, -> 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -> } -> return MockResponse(json_data,200) -> if ststrokestester.match(args[0]): -> return MockResponse(ststrokesjson,200) -> if stuploadtester.match(args[0]): -> json_data = { -> "uris": [ -> "https://api.sporttracks.mobi/api/v2/fitnessActivities/123456.json" -> ] -> } -> return MockResponse(json_data, 200) -> if stworkoutlisttester.match(args[0]): -> return MockResponse(sporttracksworkoutlist,200) - - -> if stravatester.match(args[0]): -> if stravaworkoutlisttester.match(args[0]): -! return MockResponse(stravaworkoutlist,200) -> if stravastreamtester.match(args[0]): -> metric = stravastreamtester.match(args[0]).group(1) -> json_data = stravastreamjson[metric] -> return MockResponse(json_data,200) -> elif stravasummarytester.match(args[0]): -> return MockResponse(stravasummaryjson,200) -> elif 'token' in args[0]: -> json_data = { -> "token_type": "Bearer", -> "access_token": "987654321234567898765432123456789", -> "refresh_token": "1234567898765432112345678987654321", -> "expires_at": 1531385304 -> } -> return MockResponse(json_data,200) - - -> if c2tester.match(args[0]): -> if c2uploadtester.match(args[0]): -> return MockResponse(c2uploadjson,201) -> if c2strokestester.match(args[0]): -> return MockResponse(c2strokedata,200) -> elif c2importtester.match(args[0]): -> return MockResponse(c2workoutdata,200) -> elif c2workoutlisttester.match(args[0]): -> return MockResponse(c2workoutlist,200) -> elif 'access_token' in args[0]: -! json_data = { -! 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', -! 'expires_in': 604800, -! 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' -! } -! return MockResponse(json_data,200) -> elif 'users/me' in args[0]: -> json_data = { -> 'data': { -> 'username': 'john', -> 'id': 1234, -> } -> } -> return MockResponse(json_data,200) -! elif 'results' in args[0]: -! json_data = { -! 'data': { -! 'id': 1223, -! } -! } -! else: -! return MockResponse(c2workoutdata,200) - -! return MockResponse(None,404) - - #@pytest.mark.django_db -> class C2Objects(DjangoTestCase): -> def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -> self.u.first_name = 'John' -> self.u.last_name = 'Sander' -> self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -> self.r.c2token = '12' -> self.r.c2refreshtoken = 'ab' -> self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) -> self.r.save() -> self.c.login(username='john',password='koeinsloot') - -> self.nu = datetime.datetime.now() - -> filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -> totaldist = row.df['cum_dist'].max() -> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - - -> @patch('rowers.c2stuff.requests.Session', side_effect=mocked_requests) -> def test_c2_callback(self, mock_Session): -> response = self.c.get('/call_back?code=dsdoij232s',follow=True) - - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.c2stuff.Session', side_effect=mocked_requests) -> def test_c2_token_refresh(self, mock_post): -> response = self.c.get('/rowers/me/c2refresh/',follow=True) - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) -> def test_c2_upload(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/1/c2uploadw/') - -> self.assertRedirects(response, -> expected_url = '/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.url, '/rowers/workout/1/edit') -> self.assertEqual(response.status_code, 302) - -> @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) -> def test_c2_list(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/c2list',follow=True) - -> self.assertEqual(response.status_code,200) - -> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) -> def test_c2_import(self, mock_get): - -> response = self.c.get('/rowers/workout/c2import/12/',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/2/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - - -> def test_strokedata(self): -> with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile: -> res = json.load(infile) - -> strokedata = pd.DataFrame.from_dict(res['data']) - -> with open('rowers/tests/testdata/c2testdata.txt','r') as infile: -> res = json.load(infile) - -> data = res['data'] - -> from rowers.views import add_workout_from_strokedata - -> res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') - -> def test_strokedatanohr(self): -> with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile: -> res = json.load(infile) - -> strokedata = pd.DataFrame.from_dict(res['data']) - -> with open('rowers/tests/testdata/c2testdata.txt','r') as infile: -> res = json.load(infile) - -> data = res['data'] - -> from rowers.views import add_workout_from_strokedata - - -> res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') - -! class C2ObjectsTokenExpired(DjangoTestCase): -! def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -> self.u.first_name = 'John' -! self.u.last_name = 'Sander' -> self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -! self.r.c2token = '12' -! self.r.c2refreshtoken = 'ab' -> self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) -! self.r.save() -> self.c.login(username='john',password='koeinsloot') - -! self.nu = datetime.datetime.now() - -! filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -! totaldist = row.df['cum_dist'].max() -! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -! seconds = int(totaltime - 3600.*hours - 60.*minutes) -> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - - - -! @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) -> def test_c2_list(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/c2list',follow=True) - -! self.assertEqual(response.status_code,200) - -! @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) -! def test_c2_import(self, mock_get): - -> response = self.c.get('/rowers/workout/c2import/12/',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/2/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - - - - #@pytest.mark.django_db -> class StravaObjects(DjangoTestCase): -> def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -! self.u.first_name = 'John' -> self.u.last_name = 'Sander' -> self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -> self.r.stravatoken = '12' - -> self.r.save() -> self.c.login(username='john',password='koeinsloot') - -! @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) -! def test_strava_list(self, mock_get): -! response = self.c.get('/rowers/workout/stravaimport/',follow=True) - -! self.assertEqual(response.status_code,200) - -> @patch('rowers.utils.requests.get', side_effect=mocked_requests) -> def test_strava_import(self, mock_get): - -> response = self.c.get('/rowers/workout/stravaimport/12',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/1/edit', -> status_code=301,target_status_code=200) - -! self.assertEqual(response.status_code, 200) - - - - #@pytest.mark.django_db -! class STObjects(DjangoTestCase): -> def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -! self.u.first_name = 'John' -> self.u.last_name = 'Sander' -! self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - - -! self.r.sporttrackstoken = '12' -! self.r.sporttracksrefreshtoken = '12' -> self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) -! self.r.save() - -> self.c.login(username='john',password='koeinsloot') - -! self.nu = datetime.datetime.now() - -! filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -! totaldist = row.df['cum_dist'].max() -> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -! totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -! minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -! tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -! workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - -> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) -> def test_sporttracks_callback(self, mock_post): -! response = self.c.get('/sporttracks_callback?code=dsdoij232s',follow=True) - - -! self.assertEqual(response.status_code, 200) - - -> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) -> def test_sporttracks_token_refresh(self, mock_post): -> response = self.c.get('/rowers/me/sporttracksrefresh/',follow=True) - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) -> def test_sporttracks_upload(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/1/sporttracksuploadw/') - -> self.assertRedirects(response, -> expected_url = '/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.url, '/rowers/workout/1/edit') -> self.assertEqual(response.status_code, 302) - -! @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) -! def test_sporttracks_list(self, mock_get): -! response = self.c.get('/rowers/workout/sporttracksimport',follow=True) - -> self.assertEqual(response.status_code,200) - -! @patch('rowers.imports.requests.get', side_effect=mocked_requests) -! def test_sporttracks_import(self, mock_get): - -> response = self.c.get('/rowers/workout/sporttracksimport/12/',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/2/edit', -> status_code=302,target_status_code=200) - -! self.assertEqual(response.status_code, 200) - -! def test_strokedata(self): -> with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile: -! data = json.load(infile) - -! from rowers.sporttracksstuff import add_workout_from_data - -> res = add_workout_from_data(self.u,1,data,data) - -> def test_strokedatanohr(self): -! with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile: -> data = json.load(infile) - -> from rowers.sporttracksstuff import add_workout_from_data - - - -! res = add_workout_from_data(self.u,1,data,data) - - #@pytest.mark.django_db -> class RunKeeperObjects(DjangoTestCase): -! def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -> self.u.first_name = 'John' -! self.u.last_name = 'Sander' -> self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - - -! self.r.runkeepertoken = '12' - -! self.r.save() - -> self.c.login(username='john',password='koeinsloot') - -> self.nu = datetime.datetime.now() - -> filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -> totaldist = row.df['cum_dist'].max() -! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -! totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -! tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -! workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - -> @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) -> def test_runkeeper_callback(self, mock_post): -> response = self.c.get('/runkeeper_callback?code=dsdoij232s',follow=True) - -> self.assertEqual(response.status_code, 200) - -! @patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) -> def test_runkeeper_upload(self, mock_get, mock_post): -! response = self.c.get('/rowers/workout/1/runkeeperuploadw/') - -> self.assertRedirects(response, -> expected_url = '/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.url, '/rowers/workout/1/edit') -> self.assertEqual(response.status_code, 302) - -! @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) -! def test_runkeeper_list(self, mock_get): -! response = self.c.get('/rowers/workout/runkeeperimport',follow=True) - -! self.assertEqual(response.status_code,200) - -> @patch('rowers.imports.requests.get', side_effect=mocked_requests) -> def test_runkeeper_import(self, mock_get): - -> response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/2/edit', -> status_code=302,target_status_code=200) - -! self.assertEqual(response.status_code, 200) - - - - #@pytest.mark.django_db -! class UAObjects(DjangoTestCase): -> def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -! self.u.first_name = 'John' -> self.u.last_name = 'Sander' -! self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - - -! self.r.underarmourtoken = '12' -! self.r.underarmourrefreshtoken = '12' -> self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) -! self.r.save() - -> self.c.login(username='john',password='koeinsloot') - -! self.nu = datetime.datetime.now() - -! filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -> totaldist = row.df['cum_dist'].max() -> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -! duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - -> @patch('rowers.imports.requests.post', side_effect=mocked_requests) -> def test_underarmour_callback(self, mock_post): -> response = self.c.get('/underarmour_callback?code=dsdoij232s',follow=True) - - -! self.assertEqual(response.status_code, 200) - - -> @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) -> def test_underarmour_token_refresh(self, mock_post): -> response = self.c.get('/rowers/me/underarmourrefresh/',follow=True) - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) -> def test_underarmour_upload(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/1/underarmouruploadw/') - -> self.assertRedirects(response, -> expected_url = '/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.url, '/rowers/workout/1/edit') -! self.assertEqual(response.status_code, 302) - -> @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) -> def test_underarmour_list(self, mock_get): -> response = self.c.get('/rowers/workout/underarmourimport',follow=True) - -! self.assertEqual(response.status_code,200) - -! @patch('rowers.imports.requests.get', side_effect=mocked_requests) -! def test_underarmour_import(self, mock_get): - -! response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/workout/2/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - - - #@pytest.mark.django_db -! class TPObjects(DjangoTestCase): -> def setUp(self): -> self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') - -! self.u.first_name = 'John' -! self.u.last_name = 'Sander' -! self.u.save() -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - - -> self.r.tptoken = '12' -> self.r.tprefreshtoken = '12' -> self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) -> self.r.save() - -> self.c.login(username='john',password='koeinsloot') - -> self.nu = datetime.datetime.now() - -> filename = 'rowers/tests/testdata/testdata.csv' - -> rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, -> hrut1=self.r.ut1,hrat=self.r.at, -> hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) -> row = rdata(filename,rower=rr) -> totaldist = row.df['cum_dist'].max() -! totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -> workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -> workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> self.w = Workout.objects.create( -> name='testworkout',workouttype='water', -> user=self.r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> startdatetime=row.rowdatetime, -> duration=duration,distance=totaldist, -> csvfilename=filename -> ) - -> @patch('rowers.imports.requests.post', side_effect=mocked_requests) -> def test_tp_callback(self, mock_post): -> response = self.c.get('/tp_callback?code=dsdoij232s',follow=True) - - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) -> def test_tp_token_refresh(self, mock_post): -> response = self.c.get('/rowers/me/tprefresh/',follow=True) - -> self.assertEqual(response.status_code, 200) - - -> @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) -> @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) -> def test_tp_upload(self, mock_get, mock_post): -> response = self.c.get('/rowers/workout/1/tpuploadw/') - -> self.assertRedirects(response, -> expected_url = '/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.url, '/rowers/workout/1/edit') -> self.assertEqual(response.status_code, 302) - - - - - #@pytest.mark.django_db -> class TestErrorPages(TestCase): -> def test_error_handlers(self): - -! self.assertTrue(urls.handler404.endswith('.error404_view')) -! self.assertTrue(urls.handler500.endswith('.error500_view')) -! factory = RequestFactory() -! request = factory.get('/') -> response = error404_view(request) -> self.assertEqual(response.status_code, 404) -> self.assertIn('404 Page not found', unicode(response)) -> response = error500_view(request) -> self.assertEqual(response.status_code, 500) -> self.assertIn('500 Internal Server Error', unicode(response)) - - #@pytest.mark.django_db -> class NewUserRegistrationTest(TestCase): -> def setUp(self): -> self.c = Client() -! redis_connection.publish('tasks','KILL') - -! def test_newuser(self): -> form_data = { -> 'first_name':'Jan', -> 'last_name':'Roeiert', -> 'email':'jan@loop.nl', -> 'username':'janderoeiert', -> 'password1':'aapindewei2', -> 'password2':'aapindewei2', -> 'tos':True, -> 'weightcategory':'hwt', -> 'adaptiveclass': 'None', -> 'sex':'male', -> 'next':'/rowers/list-workouts', -> 'birthdate':datetime.datetime(year=1970,month=4,day=2) -> } - -> form = RegistrationFormUniqueEmail(form_data) -> self.assertTrue(form.is_valid()) - -! response = self.c.post('/rowers/register', form_data, follow=True) - -> self.assertRedirects(response, -> expected_url='/rowers/me/gdpr-optin/?next=/rowers/list-workouts/', -> status_code=302,target_status_code=200) - -> from django_mailbox.models import Mailbox,MessageAttachment,Message - - #@pytest.mark.django_db -> class AutoExportTests(TestCase): -! def setUp(self): -! redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> r = Rower.objects.create(user=u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -> r.c2_auto_export = True -> r.sporttracks_auto_export = True -> r.mapmyfitness_auto_export = True -> r.trainingpeaks_auto_export = True - -! r.save() - -! nu = datetime.datetime.now() -! workoutsbox = Mailbox.objects.create(name='workouts') -> workoutsbox.save() -! failbox = Mailbox.objects.create(name='Failed') -> failbox.save() - -> filename = 'testdata.csv' - -> m = Message(mailbox=workoutsbox, -> from_header = u.email, -> subject = filename, -> body=""" -> --- -> workouttype: water -> boattype: 2x -> ... -> """) -> m.save() -! a2 = 'media/mailbox_attachments/'+filename -! copyfile('rowers/tests/testdata/'+filename,a2) -> a = MessageAttachment(message=m,document=a2[6:]) -> a.save() - -> def tearDown(self): -> for filename in os.listdir('media/mailbox_attachments'): -! path = os.path.join('media/mailbox_attachments/',filename) -> if not os.path.isdir(path): -> try: -> os.remove(path) -> except WindowsError: -! pass - -! @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) -! @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) -! def test_emailprocessing(self, mock_post, mock_get): -> out = StringIO() -> call_command('processemail', stdout=out, testing=True) -> self.assertIn('Successfully processed email attachments',out.getvalue()) - - #@pytest.mark.django_db -> class UploadTests(TestCase): -! def setUp(self): -> redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> r = Rower.objects.create(user=u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -> nu = datetime.datetime.now() -> workoutsbox = Mailbox.objects.create(name='workouts') -> workoutsbox.save() -! failbox = Mailbox.objects.create(name='Failed') -! failbox.save() -> m = Message(mailbox=workoutsbox, -> from_header = u.email, -> subject = "3x(5min/2min)/r2 \r2", -> body = """ -> workout run -> """) -! m.save() -! a2 = 'media/mailbox_attachments/colin2.csv' -! copyfile('rowers/tests/testdata/emails/colin.csv',a2) -> a = MessageAttachment(message=m,document=a2[6:]) -! a.save() - -> def tearDown(self): -> for filename in os.listdir('media/mailbox_attachments'): -! path = os.path.join('media/mailbox_attachments/',filename) -! if not os.path.isdir(path): -! try: -> os.remove(path) -> except (IOError,WindowsError): -> pass - -> @patch('requests.get', side_effect=mocked_requests) -> def test_email_workouttype(self, mock_get): -> out = StringIO() -> call_command('processemail', stdout=out, testing=True) -! w = Workout.objects.get(id=1) -> self.assertEqual(w.workouttype,'Run') - - #@pytest.mark.django_db -> class EmailTests(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> r = Rower.objects.create(user=u,gdproptin=True, -> gdproptindate=timezone.now() -> ) - -! nu = datetime.datetime.now() -! workoutsbox = Mailbox.objects.create(name='workouts') -! workoutsbox.save() -! failbox = Mailbox.objects.create(name='Failed') -! failbox.save() - -! for filename in os.listdir(u'rowers/tests/testdata/emails'): -> m = Message(mailbox=workoutsbox, -> from_header = u.email, -> subject = filename, -> body=""" -> --- -> workouttype: water -> boattype: 4x -> ... -> """) -! m.save() -! a2 = 'media/mailbox_attachments/'+filename -! copyfile(u'rowers/tests/testdata/emails/'+filename,a2) -> a = MessageAttachment(message=m,document=a2[6:]) -> a.save() - -> m = Message(mailbox=workoutsbox, -> from_header = u.email, -> subject = "3x(5min/2min)/r2 \r2", -> body = """ -> workout water -> """) -> m.save() -! a2 = 'media/mailbox_attachments/colin2.csv' -! copyfile('rowers/tests/testdata/emails/colin.csv',a2) -> a = MessageAttachment(message=m,document=a2[6:]) -> a.save() - - -> def tearDown(self): -> for filename in os.listdir('media/mailbox_attachments'): -> path = os.path.join('media/mailbox_attachments/',filename) -> if not os.path.isdir(path): -> try: -> os.remove(path) -> except (IOError,WindowsError): -> pass - -> @patch('requests.get', side_effect=mocked_requests) -> def test_emailprocessing(self, mock_get): -> out = StringIO() -> call_command('processemail', stdout=out,testing=True) -! self.assertIn('Successfully processed email attachments',out.getvalue()) - - - #@pytest.mark.django_db -> class WorkoutTests(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) -> nu = datetime.datetime.now() -> self.w = Workout.objects.create(name='testworkout', -> workouttype='water', -> user=self.r,date=nu.strftime('%Y-%m-%d'), -> starttime=nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000) - -> def test_checkworkoutuser(self): -> self.assertEqual(checkworkoutuser(self.u,self.w),True) - - #@pytest.mark.django_db -> class C2Tests(TestCase): -> def setUp(self): -! redis_connection.publish('tasks','KILL') -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now() -> ) -> self.nu = datetime.datetime.now() -> self.w = Workout.objects.create(name='testworkout',workouttype='water', -> user=r,date=nu.strftime('%Y-%m-%d'), -> starttime=nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000) - -> def c2_notokentest(self): -! thetoken = c2_open(self.u) - # should raise NoTokenError -> self.assertRaises(NoTokenError) - - #@pytest.mark.django_db -> class DataTest(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> r = Rower.objects.create(user=u,gdproptin=True, -> gdproptindate=timezone.now() -> ) -! self.nu = datetime.datetime.now() - - -! def test_workoutform(self): -> form_data = { -> 'name':'test', -> 'date':'2016-05-01', -> 'starttime':'07:53:00', -> 'timezone':'UTC', -> 'duration':'0:55:00.1', -> 'distance':8000, -> 'notes':'Aap noot \n mies', -> 'weightcategory':'lwt', -> 'adaptiveclass': 'PR1', -> 'workouttype':'water', -> 'boattype':'1x', -> 'private':False, -> } -> form = WorkoutForm(data=form_data) -> self.assertTrue(form.is_valid()) - -> def test_rower_form_withvalidnumbers(self): -> form_data = { -> 'max':192, -> 'rest':48, -> 'ut2':105, -> 'ut1':148, -> 'at':160, -> 'tr':167, -> 'an':180, -> 'weightcategory':'lwt', -> } -> form = RowerForm(data=form_data) -> self.assertTrue(form.is_valid()) - - -> def test_rower_form_twoequalvalues(self): -> form_data = { -> 'max':192, -> 'rest':48, -> 'ut2':105, -> 'ut1':105, -> 'at':160, -> 'an':180, -> 'tr':167, -> 'weightcategory':'lwt', -> } -! form = RowerForm(data=form_data) -> self.assertFalse(form.is_valid()) - -! def test_rower_form_abovemaxallowed(self): -> form_data = { -> 'max':300, -> 'rest':48, -> 'ut2':105, -> 'ut1':148, -> 'at':160, -> 'an':180, -> 'tr':167, -> 'weightcategory':'lwt', -> } -> form = RowerForm(data=form_data) -> self.assertFalse(form.is_valid()) - -! def test_rower_form_wrongorder(self): -> form_data = { -> 'max':192, -> 'rest':48, -> 'ut2':20, -> 'ut1':148, -> 'at':160, -> 'an':180, -> 'tr':167, -> 'weightcategory':'lwt', -> } -> form = RowerForm(data=form_data) -! self.assertFalse(form.is_valid()) - -> def test_rower_form_belowminalloed(self): -> form_data = { -> 'max':192, -> 'rest':2, -> 'ut2':105, -> 'ut1':148, -> 'at':160, -> 'an':180, -> 'tr':167, -> 'weightcategory':'lwt', -> } -> form = RowerForm(data=form_data) -> self.assertFalse(form.is_valid()) - -> def test_rower_form_wrongorder2(self): -> form_data = { -> 'max':192, -> 'rest':48, -> 'ut2':105, -> 'ut1':170, -> 'at':160, -> 'an':180, -> 'tr':167, -> 'weightcategory':'lwt', -> } -! form = RowerForm(data=form_data) -! self.assertFalse(form.is_valid()) - -> def test_painsled(self): -> filename = 'rowers/tests/testdata/testdata.csv' -> f = open(filename,'rb') -> file_data = {'file': SimpleUploadedFile(f.name, f.read())} -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> } - -! form = DocumentsForm(form_data,file_data) -> self.assertTrue(form.is_valid()) - -! f.close() - -! u = User.objects.get(username='john') -! r = Rower.objects.get(user=u) - -> rr = rrower(hrmax=r.max,hrut2=r.ut2, -> hrut1=r.ut1,hrat=r.at, -> hrtr=r.tr,hran=r.an,ftp=r.ftp) -> row = rdata(filename,rower=rr) -! totaldist = row.df['cum_dist'].max() -> totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() -> totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - -> hours = int(totaltime/3600.) -> minutes = int((totaltime - 3600.*hours)/60.) -> seconds = int(totaltime - 3600.*hours - 60.*minutes) -> tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - -> duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - -! workoutdate = row.rowdatetime.strftime('%Y-%m-%d') -! workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - -> w = Workout.objects.create(name='testworkout',workouttype='water', -> user=r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=workoutstarttime, -> duration=duration,distance=totaldist, -> csvfilename=filename) - - -> fig1 = plots.mkplot(row,'test') -! res = iplots.interactive_chart(w.id) -> res = iplots.interactive_chart(w.id,promember=1) -> res = iplots.interactive_bar_chart(w.id) -! res = iplots.interactive_bar_chart(w.id,promember=1) -> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', -> yparam1='pace',yparam2='hr') -! res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', -! yparam1='pace',yparam2='hr') -> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time', -> yparam1='pace',yparam2='spm') -> res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance', -> yparam1='pace',yparam2='spm') - -> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', -> yparam1='pace',yparam2='hr') -> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', -> yparam1='pace',yparam2='hr') -> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time', -> yparam1='pace',yparam2='spm') -> res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance', -> yparam1='pace',yparam2='spm') - - - - - #@pytest.mark.django_db -> class ViewTest(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -! self.c = Client() -> self.u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -> self.r = Rower.objects.create(user=self.u,gdproptin=True, -> gdproptindate=timezone.now(), -> rowerplan='coach', -> ) -! self.nu = datetime.datetime.now() - -! def test_upload_view_notloggedin(self): -! response = self.c.post('/rowers/workout/upload/',follow=True) - - -! self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', -! status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> def test_upload_view_sled(self): -! self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/testdata.csv' -! f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - -> f.close() - -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> response = self.c.get('/rowers/workout/1/', form_data, follow=True) -! self.assertEqual(response.status_code, 200) - -! response = self.c.get('/rowers/workout/1/edit', form_data, follow=True) -> self.assertEqual(response.status_code, 200) - - -> response = self.c.get('/rowers/workout/1/histo', form_data, follow=True) -! self.assertEqual(response.status_code, 200) - -> form_data = { -> 'name':'aap', -> 'date':'2016-11-05', -> 'starttime':'09:07:14', -> 'timezone':'Europe/Berlin', -> 'duration':'1:00:00.5', -> 'distance':'15000', -> 'weightcategory':'hwt', -> 'adaptiveclass':'PR1', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'private':True, -> 'notes':'noot mies', -> } -> form = WorkoutForm(data=form_data) -! self.assertTrue(form.is_valid()) -> response = self.c.post('/rowers/workout/1/edit', form_data, follow=True) -> self.assertEqual(response.status_code, 200) - - -> w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - - - -> def test_upload_view_notloggedin(self): -! response = self.c.post('/rowers/workout/upload/',follow=True) - - -> self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> def test_upload_view_sled_negativetime(self): -! self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/tim.csv' -> f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_C2':False, -> 'upload_to_Strava':False, -> 'upload_to_SportTracks':False, -> 'upload_to_RunKeeper':False, -> 'upload_to_MapMyFitness':False, -> 'plottype':'timeplot', -> 'file': f, -> 'makeprivate':False, -> 'landingpage':'workout_edit_view', -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - -! f.close() - -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> response = self.c.get('/rowers/workout/1/', form_data, follow=True) -! self.assertEqual(response.status_code, 200) - - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -> os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - - - - -! def test_upload_view_sled_noname(self): -! self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/testdata.csv' -! f = open(filename,'rb') -! file_data = {'file': f} -! form_data = { -! 'title':'', -! 'workouttype':'rower', -! 'boattype':'1x', -! 'notes':'aap noot mies', -! 'make_plot':False, -! 'upload_to_c2':False, -! 'plottype':'timeplot', -! 'file': f, -! } - -! form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - -! f.close() - -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) - -! self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - -! def test_upload_view_logcard(self): -! self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/logcard.csv' -! f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'', -> 'workouttype':'rower', -> 'boattype': '1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - -! f.close() - -> self.assertRedirects(response, -> expected_url='/rowers/workout/upload/', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - - - - -> def test_upload_view_TCX_CN(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/crewnerddata.tcx' -! f = open(filename,'rb') -! file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> filename = 'rowers/tests/testdata/crewnerddata.CSV' -> f = open(filename,'rb') -> file_data = {'file': f} -> form_data = {} -! form = CNsummaryForm(form_data,file_data) - -> response = self.c.post('rowers/workout/1/crewnerdsummary', -> form_data, -> follow=True) - -> f.close() - -! self.assertEqual(response.status_code, 200) -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -! pass - -> def test_upload_view_TCX_SpeedCoach2a(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/Speedcoach2example.csv' -> f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - -> def test_upload_view_TCX_SpeedCoach2b(self): -> self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/Speedcoach2example.csv' -> f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - - - -> def test_upload_view_TCX_SpeedCoach2c(self): -> self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/speedcoach3test3.csv' -> f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - - -! def test_upload_view_SpeedCoach2v127(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/SpeedCoach2Linkv1.27.csv' -! f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - - - -> def test_upload_view_SpeedCoach2v127intervals(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/SpeedCoach2Link_interval.csv' -> f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> f.close() -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) - -! self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -> pass - - - -> def test_upload_view_TCX_NoHR(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/NoHR.tcx' -> f = open(filename,'rb') -> file_data = {'file': f} - -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! f.close() -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) - -> self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - -> def test_upload_view_TCX_CN(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/rowinginmotionexample.tcx' -> f = open(filename,'rb') -! file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'water', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -> self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - -> def test_upload_view_RP(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/RP_testdata.csv' -> f = open(filename,'rb') -! file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -! self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - -> def test_upload_view_Mystery(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/mystery.csv' -> f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -> self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - -> def test_upload_view_RP_interval(self): -> self.c.login(username='john',password='koeinsloot') - -> filename = 'rowers/tests/testdata/RP_interval.csv' -> f = open(filename,'rb') -! file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) -> self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - - -> def test_upload_view_sled_desktop(self): -> self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/painsled_desktop_example.csv' -! f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -! form = DocumentsForm(form_data,file_data) - -> response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -> self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -> status_code=302,target_status_code=200) -> self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - -> def test_upload_view_sled_ergdata(self): -> self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/ergdata_example.csv' -! f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -! form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -! self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -! try: -! os.remove(f_to_be_deleted+'.gz') -! except WindowsError: -! pass - -! def test_upload_view_sled_boatcoach(self): -! self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/boatcoach.csv' -! f = open(filename,'rb') -! file_data = {'file': f} -! form_data = { -! 'title':'test', -! 'workouttype':'rower', -! 'boattype':'1x', -! 'notes':'aap noot mies', -! 'make_plot':False, -! 'upload_to_c2':False, -! 'plottype':'timeplot', -! 'file': f, -! } - -! form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -! self.assertEqual(response.status_code, 200) - -> w = Workout.objects.get(id=1) -> f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - -> def test_upload_view_sled_ergstick(self): -> self.c.login(username='john',password='koeinsloot') - -! filename = 'rowers/tests/testdata/ergstick.csv' -> f = open(filename,'rb') -> file_data = {'file': f} -> form_data = { -> 'title':'test', -> 'workouttype':'rower', -> 'boattype':'1x', -> 'notes':'aap noot mies', -> 'make_plot':False, -> 'upload_to_c2':False, -> 'plottype':'timeplot', -> 'file': f, -> } - -> form = DocumentsForm(form_data,file_data) - -! response = self.c.post('/rowers/workout/upload/', form_data, follow=True) -! self.assertRedirects(response, expected_url='/rowers/workout/1/edit', -! status_code=302,target_status_code=200) -! self.assertEqual(response.status_code, 200) - -! w = Workout.objects.get(id=1) -! f_to_be_deleted = w.csvfilename -> try: -> os.remove(f_to_be_deleted+'.gz') -> except WindowsError: -> pass - - - # def test_upload_view_FIT_SpeedCoach2a(self): - # self.c.login(username='john',password='koeinsloot') - - # filename = 'rowers/tests/testdata/3x250m.fit' - # with open(filename,'rb') as f: - - # file_data = {'file': f} - - # form_data = { - # 'title':'test', - # 'workouttype':'water', - # 'boattype':'1x', - # 'notes':'aap noot mies', - # 'make_plot':False, - # 'upload_to_c2':False, - # 'plottype':'timeplot', - # 'file': f, - # } - - # form = DocumentsForm(form_data,file_data) - - # response = self.c.post('/rowers/workout/upload/', - # form_data, follow=True, - # format='multipart') - # f.close() - # self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - # status_code=302,target_status_code=200) - - # self.assertEqual(response.status_code, 200) - - # w = Workout.objects.get(id=1) - # f_to_be_deleted = w.csvfilename - # os.remove(f_to_be_deleted+'.gz') - - #@pytest.mark.django_db -> class URLTests(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot', -> ) -> r = Rower.objects.create(user=u,rowerplan='coach') -> self.c = Client() -> self.c.login(username='john',password='koeinsloot') - -> self.nu = datetime.datetime.now() -> filename = 'rowers/tests/testdata/testdata.csv' -> self.wotw = Workout.objects.create(name='testworkout', -> workouttype='water', -> user=r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=self.nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000, -> csvfilename=filename) - -> self.wote = Workout.objects.create(name='testworkout', -> workouttype='Indoor Rower', -> user=r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=self.nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000, -> csvfilename=filename) - -> powerperc = 100*np.array([r.pw_ut2, -> r.pw_ut1, -> r.pw_at, -> r.pw_tr,r.pw_an])/r.ftp - - -> self.hrdata = { -> 'hrmax':r.max, -> 'hrut2':r.ut2, -> 'hrut1':r.ut1, -> 'hrat':r.at, -> 'hrtr':r.tr, -> 'hran':r.an, -> 'ftp':r.ftp, -> 'powerperc':serialize_list(powerperc), -> 'powerzones':serialize_list(r.powerzones), -> } - -> urlstotest = [ -> '/rowers/400/', -> '/rowers/403/', -> '/rowers/404/', -> '/rowers/500/', -> '/rowers/502/', -> '/rowers/1/list-workouts/', -> '/rowers/1/list-workouts/2016-01-01/2016-12-31', -> '/rowers/1/ote-bests/', -> '/rowers/1/ote-bests2/2016-01-01/2016-12-31', -> '/rowers/about', -> '/rowers/addmanual/', -> '/rowers/agegroupcp/30', -> '/rowers/agegroupcp/30/1', -> '/rowers/agegrouprecords/male/hwt', -> '/rowers/agegrouprecords/male/hwt/2000m', -> '/rowers/agegrouprecords/male/hwt/2000min', -> '/rowers/ajax_agegroup/45/hwt/male/1', -> '/rowers/analysis/', -> '/rowers/analysis/user/1', -> '/rowers/brochure', -> '/rowers/courses/upload', -> '/rowers/createplan/', -> '/rowers/createplan/user/1/', -> '/rowers/cumstats/', -> '/rowers/cumstats/2016-01-01/2016-12-31', -> '/rowers/cumstats/user/1', -> '/rowers/cumstats/user/1/2016-01-01/2016-12-31', -> '/rowers/developers', -> '/rowers/email/', -> '/rowers/email/thankyou/', -> '/rowers/fitness-progress/', -> '/rowers/fitness-progress/user/1', -> '/rowers/fitness-progress/user/1/rower', -> '/rowers/flexall/', -> '/rowers/flexall/spm/hr/None/', -> '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/', -> '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1', -> '/rowers/flexall/user/1/', -> '/rowers/flexalldata/', -> '/rowers/help', -> '/rowers/histo/', -> '/rowers/histo/user/1', -> '/rowers/histo/user/1/2016-01-01/2016-12-31', -> '/rowers/histodata', -> '/rowers/job-kill/1', -> '/rowers/jobs-status/', -> '/rowers/laboratory/', -> '/rowers/laboratory/user/1', -> '/rowers/legal', -> '/rowers/list-courses/', -> '/rowers/list-graphs/', -> '/rowers/list-jobs/', -> '/rowers/list-workouts/', -> '/rowers/list-workouts/2016-01-01/2016-12-31', -> '/rowers/list-workouts/2016-01-01/2016-12-31/user/1/', -> '/rowers/list-workouts/ranking', -> '/rowers/list-workouts/user/1/', -> '/rowers/me/calcdps/', -> '/rowers/me/edit/', -> '/rowers/me/edit/user/1', -> '/rowers/me/exportsettings/', -> '/rowers/me/exportsettings/user/1', -> '/rowers/me/favoritecharts/', -> '/rowers/me/favoritecharts/user/1', -> '/rowers/me/invitation/', -> '/rowers/me/preferences/', -> '/rowers/me/preferences/user/1', -> '/rowers/me/request/', -> '/rowers/me/teams/', -> '/rowers/me/workflowconfig2/', -> '/rowers/me/workflowconfig2/user/1', -> '/rowers/me/workflowdefault', -> '/rowers/multi-compare', -> '/rowers/ote-bests/', -> '/rowers/ote-bests/2016-01-01/2016-12-31', -> '/rowers/ote-bests/user/1', -> '/rowers/ote-bests/user/1/2016-01-01/2016-12-31', -> '/rowers/ote-bests2/', -> '/rowers/ote-bests2/2016-01-01/2016-12-31', -> '/rowers/ote-bests2/user/1', -> '/rowers/ote-ranking/', -> '/rowers/ote-ranking/2016-01-01/2016-12-31', -> '/rowers/ote-ranking/user/1/', -> '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31', -> '/rowers/otw-bests/', -> '/rowers/otw-bests/2016-01-01/2016-12-31', -> '/rowers/otw-bests/user/1/2016-01-01/2016-12-31', -> '/rowers/partners', -> '/rowers/physics', -> '/rowers/planrequired', -> '/rowers/promembership', -> '/rowers/register', -> '/rowers/register/thankyou/', -> '/rowers/sessions/', -> '/rowers/sessions/2016-01-01/2016-12-31', -> '/rowers/sessions/2016-01-01/2016-12-31/user/1', -> '/rowers/sessions/coach/', -> '/rowers/sessions/coach/user/1/', -> '/rowers/sessions/create/', -> '/rowers/sessions/create/user/1', -> '/rowers/sessions/manage/', -> '/rowers/sessions/manage/user/1/', -> '/rowers/sessions/multiclone/', -> '/rowers/sessions/multiclone/user/1/', -> '/rowers/sessions/multicreate/', -> '/rowers/sessions/multicreate/user/1/', -> '/rowers/sessions/print/', -> '/rowers/sessions/print/user/1', -> '/rowers/sessions/teamcreate/', -> '/rowers/sessions/user/1', -> '/rowers/team-compare-select/', -> '/rowers/team-compare-select/workout/1', -> '/rowers/team-compare-select/2016-01-01/2016-12-31', -> '/rowers/test-job/2', -> '/rowers/test-job2/2', -> '/rowers/test_callback', -> '/rowers/updatefitness', -> '/rowers/updatefitness/rower', -> '/rowers/updatefitness/rower/50', -> '/rowers/user-boxplot', -> '/rowers/user-boxplot-data', -> '/rowers/user-boxplot-select/', -> '/rowers/user-boxplot-select/user/1/', -> '/rowers/user-boxplot/user/1', -> '/rowers/user-multiflex-data', -> '/rowers/user-multiflex-select/', -> '/rowers/user-multiflex-select/2016-01-01/2016-12-31', -> '/rowers/user-multiflex-select/user/1/', -> '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31', -> '/rowers/user-multiflex/', -> '/rowers/user-multiflex/user/1', -> '/rowers/workout/1/', -> '/rowers/workout/1/adddistanceplot', -> '/rowers/workout/1/adddistanceplot2', -> '/rowers/workout/1/addotwpowerplot', -> '/rowers/workout/1/addpiechart', -> '/rowers/workout/1/addpowerpiechart', -> '/rowers/workout/1/addstatic', -> '/rowers/workout/1/addstatic/3', -> '/rowers/workout/1/addtimeplot', -> '/rowers/workout/1/addtimeplot2', -> '/rowers/workout/1/comment', -> '/rowers/workout/1/darkskywind', -> '/rowers/workout/1/data', -> '/rowers/workout/1/edit', -> '/rowers/workout/1/editintervals', -> '/rowers/workout/1/flexchart', -> '/rowers/workout/1/flexchart/spm/hr/None', -> '/rowers/workout/1/flexchart/spm/hr/None/scatter', -> '/rowers/workout/1/flexchart/spm/hr/None/scatter/', -> '/rowers/workout/1/forcecurve', -> '/rowers/workout/1/get-testscript', -> '/rowers/workout/1/get-thumbnails', -> '/rowers/workout/1/histo', -> '/rowers/workout/1/image', -> '/rowers/workout/1/instroke', -> '/rowers/workout/1/interactiveotwplot', -> '/rowers/workout/1/map', -> '/rowers/workout/1/otwsetpower', -> '/rowers/workout/1/recalcsummary/', -> '/rowers/workout/1/restore', -> '/rowers/workout/1/smoothenpace', -> '/rowers/workout/1/split', -> '/rowers/workout/1/stats', -> '/rowers/workout/1/stream', -> '/rowers/workout/1/task', -> '/rowers/workout/1/test_strokedata', -> '/rowers/workout/1/toggle-ranking', -> '/rowers/workout/1/undosmoothenpace', -> '/rowers/workout/1/unsubscribe', -> '/rowers/workout/1/updatecp', -> '/rowers/workout/1/view', -> '/rowers/workout/1/wind', -> '/rowers/workout/1/workflow', -> '/rowers/workout/compare/1/2016-01-01/2016-12-31', -> '/rowers/workout/fusion/1/', -> '/rowers/workout/fusion/1/2016-01-01/2016-12-31', -> '/rowers/workout/upload/', -> '/rowers/workout/upload/team/', -> '/rowers/workouts-join', -> '/rowers/workouts-join-select/', -> '/rowers/workouts-join-select/2016-01-01/2016-12-31', -> ] - -! lijst = [] -> for url in urlstotest: -> lijst.append( -> (url,200) -> ) - -> @parameterized.expand(lijst) -> def test_url_generator(self,url,expected): -> response = self.c.get(url,follow=True) -> if response.status_code != expected: -> print response.status_code -! self.assertEqual(response.status_code, -! expected, -! msg=url+' response status code not 200') - - - #@pytest.mark.django_db -> class subroutinetests(TestCase): -> def setUp(self): -> redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -! r = Rower.objects.create(user=u) -! nu = datetime.datetime.now() -> filename = 'rowers/tests/testdata/testdata.csv' -> self.w = Workout.objects.create(name='testworkout', -> workouttype='water', -> user=r,date=nu.strftime('%Y-%m-%d'), -> starttime=nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000, -> csvfilename=filename) - - -> def c2stuff(self): -> data = c2stuff.createc2workoutdata(self.w) -! jsond = json.dumps(data) -! data = c2stuff.createc2workoutdata_as_splits(w) -> jsond = json.dumps(data) - - - - #@pytest.mark.django_db -> class PlotTests(TestCase): -! def setUp(self): -! redis_connection.publish('tasks','KILL') -> u = User.objects.create_user('john', -> 'sander@ds.ds', -> 'koeinsloot') -! r = Rower.objects.create(user=u) -! self.nu = datetime.datetime.now() -> filename = 'rowers/tests/testdata/testdata.csv' -> self.wotw = Workout.objects.create(name='testworkout', -> workouttype='water', -> user=r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=self.nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000, -> csvfilename=filename) - -> self.wote = Workout.objects.create(name='testworkout', -> workouttype='Indoor Rower', -> user=r,date=self.nu.strftime('%Y-%m-%d'), -> starttime=self.nu.strftime('%H:%M:%S'), -> duration="0:55:00",distance=8000, -> csvfilename=filename) - - # timestr = strftime("%Y%m%d-%H%M%S") - # imagename = f1+timestr+'.png' - # fullpathimagename = 'static/plots/'+imagename -> powerperc = 100*np.array([r.pw_ut2, -> r.pw_ut1, -> r.pw_at, -> r.pw_tr,r.pw_an])/r.ftp - - -> self.hrdata = { -> 'hrmax':r.max, -> 'hrut2':r.ut2, -> 'hrut1':r.ut1, -> 'hrat':r.at, -> 'hrtr':r.tr, -> 'hran':r.an, -> 'ftp':r.ftp, -> 'powerperc':serialize_list(powerperc), -> 'powerzones':serialize_list(r.powerzones), -> } - - -! def test_ote_plots(self): -! w = self.wote -> f1 = 'testdata.csv'[:-4] -> timestr = strftime("%Y%m%d-%H%M%S") -> imagename = f1+timestr+'.png' -> fullpathimagename = 'static/plots/'+imagename - # make plot - asynchronous task -> plotnr = 1 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 1 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 2 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 3 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 4 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -! except WindowsError: -> pass - -> plotnr = 5 -! if (w.workouttype=='water'): -> plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -> pass - -> plotnr = 6 -! if (w.workouttype=='water'): -> plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -> pass - -> plotnr = 7 -! if (w.workouttype=='water'): -> plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -> pass - -> plotnr = 8 -! if (w.workouttype=='water'): -> plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -> pass - -> plotnr = 13 -! if (w.workouttype=='water'): -> plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -> pass - -> def test_otw_plots(self): -! w = self.wotw -> f1 = 'testdata.csv'[:-4] -> timestr = strftime("%Y%m%d-%H%M%S") -> imagename = f1+timestr+'.png' -> fullpathimagename = 'static/plots/'+imagename - # make plot - asynchronous task -> plotnr = 1 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 1 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 2 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 3 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 4 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -> res = handle_makeplot(f1,w.csvfilename, -> w.name,self.hrdata,plotnr,imagename) -> i = GraphImage(workout=w,creationdatetime=self.nu, -> filename=fullpathimagename) -> try: -> os.remove(fullpathimagename) -> except WindowsError: -> pass - -> plotnr = 5 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass - -! plotnr = 6 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass - -! plotnr = 7 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass - -! plotnr = 8 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass - -! plotnr = 9 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass - -! plotnr = 13 -! if (w.workouttype=='water'): -! plotnr = plotnr+3 - -! res = handle_makeplot(f1,w.csvfilename, -! w.name,self.hrdata,plotnr,imagename) -! i = GraphImage(workout=w,creationdatetime=self.nu, -! filename=fullpathimagename) -! try: -! os.remove(fullpathimagename) -! except WindowsError: -! pass diff --git a/rowers/views.py b/rowers/views.py index 77299f11..9450d9cb 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -38,6 +38,7 @@ from django.views.generic.edit import UpdateView,DeleteView from django.http import ( HttpResponse, HttpResponseRedirect, + JsonResponse, HttpResponseForbidden, HttpResponseNotAllowed, HttpResponseNotFound,Http404 ) @@ -227,6 +228,7 @@ class JSONResponse(HttpResponse): kwargs['content_type'] = 'application/json' super(JSONResponse, self).__init__(content, **kwargs) + def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): userid = int(userid) @@ -12038,7 +12040,10 @@ def workout_toggle_ranking(request,id=0): row.save() if is_ajax: - return JSONResponse({'result':row.rankingpiece}) + response = JSONResponse({'result':row.rankingpiece}, + content_type='application/json') + + return response else: url = reverse(workouts_view) response = HttpResponseRedirect(url) From 7e8cb40d464097c19dc8456074ef78d28bbf6843 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 4 Jan 2019 08:27:01 +0100 Subject: [PATCH 11/18] adding multi compare test --- rowers/tests/test_fakers.py | 140 ++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 rowers/tests/test_fakers.py diff --git a/rowers/tests/test_fakers.py b/rowers/tests/test_fakers.py new file mode 100644 index 00000000..c7dfb940 --- /dev/null +++ b/rowers/tests/test_fakers.py @@ -0,0 +1,140 @@ +#from __future__ import print_function +import pytest + +pytestmark = pytest.mark.django_db + +from bs4 import BeautifulSoup +import re +from nose_parameterized import parameterized +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from rowers.views import checkworkoutuser,c2_open + +from rowers.forms import ( + DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail, + ChartParamChoiceForm,WorkoutMultipleCompareForm) +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.utils import NoTokenError +from shutil import copyfile +from nose.tools import assert_true +from mock import Mock, patch +from minimocktest import MockTestCase +import pandas as pd +import rowers.c2stuff as c2stuff + +import json +import numpy as np + +from rowers import urls +from rowers.views import ( + error500_view,error404_view,error400_view,error403_view + ) + +from rowers.dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +from django_mailbox.models import Mailbox,MessageAttachment,Message + +from rowers.tests.mocks import * + +from rowers.models import * + +import factory +from faker import Factory + +faker = Factory.create() + +filename = 'rowers/tests/testdata/testdata.csv' + +row = rdata(filename) +totaldist = row.df['cum_dist'].max() +totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() +totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + +hours = int(totaltime/3600.) +minutes = int((totaltime - 3600.*hours)/60.) +seconds = int(totaltime - 3600.*hours - 60.*minutes) +tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + +duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) +duration = datetime.time(hour=hours,minute=minutes,second=seconds) + +workoutdate = row.rowdatetime.strftime('%Y-%m-%d') +workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + +nu = datetime.datetime.now() + +class UserFactory(factory.DjangoModelFactory): + class Meta: + model = User + + email = faker.email() + username = faker.profile()['username'] + + first_name = faker.name().split(' ')[0] + last_name = faker.name().split(' ')[0] + +class WorkoutFactory(factory.DjangoModelFactory): + class Meta: + model = Workout + + name = factory.LazyAttribute(lambda _: faker.word()) + notes = faker.text() + startdatetime = row.rowdatetime + starttime = workoutstarttime + workouttype='water' + date=timezone.now().date() + duration=duration + distance=totaldist + csvfilename=filename + +class ModelObjectsTest(TestCase): + def setUp(self): + self.u = UserFactory() + self.r = Rower.objects.create(user=self.u, + birthdate=faker.profile()['birthdate'], + gdproptin=True) + + self.c = Client() + + def test_workouts_compare(self): + user_workouts = WorkoutFactory.create_batch(5, user=self.r) + + url = '/rowers/team-compare-select/workout/1/team/0/user/1/' + + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + + form_data = { + 'chartform':'Compare', + 'plottype':'scatter', + 'teamid':0, + 'workouts':['1','2','3'], + 'xparam':'distance', + 'yparam':'hr', + } + + form = WorkoutMultipleCompareForm(form_data) + chartform = ChartParamChoiceForm(form_data) + self.assertTrue(form.is_valid) + self.assertTrue(chartform.is_valid) + + response = self.c.post('/rowers/multi-compare',form_data,follow=True) + + self.assertEqual(response.status_code,200) From 50928cba32e720d46ae50c27612a654c07124618 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 4 Jan 2019 09:14:14 +0100 Subject: [PATCH 12/18] changed links to paidplans was promembership --- rowers/templates/about_us.html | 2 +- rowers/templates/advancededit.html | 18 ++--- rowers/templates/advancedotw.html | 24 +++--- rowers/templates/basebase.html | 2 +- rowers/templates/comparisonchart2.html | 4 +- rowers/templates/flexchart2.html | 36 ++++----- rowers/templates/imports.html | 2 +- rowers/templates/menu_workouts.html | 2 +- rowers/templates/rankings.html | 2 +- rowers/templates/registeremail.html | 2 +- rowers/views.py | 108 ++++++++++++------------- templates/newbase.html | 6 +- templates/newbasefront.html | 4 +- 13 files changed, 106 insertions(+), 106 deletions(-) diff --git a/rowers/templates/about_us.html b/rowers/templates/about_us.html index 1d64d9b4..c178aa32 100644 --- a/rowers/templates/about_us.html +++ b/rowers/templates/about_us.html @@ -93,7 +93,7 @@ and inspired by the RowPro Dan Burpee spreadsheet

We offer three plans. Click on the name of the plan to find out more:

    -
  • Pro Membership, +
  • Pro Membership, offering additional rowing metrics and analysis tools for individual rowers.
  • Self-Coach Membership, diff --git a/rowers/templates/advancededit.html b/rowers/templates/advancededit.html index d0d4feaf..5ab7140b 100644 --- a/rowers/templates/advancededit.html +++ b/rowers/templates/advancededit.html @@ -16,7 +16,7 @@

    {{ workout.name }} - Advanced

    {% if user.rower.rowerplan == 'basic' %}

    Functionality marked with an asterisk (*) is limited to the paid plans. See - the page about Pro membership + the page about Pro membership for more information and to sign up for Pro Membership

    {% endif %} @@ -62,7 +62,7 @@ {% if user|is_promember %} Compare Workouts {% else %} - Compare Workouts* + Compare Workouts* {% endif %}

    Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts. @@ -82,7 +82,7 @@ {% if user|is_promember %} Edit Intervals {% else %} - Edit Intervals* + Edit Intervals* {% endif %}

    Enter or change the interval and summary data for your workout @@ -98,7 +98,7 @@ {% if user|is_promember %} Dist Metrics Plot {% else %} - Dist Metrics Plot* + Dist Metrics Plot* {% endif %}

    @@ -110,7 +110,7 @@ {% if user|is_promember %} Time Metrics Plot {% else %} - Time Metrics Plot* + Time Metrics Plot* {% endif %}

    @@ -122,7 +122,7 @@ {% if user|is_promember %} Power Histogram {% else %} - Power Histogram* + Power Histogram* {% endif %}

    @@ -136,7 +136,7 @@ {% if user|is_promember %} Glue {% else %} - Glue* + Glue* {% endif %}

    @@ -149,7 +149,7 @@ {% if user|is_promember %} Sensor Fusion {% else %} - Sensor Fusion* + Sensor Fusion* {% endif %}

    @@ -161,7 +161,7 @@ {% if user|is_promember %} Split Workout {% else %} - Split Workout* + Split Workout* {% endif %}

    diff --git a/rowers/templates/advancedotw.html b/rowers/templates/advancedotw.html index 4e8c0924..56d5a322 100644 --- a/rowers/templates/advancedotw.html +++ b/rowers/templates/advancedotw.html @@ -16,7 +16,7 @@

    {{ workout.name }} - Advanced OTW

    {% if user.rower.rowerplan == 'basic' %}

    Functionality marked with an asterisk (*) is limited to the paid plans. See - the page about Pro membership + the page about Pro membership for more information and to sign up for Pro Membership

    {% endif %}
    @@ -60,7 +60,7 @@ {% if user|is_promember %} Compare Workouts {% else %} - Compare Workouts* + Compare Workouts* {% endif %}

    @@ -82,7 +82,7 @@ {% if user|is_promember %} Edit Intervals {% else %} - Edit Intervals* + Edit Intervals* {% endif %}

    Enter or change the interval and summary data for your workout @@ -99,7 +99,7 @@ {% if user|is_promember %} CrewNerd Summary {% else %} - CrewNerd Summary* + CrewNerd Summary* {% endif %}

    @@ -113,7 +113,7 @@ {% if user|is_promember %} Stroke Profile (Empower) {% else %} - Stroke Profile (Empower)* + Stroke Profile (Empower)* {% endif %}

    Analyze your stroke force profile (need Empower Oarlock data)

    @@ -126,7 +126,7 @@ {% if user|is_promember %} OTW Power Plot {% else %} - OTW Power Plot* + OTW Power Plot* {% endif %}

    Note: You must run the OTW calculations under Geeky Stuff first. Otherwise the plot will be empty @@ -146,7 +146,7 @@ {% if user|is_promember %} Geeky Stuff {% else %} - Geeky Stuff* + Geeky Stuff* {% endif %}

    @@ -161,7 +161,7 @@ {% if user|is_promember %} Smooth out Pace Data {% else %} - Smooth out Pace Data* + Smooth out Pace Data* {% endif %}

    @@ -178,7 +178,7 @@ {% if user|is_promember %} Raw Data {% else %} - Reset Smoothing* + Reset Smoothing* {% endif %}

    @@ -193,7 +193,7 @@ {% if user|is_promember %} Glue {% else %} - Glue* + Glue* {% endif %}

    @@ -205,7 +205,7 @@ {% if user|is_promember %} Sensor Fusion {% else %} - Sensor Fusion* + Sensor Fusion* {% endif %}

    @@ -217,7 +217,7 @@ {% if user|is_promember %} Split Workout {% else %} - Split Workout* + Split Workout* {% endif %}

    diff --git a/rowers/templates/basebase.html b/rowers/templates/basebase.html index 41dd1dfb..98f30743 100644 --- a/rowers/templates/basebase.html +++ b/rowers/templates/basebase.html @@ -98,7 +98,7 @@ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}

    Pro Member
    {% else %} - + {% endif %}
    diff --git a/rowers/templates/comparisonchart2.html b/rowers/templates/comparisonchart2.html index 1fd119fe..93a996b8 100644 --- a/rowers/templates/comparisonchart2.html +++ b/rowers/templates/comparisonchart2.html @@ -74,7 +74,7 @@ {% endfor %} {% else %} {% for key, value in axchoicespro.items %} - {{ value }} + {{ value }} {% endfor %} {% endif %} @@ -98,7 +98,7 @@ {% else %} {% for key, value in axchoicespro.items %} {% if key not in noylist %} - {{ value }} (Pro) + {{ value }} (Pro) {% endif %} {% endfor %} {% endif %} diff --git a/rowers/templates/flexchart2.html b/rowers/templates/flexchart2.html index 8dbf755f..253bc0c7 100644 --- a/rowers/templates/flexchart2.html +++ b/rowers/templates/flexchart2.html @@ -76,14 +76,14 @@ Work per Stroke Drive Speed {% else %} - Power (Pro) - HR (Pro) - SPM (Pro) - Peak Force (Pro) - Average Force (Pro) - Drive Length (Pro) - Work per Stroke (Pro) - Drive Speed (Pro) + Power (Pro) + HR (Pro) + SPM (Pro) + Peak Force (Pro) + Average Force (Pro) + Drive Length (Pro) + Work per Stroke (Pro) + Drive Speed (Pro) {% endif %} @@ -103,11 +103,11 @@ Work per Stroke Drive Speed {% else %} - Peak Force (Pro) - Average Force (Pro) - Drive Length (Pro) - Work per Stroke (Pro) - Drive Speed (Pro) + Peak Force (Pro) + Average Force (Pro) + Drive Length (Pro) + Work per Stroke (Pro) + Drive Speed (Pro) {% endif %} @@ -126,11 +126,11 @@ Work per Stroke Drive Speed {% else %} - Peak Force (Pro) - Average Force (Pro) - Drive Length (Pro) - Work per Stroke (Pro) - Drive Speed (Pro) + Peak Force (Pro) + Average Force (Pro) + Drive Length (Pro) + Work per Stroke (Pro) + Drive Speed (Pro) {% endif %} None diff --git a/rowers/templates/imports.html b/rowers/templates/imports.html index 87dbd002..ceb31260 100644 --- a/rowers/templates/imports.html +++ b/rowers/templates/imports.html @@ -115,7 +115,7 @@ to the partner site

    These settings only have effect if you are a user on one - of the paid plans

    + of the paid plans

    diff --git a/rowers/templates/menu_workouts.html b/rowers/templates/menu_workouts.html index 90905a6e..1721f0bd 100644 --- a/rowers/templates/menu_workouts.html +++ b/rowers/templates/menu_workouts.html @@ -25,7 +25,7 @@ {% if user|is_promember %} {% else %} - + {% endif %}  Glue Workouts diff --git a/rowers/templates/rankings.html b/rowers/templates/rankings.html index bfffd7e4..6291b8b5 100644 --- a/rowers/templates/rankings.html +++ b/rowers/templates/rankings.html @@ -90,7 +90,7 @@

    Missing your best pieces? Upload stroke data of any Concept2 ranking piece and they will be automatically added to this page.

    Don't have stroke data for official Concept2 ranking pieces? - The PRO membership ranking piece functionality + The PRO membership ranking piece functionality allows you to include your best non ranking pieces and even use parts of workouts for improved calculation accuracy.

    diff --git a/rowers/templates/registeremail.html b/rowers/templates/registeremail.html index d427b5a7..c516f592 100644 --- a/rowers/templates/registeremail.html +++ b/rowers/templates/registeremail.html @@ -39,7 +39,7 @@ If you find it to be useful, please help us cover our hosting costs and gain access to additional functionality by signing on as a Pro member: - https://rowsandall.com/rowers/promembership + https://rowsandall.com/rowers/paidplans

    diff --git a/rowers/views.py b/rowers/views.py index 9450d9cb..55660d38 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -1647,7 +1647,7 @@ def start_trial_view(request): if r.protrialexpires is not None: messages.error(request,'You do not qualify for a trial') - url = '/rowers/promembership' + url = '/rowers/paidplans' return HttpResponseRedirect(url) r.protrialexpires = datetime.date.today()+datetime.timedelta(13) @@ -1674,7 +1674,7 @@ def start_plantrial_view(request): if r.plantrialexpires is not None: messages.error(request,'You do not qualify for a trial') - url = '/rowers/promembership' + url = '/rowers/paidplans' return HttpResponseRedirect(url) r.plantrialexpires = datetime.date.today()+datetime.timedelta(13) @@ -3512,7 +3512,7 @@ def planrequired_view(request): return render(request,'promembership.html') -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def fitnessmetric_view(request,id=0,mode='rower', @@ -3555,7 +3555,7 @@ def fitnessmetric_view(request,id=0,mode='rower', # Show the EMpower Oarlock generated Stroke Profile -@user_passes_test(ispromember,login_url="/rowers/promembership/", +@user_passes_test(ispromember,login_url="/rowers/paidplans/", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_forcecurve_view(request,id=0,workstrokesonly=False): @@ -3687,7 +3687,7 @@ def workout_histo_view(request,id=0): # Histogram for a date/time range -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def histo(request,theuser=0, @@ -4802,7 +4802,7 @@ def rankings_view2(request,theuser=0, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_update_cp_view(request,id=0): @@ -4830,7 +4830,7 @@ def workout_update_cp_view(request,id=0): return HttpResponseRedirect(url) # Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def otwrankings_view(request,theuser=0, @@ -5235,7 +5235,7 @@ def otwcp_toadmin_view(request,theuser=0, return response # Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def oterankings_view(request,theuser=0, @@ -5677,7 +5677,7 @@ def workout_setprivate_view(request,id, return HttpResponseRedirect(url) # Joining workout -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workouts_join_view(request): @@ -5723,7 +5723,7 @@ def workouts_join_view(request): url = reverse(workouts_join_select) return HttpResponseRedirect(url) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workouts_join_select(request, @@ -6431,7 +6431,7 @@ def multi_compare_view(request,id=0,userid=0): # Multi Flex Chart with Grouping -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def user_multiflex_select(request, @@ -6637,7 +6637,7 @@ def user_multiflex_select(request, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def multiflex_data(request,userid=0, @@ -6883,7 +6883,7 @@ def multiflex_data(request,userid=0, }) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def multiflex_view(request,userid=0, @@ -7050,7 +7050,7 @@ def multiflex_view(request,userid=0, # Box plots -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def user_boxplot_select(request, @@ -7258,7 +7258,7 @@ def user_boxplot_select(request, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def boxplot_view_data(request,userid=0, @@ -7365,7 +7365,7 @@ def boxplot_view_data(request,userid=0, "div":div, }) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def boxplot_view(request,userid=0, @@ -7722,7 +7722,7 @@ def workouts_view(request,message='',successmessage='', # List of workouts to compare a selected workout to -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_comparison_list(request,id=0,message='',successmessage='', @@ -7808,7 +7808,7 @@ def workout_comparison_list(request,id=0,message='',successmessage='', # List of workouts to compare a selected workout to -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_fusion_list(request,id=0,message='',successmessage='', @@ -8011,7 +8011,7 @@ def workout_view(request,id=0): # Resets stroke data to raw data (pace) -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_undo_smoothenpace_view( @@ -8050,7 +8050,7 @@ def workout_undo_smoothenpace_view( # Data smoothing of pace data -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_smoothenpace_view(request,id=0,message="",successmessage=""): @@ -8103,7 +8103,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): return HttpResponseRedirect(url) # Process CrewNerd Summary CSV and update summary -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): @@ -8180,7 +8180,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): 'id':row.id}) # Get weather for given location and date/time -@user_passes_test(ispromember,login_url="/rowers/promembership", +@user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_downloadwind_view(request,id=0, @@ -8248,7 +8248,7 @@ def workout_downloadwind_view(request,id=0, return response # Get weather for given location and date/time -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_downloadmetar_view(request,id=0, airportcode=None, message="",successmessage=""): @@ -8315,7 +8315,7 @@ def workout_downloadmetar_view(request,id=0, # Show form to update wind data -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_wind_view(request,id=0,message="",successmessage=""): row = get_workout(id) r = getrower(request.user) @@ -8451,7 +8451,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): # Show form to update River stream data (for river dwellers) -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_stream_view(request,id=0,message="",successmessage=""): row = get_workout(id) r = getrower(request.user) @@ -8537,7 +8537,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""): 'the_div':div}) # Form to set average crew weight and boat type, then run power calcs -@user_passes_test(ispromember, login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember, login_url="/rowers/paidplans",redirect_field_name=None) def workout_otwsetpower_view(request,id=0,message="",successmessage=""): w = get_workout(id) r = getrower(request.user) @@ -8846,7 +8846,7 @@ def instroke_chart(request,id=0,metric=''): return HttpResponseRedirect(url) # Cumulative stats page -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def cumstats(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=30), enddate=timezone.now(), @@ -12484,7 +12484,7 @@ def workout_upload_view(request, # This is the main view for processing uploaded files -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_workout_upload_view(request,message="", successmessage="", uploadoptions={ @@ -12891,7 +12891,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): return HttpResponseRedirect(url) # Split a workout -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_split_view(request,id=id): row = get_workout_permitted(request.user,id) @@ -12982,7 +12982,7 @@ def workout_split_view(request,id=id): # Fuse two workouts -@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_fusion_view(request,id1=0,id2=1): r = getrower(request.user) @@ -14727,7 +14727,7 @@ def rower_teams_view(request,message='',successmessage=''): 'myinvites':myinvites, }) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def invitation_revoke_view(request,id): res,text = teams.revoke_invite(request.user,id) if res: @@ -14741,7 +14741,7 @@ def invitation_revoke_view(request,id): return HttpResponseRedirect(url) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def manager_member_drop_view(request,teamid,userid, message='',successmessage=''): rower = Rower.objects.get(user__id=userid) @@ -14755,7 +14755,7 @@ def manager_member_drop_view(request,teamid,userid, return HttpResponseRedirect(url) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def manager_requests_view(request,code=None,message='',successmessage=''): if code: res,text = teams.process_request_code(request.user,code) @@ -14807,7 +14807,7 @@ def request_revoke_view(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def request_reject_view(request,id=0): res,text = teams.reject_request(request.user,id) @@ -14820,7 +14820,7 @@ def request_reject_view(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def invitation_reject_view(request,id=0): res,text = teams.reject_invitation(request.user,id) @@ -14856,7 +14856,7 @@ def rower_invitations_view(request,code=None,message='',successmessage=''): }) return HttpResponseRedirect(url) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_edit_view(request,id=0): try: t = Team.objects.get(id=id) @@ -14920,7 +14920,7 @@ def team_edit_view(request,id=0): 'team':t, }) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_create_view(request): if request.method == 'POST': teamcreateform = TeamForm(request.POST) @@ -14963,7 +14963,7 @@ def team_create_view(request): 'breadcrumbs':breadcrumbs, }) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_deleteconfirm_view(request,id): r = getrower(request.user) try: @@ -14999,7 +14999,7 @@ def team_deleteconfirm_view(request,id): 'active':'nav-teams', }) -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_delete_view(request,id): r = getrower(request.user) try: @@ -15015,7 +15015,7 @@ def team_delete_view(request,id): response = HttpResponseRedirect(url) return response -@user_passes_test(iscoachmember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None) def team_members_stats_view(request,id): r = getrower(request.user) try: @@ -15112,7 +15112,7 @@ def agegrouprecordview(request,sex='male',weightcategory='hwt', }) # Cloning sessions -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multiclone_view( @@ -15242,7 +15242,7 @@ def plannedsession_multiclone_view( ) # Individual user creates training for himself -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_create_view(request, @@ -15379,7 +15379,7 @@ def plannedsession_create_view(request, 'timeperiod':timeperiod, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multicreate_view(request, @@ -15492,7 +15492,7 @@ def plannedsession_multicreate_view(request, return render(request,'plannedsession_multicreate.html',context) # Manager creates sessions for entire team -@user_passes_test(iscoachmember,login_url="/rowers/promembership/", +@user_passes_test(iscoachmember,login_url="/rowers/paidplans/", redirect_field_name=None) def plannedsession_teamcreate_view(request, teamid=0,userid=0): @@ -15659,7 +15659,7 @@ def plannedsession_teamcreate_view(request, }) # Manager edits sessions for entire team -@user_passes_test(iscoachmember,login_url="/rowers/promembership/", +@user_passes_test(iscoachmember,login_url="/rowers/paidplans/", redirect_field_name=None) def plannedsession_teamedit_view(request, sessionid=0,userid=0): @@ -15815,7 +15815,7 @@ def plannedsession_teamedit_view(request, 'plannedsessions':sps, }) -#@user_passes_test(iscoachmember,login_url="/rowers/promembership/", +#@user_passes_test(iscoachmember,login_url="/rowers/paidplans/", # redirect_field_name=None) @login_required() def plannedsessions_coach_view(request, @@ -16264,7 +16264,7 @@ def plannedsessions_manage_view(request,userid=0, # Clone an existing planned session # need clarity on cloning behavior time shift -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_clone_view(request,id=0,userid=0): @@ -16325,7 +16325,7 @@ def plannedsession_clone_view(request,id=0,userid=0): # Edit an existing planned session -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_edit_view(request,id=0,userid=0): @@ -18364,7 +18364,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): 'w_form':w_form, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_create_trainingplan(request,userid=0): @@ -18468,7 +18468,7 @@ def rower_create_trainingplan(request,userid=0): 'targetform':targetform, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_delete_trainingtarget(request,id=0): @@ -18488,7 +18488,7 @@ def rower_delete_trainingtarget(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_delete_trainingplan(request,id=0): @@ -18801,7 +18801,7 @@ class MacroCycleDelete(DeleteView): return obj -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_trainingplan_view(request, @@ -19320,7 +19320,7 @@ def allsundays(startdate,enddate): yield d d += timedelta(days=7) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def planmesocyclebyweek(request,id=0,userid=0): @@ -19381,7 +19381,7 @@ def allmonths(startdate,enddate): yield d d = datetime.date(d.year+(d.month / 12),((d.month % 12) + 1),1) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def planmacrocyclebymonth(request,id=0,userid=0): diff --git a/templates/newbase.html b/templates/newbase.html index 00ddebf6..462a2e02 100644 --- a/templates/newbase.html +++ b/templates/newbase.html @@ -236,7 +236,7 @@ {% if user.rower.planexpires|date_dif|ddays < 4 %}

  • - You have {{ user.rower.planexpires|date_dif|ddays }} days left of your one year subscription. Please renew on or before {{ user.rower.planexpires }} or your plan will be reset to Basic. Click here to renew your membership.

    + You have {{ user.rower.planexpires|date_dif|ddays }} days left of your one year subscription. Please renew on or before {{ user.rower.planexpires }} or your plan will be reset to Basic. Click here to renew your membership.

  • {% endif %} {% endif %} @@ -252,7 +252,7 @@ {% if user.rower.rowerplan == 'basic' %}
  • - {{ user.rower.protrialexpires|date_dif|ddays }} days left of your Pro trial - Would you like to upgrade now? + {{ user.rower.protrialexpires|date_dif|ddays }} days left of your Pro trial - Would you like to upgrade now?

  • {% endif %} @@ -375,7 +375,7 @@

    Paid Plans

  • diff --git a/templates/newbasefront.html b/templates/newbasefront.html index 85abb700..55303389 100644 --- a/templates/newbasefront.html +++ b/templates/newbasefront.html @@ -254,7 +254,7 @@ {% if user.rower.rowerplan == 'basic' %}
  • - {{ user.rower.protrialexpires|date_dif|ddays }} days left of your Pro trial - Would you like to upgrade now? + {{ user.rower.protrialexpires|date_dif|ddays }} days left of your Pro trial - Would you like to upgrade now?

  • {% endif %} @@ -347,7 +347,7 @@

    Paid Plans

    From 879e16e057db542083403a635787b249d6e28adf Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 4 Jan 2019 14:56:51 +0100 Subject: [PATCH 13/18] no changes, really --- rowers/tests/test_fakers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rowers/tests/test_fakers.py b/rowers/tests/test_fakers.py index c7dfb940..65d906e3 100644 --- a/rowers/tests/test_fakers.py +++ b/rowers/tests/test_fakers.py @@ -112,15 +112,17 @@ class ModelObjectsTest(TestCase): gdproptin=True) self.c = Client() + self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) def test_workouts_compare(self): - user_workouts = WorkoutFactory.create_batch(5, user=self.r) + self.c.login(username=self.u.username,password=self.u.password) url = '/rowers/team-compare-select/workout/1/team/0/user/1/' response = self.c.get(url,follow=True) self.assertEqual(response.status_code,200) - + + def test_workouts_compare_submit(self): form_data = { 'chartform':'Compare', 'plottype':'scatter', From c85bc536329bb232256c9f5301a1149da2eca5b5 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 4 Jan 2019 18:14:42 +0100 Subject: [PATCH 14/18] improved most tests --- rowers/interactiveplots.py | 3 + rowers/templatetags/rowerfilters.py | 61 +- rowers/tests/mocks.py | 12 +- rowers/tests/test_fakers.py | 53 +- rowers/tests/test_imports.py | 30 +- rowers/tests/test_urls.py | 257 ++--- rowers/tests/testdata/colsfromdb.csv | 1399 +++++++++++++++++++++++++ rowers/tests/testdata/testdata.csv.gz | Bin 7866 -> 11511 bytes rowers/tests/tests.py | 51 +- rowers/urls.py | 402 +++---- rowers/views.py | 8 +- 11 files changed, 1872 insertions(+), 404 deletions(-) create mode 100644 rowers/tests/testdata/colsfromdb.csv diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index d1b88a42..2efc1487 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -673,6 +673,9 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower'): dates = [m.date for m in fitnessmetrics] mode = [m.workoutmode for m in fitnessmetrics] + if len(power4min) == 0: + return ['',''] + df = pd.DataFrame( {'power4min':power4min, 'power2k':power2k, diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 253ced99..207363ce 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -493,21 +493,26 @@ def micromacroid(id): @register.filter def nextworkout(workout,user): if user.rower == workout.user: - ws = Workout.objects.filter( - startdatetime__gte=workout.startdatetime, - user=workout.user - ).order_by( - "startdatetime" - ).exclude(id=workout.id) + try: + ws = Workout.objects.filter( + startdatetime__gte=workout.startdatetime, + user=workout.user + ).order_by( + "startdatetime" + ).exclude(id=workout.id) + except ValueError: + return 0 else: - ws = Workout.objects.filter( - startdatetime__gte=workout.startdatetime, - user=workout.user,privacy='visible' - ).order_by( - "startdatetime" - ).exclude(id=workout.id) - - + try: + ws = Workout.objects.filter( + startdatetime__gte=workout.startdatetime, + user=workout.user,privacy='visible' + ).order_by( + "startdatetime" + ).exclude(id=workout.id) + except ValueError: + return 0 + if ws: return ws[0].id else: @@ -518,19 +523,25 @@ def nextworkout(workout,user): @register.filter def previousworkout(workout,user): if user.rower == workout.user: - ws = Workout.objects.filter( - startdatetime__lte=workout.startdatetime, - user=workout.user - ).order_by( + try: + ws = Workout.objects.filter( + startdatetime__lte=workout.startdatetime, + user=workout.user + ).order_by( "-startdatetime" - ).exclude(id=workout.id) + ).exclude(id=workout.id) + except ValueError: + return 0 else: - ws = Workout.objects.filter( - startdatetime__lte=workout.startdatetime, - user=workout.user,privacy='visible' - ).order_by( - "-startdatetime" - ).exclude(id=workout.id) + try: + ws = Workout.objects.filter( + startdatetime__lte=workout.startdatetime, + user=workout.user,privacy='visible' + ).order_by( + "-startdatetime" + ).exclude(id=workout.id) + except ValueError: + return 0 if ws: diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 2436af15..e48495c8 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -113,7 +113,17 @@ def mocked_read_df_sql(id): return df - + +def mocked_getsmallrowdata_db(*args, **kwargs): + df = pd.read_csv('rowers/tests/testdata/colsfromdb.csv') + + return df + +def mocked_read_df_cols_sql(ids, columns, convertnewtons=True): + df = pd.read_csv('rowers/tests/testdata/fake_strokedata.csv') + extracols = [] + + return df, extracols class mocked_rowingdata(rowingdata): def __init__(self, *args, **kwargs): diff --git a/rowers/tests/test_fakers.py b/rowers/tests/test_fakers.py index 65d906e3..04969fb4 100644 --- a/rowers/tests/test_fakers.py +++ b/rowers/tests/test_fakers.py @@ -6,11 +6,12 @@ pytestmark = pytest.mark.django_db from bs4 import BeautifulSoup import re from nose_parameterized import parameterized -from django.test import TestCase, Client,override_settings +from django.test import TestCase, Client,override_settings, RequestFactory + from django.core.management import call_command from django.utils.six import StringIO from django.test.client import RequestFactory -from rowers.views import checkworkoutuser,c2_open +from rowers.views import checkworkoutuser,c2_open, multi_compare_view from rowers.forms import ( DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail, @@ -44,6 +45,7 @@ from rowers.views import ( ) from rowers.dataprep import delete_strokedata +from django.contrib.sessions.middleware import SessionMiddleware from redis import StrictRedis redis_connection = StrictRedis() @@ -53,7 +55,7 @@ from django_mailbox.models import Mailbox,MessageAttachment,Message from rowers.tests.mocks import * from rowers.models import * - +from rowers.tests.mocks import * import factory from faker import Factory @@ -107,22 +109,41 @@ class WorkoutFactory(factory.DjangoModelFactory): class ModelObjectsTest(TestCase): def setUp(self): self.u = UserFactory() + self.r = Rower.objects.create(user=self.u, birthdate=faker.profile()['birthdate'], - gdproptin=True) + gdproptin=True, + gdproptindate=timezone.now(), + rowerplan='coach') self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + self.factory = RequestFactory() + self.password = faker.word() + self.u.set_password(self.password) + self.u.save() - def test_workouts_compare(self): - self.c.login(username=self.u.username,password=self.u.password) + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_workouts_compare(self, mocked_sqlalchemy, + mocked_getsmallrowdata_db): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + url = '/rowers/team-compare-select/workout/1/team/0/user/1/' - response = self.c.get(url,follow=True) + response = self.c.get(url) self.assertEqual(response.status_code,200) - def test_workouts_compare_submit(self): + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_workouts_compare_submit(self, mocked_sqlalchemy, + mocked_getsmallrowdata_db): + + login = self.c.login(username=self.u.username,password=self.password) + self.assertTrue(login) + form_data = { 'chartform':'Compare', 'plottype':'scatter', @@ -137,6 +158,20 @@ class ModelObjectsTest(TestCase): self.assertTrue(form.is_valid) self.assertTrue(chartform.is_valid) - response = self.c.post('/rowers/multi-compare',form_data,follow=True) +# request = self.factory.post('/rowers/multi-compare/') +# request.user = self.u +# request.POST = form_data + +# SessionMiddleware().process_request(request) + +# request.session['ids'] = [] + +# response = multi_compare_view(request) + +# self.assertEqual(response.status_code, 200) + + response = self.c.post('/rowers/multi-compare/',form_data) self.assertEqual(response.status_code,200) + + diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index ee537e2e..fad25be5 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -126,10 +126,10 @@ class C2Objects(DjangoTestCase): response = self.c.get('/rowers/workout/1/c2uploadw/') self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', + expected_url = '/rowers/workout/1/edit/', status_code=302,target_status_code=200) - self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.url, '/rowers/workout/1/edit/') self.assertEqual(response.status_code, 302) @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) @@ -146,7 +146,7 @@ class C2Objects(DjangoTestCase): response = self.c.get('/rowers/workout/c2import/12/',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', + expected_url='/rowers/workout/2/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -294,7 +294,7 @@ class StravaObjects(DjangoTestCase): response = self.c.get('/rowers/workout/stravaimport/12',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/1/edit', + expected_url='/rowers/workout/1/edit/', status_code=301,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -378,10 +378,10 @@ class STObjects(DjangoTestCase): response = self.c.get('/rowers/workout/1/sporttracksuploadw/') self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', + expected_url = '/rowers/workout/1/edit/', status_code=302,target_status_code=200) - self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.url, '/rowers/workout/1/edit/') self.assertEqual(response.status_code, 302) @patch('rowers.sporttracksstuff.requests.get', side_effect=mocked_requests) @@ -396,7 +396,7 @@ class STObjects(DjangoTestCase): response = self.c.get('/rowers/workout/sporttracksimport/12/',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', + expected_url='/rowers/workout/2/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -488,10 +488,10 @@ class RunKeeperObjects(DjangoTestCase): response = self.c.get('/rowers/workout/1/runkeeperuploadw/') self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', + expected_url = '/rowers/workout/1/edit/', status_code=302,target_status_code=200) - self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.url, '/rowers/workout/1/edit/') self.assertEqual(response.status_code, 302) @patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests) @@ -506,7 +506,7 @@ class RunKeeperObjects(DjangoTestCase): response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', + expected_url='/rowers/workout/2/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -590,10 +590,10 @@ class UAObjects(DjangoTestCase): response = self.c.get('/rowers/workout/1/underarmouruploadw/') self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', + expected_url = '/rowers/workout/1/edit/', status_code=302,target_status_code=200) - self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.url, '/rowers/workout/1/edit/') self.assertEqual(response.status_code, 302) @patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests) @@ -609,7 +609,7 @@ class UAObjects(DjangoTestCase): response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/2/edit', + expected_url='/rowers/workout/2/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -692,10 +692,10 @@ class TPObjects(DjangoTestCase): response = self.c.get('/rowers/workout/1/tpuploadw/') self.assertRedirects(response, - expected_url = '/rowers/workout/1/edit', + expected_url = '/rowers/workout/1/edit/', status_code=302,target_status_code=200) - self.assertEqual(response.url, '/rowers/workout/1/edit') + self.assertEqual(response.url, '/rowers/workout/1/edit/') self.assertEqual(response.status_code, 302) diff --git a/rowers/tests/test_urls.py b/rowers/tests/test_urls.py index 012a8bc4..6d568e3f 100644 --- a/rowers/tests/test_urls.py +++ b/rowers/tests/test_urls.py @@ -53,9 +53,9 @@ class URLTests(TestCase): 'sander@ds.ds', 'koeinsloot', ) - r = Rower.objects.create(user=u,rowerplan='coach') + r = Rower.objects.create(user=u,rowerplan='coach',gdproptin=True, + gdproptindate=timezone.now()) self.c = Client() - self.c.login(username='john',password='koeinsloot') self.nu = datetime.datetime.now() filename = 'rowers/tests/testdata/testdata.csv' @@ -98,100 +98,100 @@ class URLTests(TestCase): '/rowers/500/', '/rowers/502/', '/rowers/1/list-workouts/', - '/rowers/1/list-workouts/2016-01-01/2016-12-31', + '/rowers/1/list-workouts/2016-01-01/2016-12-31/', '/rowers/1/ote-bests/', - '/rowers/1/ote-bests2/2016-01-01/2016-12-31', - '/rowers/about', - '/rowers/addmanual/', - '/rowers/agegroupcp/30', - '/rowers/agegroupcp/30/1', - '/rowers/agegrouprecords/male/hwt', - '/rowers/agegrouprecords/male/hwt/2000m', - '/rowers/agegrouprecords/male/hwt/2000min', - '/rowers/ajax_agegroup/45/hwt/male/1', + '/rowers/1/ote-bests2/2016-01-01/2016-12-31/', + '/rowers/about/', + '/rowers/workout/addmanual/', + '/rowers/agegroupcp/30/', + '/rowers/agegroupcp/30/1/', + '/rowers/agegrouprecords/male/hwt/', + '/rowers/agegrouprecords/male/hwt/2000m/', + '/rowers/agegrouprecords/male/hwt/2000min/', + '/rowers/ajax_agegroup/45/hwt/male/1/', '/rowers/analysis/', - '/rowers/analysis/user/1', - '/rowers/brochure', - '/rowers/courses/upload', + '/rowers/analysis/user/1/', + '/rowers/brochure/', + '/rowers/courses/upload/', '/rowers/createplan/', '/rowers/createplan/user/1/', '/rowers/cumstats/', - '/rowers/cumstats/2016-01-01/2016-12-31', - '/rowers/cumstats/user/1', - '/rowers/cumstats/user/1/2016-01-01/2016-12-31', - '/rowers/developers', + '/rowers/cumstats/2016-01-01/2016-12-31/', + '/rowers/cumstats/user/1/', + '/rowers/cumstats/user/1/2016-01-01/2016-12-31/', + '/rowers/developers/', '/rowers/email/', '/rowers/email/thankyou/', '/rowers/fitness-progress/', - '/rowers/fitness-progress/user/1', - '/rowers/fitness-progress/user/1/rower', + '/rowers/fitness-progress/user/1/', + '/rowers/fitness-progress/user/1/rower/', '/rowers/flexall/', '/rowers/flexall/spm/hr/None/', '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/', - '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1', + '/rowers/flexall/spm/hr/None/2016-01-01/2016-12-31/user/1/', '/rowers/flexall/user/1/', '/rowers/flexalldata/', - '/rowers/help', + '/rowers/help/', '/rowers/histo/', - '/rowers/histo/user/1', - '/rowers/histo/user/1/2016-01-01/2016-12-31', - '/rowers/histodata', - '/rowers/job-kill/1', + '/rowers/histo/user/1/', + '/rowers/histo/user/1/2016-01-01/2016-12-31/', + '/rowers/histodata/', + '/rowers/job-kill/1/', '/rowers/jobs-status/', '/rowers/laboratory/', - '/rowers/laboratory/user/1', - '/rowers/legal', + '/rowers/laboratory/user/1/', + '/rowers/legal/', '/rowers/list-courses/', '/rowers/list-graphs/', '/rowers/list-jobs/', '/rowers/list-workouts/', - '/rowers/list-workouts/2016-01-01/2016-12-31', + '/rowers/list-workouts/2016-01-01/2016-12-31/', '/rowers/list-workouts/2016-01-01/2016-12-31/user/1/', - '/rowers/list-workouts/ranking', + '/rowers/list-workouts/ranking/', '/rowers/list-workouts/user/1/', '/rowers/me/calcdps/', '/rowers/me/edit/', - '/rowers/me/edit/user/1', + '/rowers/me/edit/user/1/', '/rowers/me/exportsettings/', - '/rowers/me/exportsettings/user/1', + '/rowers/me/exportsettings/user/1/', '/rowers/me/favoritecharts/', - '/rowers/me/favoritecharts/user/1', + '/rowers/me/favoritecharts/user/1/', '/rowers/me/invitation/', '/rowers/me/preferences/', - '/rowers/me/preferences/user/1', + '/rowers/me/preferences/user/1/', '/rowers/me/request/', '/rowers/me/teams/', '/rowers/me/workflowconfig2/', - '/rowers/me/workflowconfig2/user/1', - '/rowers/me/workflowdefault', - '/rowers/multi-compare', + '/rowers/me/workflowconfig2/user/1/', + '/rowers/me/workflowdefault/', +# '/rowers/multi-compare/', '/rowers/ote-bests/', - '/rowers/ote-bests/2016-01-01/2016-12-31', - '/rowers/ote-bests/user/1', - '/rowers/ote-bests/user/1/2016-01-01/2016-12-31', + '/rowers/ote-bests/2016-01-01/2016-12-31/', + '/rowers/ote-bests/user/1/', + '/rowers/ote-bests/user/1/2016-01-01/2016-12-31/', '/rowers/ote-bests2/', - '/rowers/ote-bests2/2016-01-01/2016-12-31', - '/rowers/ote-bests2/user/1', + '/rowers/ote-bests2/2016-01-01/2016-12-31/', + '/rowers/ote-bests2/user/1/', '/rowers/ote-ranking/', - '/rowers/ote-ranking/2016-01-01/2016-12-31', + '/rowers/ote-ranking/2016-01-01/2016-12-31/', '/rowers/ote-ranking/user/1/', - '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31', + '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31/', '/rowers/otw-bests/', - '/rowers/otw-bests/2016-01-01/2016-12-31', - '/rowers/otw-bests/user/1/2016-01-01/2016-12-31', - '/rowers/partners', - '/rowers/physics', - '/rowers/planrequired', - '/rowers/promembership', - '/rowers/register', + '/rowers/otw-bests/2016-01-01/2016-12-31/', + '/rowers/otw-bests/user/1/2016-01-01/2016-12-31/', + '/rowers/partners/', + '/rowers/physics/', + '/rowers/planrequired/', + '/rowers/promembership/', + '/rowers/register/', '/rowers/register/thankyou/', '/rowers/sessions/', - '/rowers/sessions/2016-01-01/2016-12-31', - '/rowers/sessions/2016-01-01/2016-12-31/user/1', + '/rowers/sessions/2016-01-01/2016-12-31/', + '/rowers/sessions/2016-01-01/2016-12-31/user/1/', '/rowers/sessions/coach/', '/rowers/sessions/coach/user/1/', '/rowers/sessions/create/', - '/rowers/sessions/create/user/1', + '/rowers/sessions/create/user/1/', '/rowers/sessions/manage/', '/rowers/sessions/manage/user/1/', '/rowers/sessions/multiclone/', @@ -199,83 +199,82 @@ class URLTests(TestCase): '/rowers/sessions/multicreate/', '/rowers/sessions/multicreate/user/1/', '/rowers/sessions/print/', - '/rowers/sessions/print/user/1', + '/rowers/sessions/print/user/1/', '/rowers/sessions/teamcreate/', - '/rowers/sessions/user/1', + '/rowers/sessions/user/1/', '/rowers/team-compare-select/', - '/rowers/team-compare-select/workout/1', - '/rowers/team-compare-select/2016-01-01/2016-12-31', - '/rowers/test-job/2', - '/rowers/test-job2/2', - '/rowers/test_callback', - '/rowers/updatefitness', - '/rowers/updatefitness/rower', - '/rowers/updatefitness/rower/50', - '/rowers/user-boxplot', - '/rowers/user-boxplot-data', - '/rowers/user-boxplot-select/', - '/rowers/user-boxplot-select/user/1/', - '/rowers/user-boxplot/user/1', - '/rowers/user-multiflex-data', - '/rowers/user-multiflex-select/', - '/rowers/user-multiflex-select/2016-01-01/2016-12-31', - '/rowers/user-multiflex-select/user/1/', - '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31', - '/rowers/user-multiflex/', - '/rowers/user-multiflex/user/1', + '/rowers/team-compare-select/workout/1/', + '/rowers/team-compare-select/2016-01-01/2016-12-31/', + '/rowers/test-job/2/', + '/rowers/test-job2/2/', +# '/rowers/test_callback/', +# '/rowers/updatefitness/', +# '/rowers/updatefitness/rower/', +# '/rowers/updatefitness/rower/50/', +# '/rowers/user-boxplot/', +# '/rowers/user-boxplot-data/', +# '/rowers/user-boxplot-select/', +# '/rowers/user-boxplot-select/user/1/', +# '/rowers/user-boxplot/user/1/', +# '/rowers/user-multiflex-data/', +# '/rowers/user-multiflex-select/', +# '/rowers/user-multiflex-select/2016-01-01/2016-12-31/', +# '/rowers/user-multiflex-select/user/1/', +# '/rowers/user-multiflex-select/user/1/2016-01-01/2016-12-31/', +# '/rowers/user-multiflex/', +# '/rowers/user-multiflex/user/1/', '/rowers/workout/1/', - '/rowers/workout/1/adddistanceplot', - '/rowers/workout/1/adddistanceplot2', - '/rowers/workout/1/addotwpowerplot', - '/rowers/workout/1/addpiechart', - '/rowers/workout/1/addpowerpiechart', - '/rowers/workout/1/addstatic', - '/rowers/workout/1/addstatic/3', - '/rowers/workout/1/addtimeplot', - '/rowers/workout/1/addtimeplot2', - '/rowers/workout/1/comment', - '/rowers/workout/1/darkskywind', - '/rowers/workout/1/data', - '/rowers/workout/1/edit', - '/rowers/workout/1/editintervals', - '/rowers/workout/1/flexchart', - '/rowers/workout/1/flexchart/spm/hr/None', - '/rowers/workout/1/flexchart/spm/hr/None/scatter', - '/rowers/workout/1/flexchart/spm/hr/None/scatter/', - '/rowers/workout/1/forcecurve', - '/rowers/workout/1/get-testscript', - '/rowers/workout/1/get-thumbnails', - '/rowers/workout/1/histo', - '/rowers/workout/1/image', - '/rowers/workout/1/instroke', - '/rowers/workout/1/interactiveotwplot', - '/rowers/workout/1/map', - '/rowers/workout/1/otwsetpower', + '/rowers/workout/1/adddistanceplot/', + '/rowers/workout/1/adddistanceplot2/', + '/rowers/workout/1/addotwpowerplot/', + '/rowers/workout/1/addpiechart/', + '/rowers/workout/1/addpowerpiechart/', + '/rowers/workout/1/addstatic/', + '/rowers/workout/1/addstatic/3/', + '/rowers/workout/1/addtimeplot/', + '/rowers/workout/1/addtimeplot2/', + '/rowers/workout/1/comment/', + '/rowers/workout/1/darkskywind/', + '/rowers/workout/1/data/', + '/rowers/workout/1/edit/', + '/rowers/workout/1/editintervals/', + '/rowers/workout/1/flexchart/', + '/rowers/workout/1/forcecurve/', + '/rowers/workout/1/get-testscript/', + '/rowers/workout/1/get-thumbnails/', + '/rowers/workout/1/histo/', + '/rowers/workout/1/image/', + '/rowers/workout/1/instroke/', + '/rowers/workout/1/interactiveotwplot/', + '/rowers/workout/1/map/', + '/rowers/workout/1/otwsetpower/', '/rowers/workout/1/recalcsummary/', - '/rowers/workout/1/restore', - '/rowers/workout/1/smoothenpace', - '/rowers/workout/1/split', - '/rowers/workout/1/stats', - '/rowers/workout/1/stream', - '/rowers/workout/1/task', - '/rowers/workout/1/test_strokedata', - '/rowers/workout/1/toggle-ranking', - '/rowers/workout/1/undosmoothenpace', - '/rowers/workout/1/unsubscribe', - '/rowers/workout/1/updatecp', - '/rowers/workout/1/view', - '/rowers/workout/1/wind', - '/rowers/workout/1/workflow', - '/rowers/workout/compare/1/2016-01-01/2016-12-31', + '/rowers/workout/1/restore/', + '/rowers/workout/1/smoothenpace/', + '/rowers/workout/1/split/', + '/rowers/workout/1/stats/', + '/rowers/workout/1/stream/', + '/rowers/workout/1/task/', + '/rowers/workout/1/test_strokedata/', + '/rowers/workout/1/toggle-ranking/', + '/rowers/workout/1/undosmoothenpace/', + '/rowers/workout/1/unsubscribe/', + '/rowers/workout/1/updatecp/', + '/rowers/workout/1/view/', + '/rowers/workout/1/wind/', + '/rowers/workout/1/workflow/', + '/rowers/workout/compare/1/2016-01-01/2016-12-31/', '/rowers/workout/fusion/1/', - '/rowers/workout/fusion/1/2016-01-01/2016-12-31', + '/rowers/workout/fusion/1/2016-01-01/2016-12-31/', '/rowers/workout/upload/', '/rowers/workout/upload/team/', - '/rowers/workouts-join', + '/rowers/workouts-join/', '/rowers/workouts-join-select/', - '/rowers/workouts-join-select/2016-01-01/2016-12-31', + '/rowers/workouts-join-select/2016-01-01/2016-12-31/', ] + # urlstotest = ['/rowers/createplan/user/1/'] + lijst = [] for url in urlstotest: lijst.append( @@ -283,12 +282,20 @@ class URLTests(TestCase): ) @parameterized.expand(lijst) - def test_url_generator(self,url,expected): + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.read_df_sql') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_url_generator(self,url,expected, + mocked_sqlalchemy, + mocked_read_df_sql, + mocked_getsmallrowdata_db): + login = self.c.login(username='john',password='koeinsloot') + self.assertTrue(login) response = self.c.get(url,follow=True) if response.status_code != expected: + print url print response.status_code self.assertEqual(response.status_code, - expected, - msg=url+' response status code not 200') + expected) diff --git a/rowers/tests/testdata/colsfromdb.csv b/rowers/tests/testdata/colsfromdb.csv new file mode 100644 index 00000000..e87e0ee6 --- /dev/null +++ b/rowers/tests/testdata/colsfromdb.csv @@ -0,0 +1,1399 @@ +,distance,fpace,workoutid,hr,pace,ftime,spm,time,workoutstate +3,80,03:30.6,1,127.2857143,210600,01:02.5,18.89142857,62500,4 +4,100,03:25.9,1,132.5142857,205900,01:10.8,18.57714286,70799.99995,4 +5,120,03:00.5,1,135.2571429,180500,01:18.0,21.22571429,78000,4 +6,140,02:32.0,1,140,152000,01:24.1,24.74857143,84099.9999,4 +7,160,02:13.2,1,146.0857143,133200,01:29.4,27.41714286,89400.0001,4 +8,180,02:15.6,1,151.9142857,135600,01:34.8,27.46857143,94799.99995,4 +9,200,02:16.0,1,155.6571429,136000,01:40.3,27.24857143,100300,4 +10,220,02:23.8,1,157.1714286,143800,01:46.0,27.2,106000,4 +11,240,02:15.6,1,158.2571429,135600,01:51.4,27.46285714,111400.0001,4 +12,260,02:24.2,1,159.7428571,144200,01:57.2,27.71428571,117200,4 +13,280,02:11.7,1,161.1714286,131700,02:02.5,27.48285714,122500,4 +14,300,02:22.6,1,161.7428571,142600,02:08.2,27.20857143,128200,4 +15,320,02:18.7,1,162.2571429,138700,02:13.7,26.65142857,133700,4 +16,340,02:28.5,1,162.9142857,148500,02:19.6,26.58285714,139599.9999,4 +17,360,02:32.7,1,164,152700,02:25.8,26.19142857,145800,4 +18,380,02:26.9,1,165.0857143,146900,02:31.6,25.69428571,151599.9999,4 +19,400,02:31.6,1,165.8285714,151600,02:37.7,25.55714286,157700,4 +20,420,02:21.0,1,166.0857143,141000,02:43.3,25.83142857,163300,4 +21,440,02:33.5,1,166,153500,02:49.5,26.14857143,169500,4 +22,460,02:35.1,1,165.9142857,155100,02:55.7,26.13714286,175700,4 +23,480,02:25.3,1,166.2571429,145300,03:01.5,26.7,181500,4 +24,500,02:34.7,1,166.7428571,154700,03:07.7,26.58571429,187700,4 +25,520,02:34.7,1,167,154700,03:13.9,26.28857143,193900.0001,4 +26,540,02:32.0,1,167.2571429,152000,03:19.9,25.54,199900.0001,4 +27,560,02:41.0,1,167.6571429,161000,03:26.4,25.30571429,206400.0001,4 +28,580,02:35.1,1,168.3428571,155100,03:32.6,25.35142857,212599.9999,4 +29,600,02:29.2,1,168.8285714,149200,03:38.6,25.90571429,218599.9999,4 +30,620,02:33.1,1,168.7428571,153100,03:44.7,25.97142857,224700,4 +31,640,02:30.4,1,168.6,150400,03:50.7,25.86571429,230700,4 +32,660,02:29.6,1,168.4,149600,03:56.7,25.81142857,236700,4 +33,680,02:28.1,1,168.3428571,148100,04:02.6,25.72571429,242599.9999,4 +34,700,02:27.7,1,167.8285714,147700,04:08.5,25.31714286,248500,4 +35,720,02:30.0,1,168.2571429,150000,04:14.5,25.11714286,254500,4 +36,740,02:28.1,1,168.7428571,148100,04:20.4,25.24285714,260400.0001,4 +37,760,02:34.3,1,169.0857143,154300,04:26.6,25.32857143,266599.9999,4 +38,780,02:23.0,1,169,143000,04:32.3,25.67428571,272300,4 +39,800,02:26.1,1,169,146100,04:38.2,26.05142857,278200,4 +40,820,02:23.4,1,168.9142857,143400,04:43.9,26.58,283900.0001,4 +41,840,02:31.2,1,169.2571429,151200,04:49.9,26.56,289900.0001,4 +42,860,02:23.0,1,169.7428571,143000,04:55.7,26.81714286,295700,4 +43,880,02:30.0,1,170.0857143,150000,05:01.7,27.07714286,301700,4 +44,900,02:26.5,1,170,146500,05:07.5,27.39428571,307500,4 +45,920,02:20.6,1,170,140600,05:13.1,27.06285714,313099.9999,4 +46,940,02:24.2,1,170,144200,05:18.9,26.73714286,318900.0001,4 +47,960,02:18.3,1,170,138300,05:24.4,26.76,324400.0001,4 +48,980,02:19.9,1,170,139900,05:30.0,26.83428571,330000,4 +49,1000,02:16.7,1,169.9142857,136700,05:35.5,27.01714286,335500,4 +50,1020,02:22.2,1,170.2571429,142200,05:41.2,27.38857143,341200,4 +51,1040,02:23.4,1,170.7428571,143400,05:46.9,27.62857143,346900.0001,4 +52,1060,02:15.6,1,171,135600,05:52.3,27.37142857,352300,4 +53,1080,02:18.3,1,171.2571429,138300,05:57.9,27.40285714,357900.0001,4 +54,1100,02:16.7,1,171.7428571,136700,06:03.3,27.36571429,363300,4 +55,1120,02:24.9,1,172.0857143,144900,06:09.1,27.08285714,369099.9999,4 +56,1140,02:18.7,1,172,138700,06:14.7,26.83142857,374700,4 +57,1160,02:21.8,1,172.0857143,141800,06:20.4,26.92285714,380400.0001,4 +58,1180,02:14.4,1,171.7428571,134400,06:25.7,27.00285714,385700,4 +59,1200,02:18.7,1,171.2571429,138700,06:31.3,27.36857143,391300,4 +60,1220,02:10.5,1,170.9142857,130500,06:36.5,27.42571429,396500,4 +61,1240,02:10.9,1,170.9142857,130900,06:41.7,26.94571429,401700,4 +62,1260,02:15.6,1,171.2571429,135600,06:47.2,26.62857143,407200,4 +63,1280,02:12.4,1,171.7428571,132400,06:52.5,26.80285714,412500,4 +64,1300,02:13.2,1,172.0857143,133200,06:57.8,27.13714286,417800,4 +65,1320,02:09.3,1,172,129300,07:03.0,27.50857143,423000,4 +66,1340,02:06.2,1,171.9142857,126200,07:08.0,27.71142857,428000,4 +67,1360,02:16.0,1,172.2571429,136000,07:13.4,27.73142857,433400.0001,4 +68,1380,02:10.9,1,172.7428571,130900,07:18.7,27.68857143,438700,4 +69,1400,02:20.2,1,173.0857143,140200,07:24.3,27.54857143,444300,4 +70,1420,02:09.3,1,173,129300,07:29.5,27.03428571,449500,4 +71,1440,02:06.2,1,172.9142857,126200,07:34.5,26.83714286,454500,4 +72,1460,02:16.0,1,173.2571429,136000,07:39.9,26.74285714,459900.0001,4 +73,1480,02:10.9,1,173.7428571,130900,07:45.2,26.92571429,465200,4 +74,1500,02:10.5,1,174.0857143,130500,07:50.4,26.86571429,470400.0001,4 +75,1520,02:15.6,1,173.9142857,135600,07:55.8,26.92285714,475800,4 +76,1540,02:16.0,1,174.2571429,136000,08:01.3,26.84857143,481300,4 +77,1560,02:20.2,1,174.7428571,140200,08:06.9,26.97428571,486900.0001,4 +78,1580,02:18.3,1,175.0857143,138300,08:12.4,26.74857143,492400.0001,4 +79,1600,02:25.3,1,175.0857143,145300,08:18.2,26.52857143,498200,4 +80,1620,02:28.1,1,174.7428571,148100,08:24.1,26.40571429,504099.9999,4 +81,1640,02:19.9,1,174.2571429,139900,08:29.7,26.29142857,509700,4 +82,1660,02:12.0,1,173.9142857,132000,08:35.0,26.10857143,515000,4 +83,1680,02:20.2,1,174,140200,08:40.6,26.52285714,520599.9999,4 +84,1700,02:18.3,1,174,138300,08:46.1,26.82285714,526099.9999,4 +85,1720,02:24.9,1,174,144900,08:51.9,26.70571429,531900.0001,4 +86,1740,02:17.9,1,174,137900,08:57.5,26.29142857,537500,4 +87,1760,02:26.9,1,174,146900,09:03.3,26.23142857,543300,4 +88,1780,02:23.4,1,173.9142857,143400,09:09.1,26.46285714,549099.9999,4 +89,1800,02:26.9,1,174.2571429,146900,09:14.9,26.78,554900.0001,4 +90,1820,02:28.1,1,174.7428571,148100,09:20.9,26.66285714,560900.0001,4 +91,1840,02:20.2,1,175.0857143,140200,09:26.5,26.38285714,566500,4 +92,1860,02:15.2,1,175,135200,09:31.9,26.30285714,571900.0001,4 +93,1880,02:20.6,1,174.9142857,140600,09:37.5,26.46,577500,4 +94,1900,02:13.2,1,175.3428571,133200,09:42.8,26.49142857,582800,4 +95,1920,02:19.1,1,175.4,139100,09:48.4,26.88571429,588400.0001,4 +96,1940,02:10.5,1,175.6,130500,09:53.6,27.38285714,593599.9999,4 +97,1960,02:14.8,1,175.6571429,134800,09:59.0,27.04,599000,4 +98,1980,02:16.7,1,176.0857143,136700,10:04.5,26.7,604500,4 +99,2000,02:16.7,1,176,136700,10:09.9,26.51142857,609900.0001,4 +100,2020,02:18.3,1,176,138300,10:15.5,26.86571429,615500,4 +101,2040,02:13.2,1,176,133200,10:20.8,27.09142857,620800,4 +102,2060,02:21.0,1,175.9142857,141000,10:26.4,27.39428571,626400.0001,4 +103,2080,02:18.7,1,176.3428571,138700,10:32.0,27.6,632000,4 +104,2100,02:22.2,1,176.4,142200,10:37.7,27.51714286,637700,4 +105,2120,02:15.6,1,176.6,135600,10:43.1,27.26857143,643099.9999,4 +106,2140,02:19.5,1,176.6571429,139500,10:48.7,27.10571429,648700,4 +107,2160,02:14.0,1,177.0857143,134000,10:54.0,27.24285714,654000,4 +108,2180,02:16.3,1,177,136300,10:59.5,27.28571429,659500,4 +109,2200,02:07.7,1,177,127700,11:04.6,27.29428571,664599.9999,4 +110,2220,02:14.0,1,177,134000,11:10.0,27.52857143,670000,4 +111,2240,02:09.7,1,176.9142857,129700,11:15.1,28.00571429,675099.9999,4 +112,2260,02:15.2,1,177.2571429,135200,11:20.6,28.47142857,680599.9999,4 +113,2280,02:09.7,1,177.7428571,129700,11:25.7,28.77428571,685700,4 +114,2300,02:20.6,1,178.0857143,140600,11:31.4,28.68571429,691400.0001,4 +115,2320,02:20.2,1,177.9142857,140200,11:37.0,28.40571429,697000,4 +116,2340,02:19.9,1,178.2571429,139900,11:42.6,28.06857143,702599.9999,4 +117,2360,02:26.1,1,178.7428571,146100,11:48.4,27.66571429,708400.0001,4 +118,2380,02:15.2,1,179.0857143,135200,11:53.8,27.4,713800,4 +119,2400,02:16.3,1,179,136300,11:59.3,27.36857143,719300,4 +120,2420,02:09.7,1,179,129700,12:04.5,27.51428571,724500,4 +121,2440,02:14.4,1,179,134400,12:09.8,27.82857143,729800,4 +122,2460,02:13.6,1,179,133600,12:15.2,27.65714286,735200,4 +123,2480,02:28.5,1,178.9142857,148500,12:21.1,28.05142857,741099.9999,4 +124,2500,02:25.7,1,179.3428571,145700,12:26.9,28.2,746900.0001,4 +125,2520,02:18.7,1,179.4857143,138700,12:32.5,27.49142857,752500,4 +126,2540,02:30.8,1,179.4285714,150800,12:38.5,26.26285714,758500,4 +127,2560,02:25.7,1,178.5714286,145700,12:44.4,25.65428571,764400.0001,4 +128,2580,02:35.9,1,178.6,155900,12:50.6,25.76,770599.9999,4 +129,2600,02:29.2,1,178.4,149200,12:56.6,25.66857143,776599.9999,4 +130,2620,02:26.5,1,178.3428571,146500,13:02.4,25.59142857,782400.0001,4 +131,2640,02:24.9,1,177.9142857,144900,13:08.2,25.26,788200,4 +132,2660,02:30.0,1,178,150000,13:14.2,25.70571429,794200,4 +133,2680,02:25.3,1,178,145300,13:20.0,26.26571429,800000,4 +134,2700,02:22.6,1,178,142600,13:25.7,26.32,805700,4 +135,2720,02:32.0,1,178,152000,13:31.8,25.91714286,811800,4 +136,2740,02:26.1,1,178,146100,13:37.6,25.96857143,817599.9999,4 +137,2760,02:29.2,1,178,149200,13:43.6,26.02,823599.9999,4 +138,2780,02:23.4,1,178.0857143,143400,13:49.4,26.26571429,829400.0001,4 +139,2800,02:26.5,1,177.6571429,146500,13:55.2,26.35142857,835200,4 +140,2820,02:19.1,1,177.5142857,139100,14:00.8,26.14857143,840800,4 +141,2840,02:25.7,1,177.6571429,145700,14:06.6,26.26857143,846599.9999,4 +142,2860,02:18.7,1,178.0857143,138700,14:12.1,27.1,852099.9999,4 +143,2880,02:19.5,1,178,139500,14:17.7,28.33142857,857700,4 +144,2900,02:28.8,1,178,148800,14:23.7,28.55714286,863700,4 +145,2920,02:32.4,1,178,152400,14:29.8,28.26571429,869800,4 +146,2940,02:21.0,1,178,141000,14:35.4,27.36,875400.0001,4 +147,2960,02:23.0,1,178,143000,14:41.1,27.18571429,881099.9999,4 +148,2980,02:30.8,1,177.9142857,150800,14:47.2,27.18285714,887200,4 +149,3000,02:27.7,1,178.3428571,147700,14:53.1,27.18571429,893099.9999,4 +150,3020,02:25.7,1,178.4,145700,14:58.9,26.68285714,898900.0001,4 +151,3040,02:23.0,1,178.6857143,143000,15:04.6,26.50285714,904599.9999,4 +152,3060,02:23.8,1,178.4,143800,15:10.4,26.31142857,910400.0001,4 +153,3080,02:17.1,1,178.3428571,137100,15:15.9,26.28,915900.0001,4 +154,3100,02:23.8,1,177.9142857,143800,15:21.6,26.49142857,921599.9999,4 +155,3120,02:17.1,1,178,137100,15:27.1,26.78857143,927099.9999,4 +156,3140,02:21.4,1,178,141400,15:32.7,26.59142857,932700,4 +157,3160,02:19.5,1,178,139500,15:38.3,26.32857143,938300,4 +158,3180,02:24.2,1,178,144200,15:44.1,26.28,944099.9999,4 +159,3200,02:17.9,1,177.9142857,137900,15:49.6,26.52857143,949599.9999,4 +160,3220,02:23.0,1,178.3428571,143000,15:55.3,26.70571429,955300,4 +161,3240,02:23.8,1,178.4857143,143800,16:01.1,26.63142857,961099.9999,4 +162,3260,02:31.6,1,178.4285714,151600,16:07.1,26.42857143,967099.9999,4 +163,3280,02:28.8,1,177.6571429,148800,16:13.1,26.63428571,973099.9999,4 +164,3300,02:23.4,1,177.2571429,143400,16:18.8,26.91142857,978800,4 +165,3320,02:29.6,1,176.8285714,149600,16:24.8,27.17428571,984800,4 +166,3340,02:19.9,1,177.2571429,139900,16:30.4,26.91428571,990400.0001,4 +167,3360,02:19.1,1,177.7428571,139100,16:36.0,26.72571429,996000,4 +168,3380,02:20.2,1,178.0857143,140200,16:41.6,26.74857143,1001600,4 +169,3400,02:22.6,1,177.9142857,142600,16:47.3,27.23142857,1007300,4 +170,3420,02:24.5,1,178.3428571,144500,16:53.1,27.3,1013100,4 +171,3440,02:19.5,1,178.4857143,139500,16:58.6,27,1018600,4 +172,3460,02:25.7,1,178.3428571,145700,17:04.5,26.54,1024500,4 +173,3480,02:13.6,1,177.9142857,133600,17:09.8,26.55714286,1029800,4 +174,3500,02:18.3,1,178,138300,17:15.3,26.65714286,1035300,4 +175,3520,02:16.0,1,178,136000,17:20.8,26.85714286,1040800,4 +176,3540,02:16.0,1,178,136000,17:26.2,26.88,1046200,4 +177,3560,02:22.6,1,178,142600,17:31.9,27.08285714,1051900,4 +178,3580,02:21.8,1,177.9142857,141800,17:37.6,27.36285714,1057600,4 +179,3600,02:17.1,1,178.2571429,137100,17:43.1,27.56,1063100,4 +180,3620,02:20.2,1,178.7428571,140200,17:48.7,27.68,1068700,4 +181,3640,02:16.3,1,179.0857143,136300,17:54.1,27.63142857,1074100,4 +182,3660,02:20.6,1,179,140600,17:59.8,27.75142857,1079800,4 +183,3680,02:17.9,1,179,137900,18:05.3,27.38571429,1085300,4 +184,3700,02:21.0,1,179,141000,18:10.9,27.30285714,1090900,4 +185,3720,02:16.3,1,179,136300,18:16.4,27.20571429,1096400,4 +186,3740,02:26.9,1,179,146900,18:22.2,27.24,1102200,4 +187,3760,02:32.4,1,179,152400,18:28.3,26.96571429,1108300,4 +188,3780,02:27.7,1,179,147700,18:34.2,26.4,1114200,4 +189,3800,02:33.5,1,178.9142857,153500,18:40.4,26.11428571,1120400,4 +190,3820,02:22.2,1,179.2571429,142200,18:46.1,26.40857143,1126100,4 +191,3840,02:22.2,1,179.7428571,142200,18:51.8,26.98285714,1131800,4 +192,3860,02:30.4,1,180.1714286,150400,18:57.8,27.06285714,1137800,4 +193,3880,02:22.6,1,179.7428571,142600,19:03.5,26.66571429,1143500,4 +194,3900,02:33.5,1,179.2571429,153500,19:09.6,26.30857143,1149600,4 +195,3920,02:29.2,1,178.8285714,149200,19:15.6,26.57714286,1155600,4 +196,3940,02:24.5,1,179.2571429,144500,19:21.4,27.16571429,1161400,4 +197,3960,02:23.4,1,179.7428571,143400,19:27.1,27.26285714,1167100,4 +198,3980,02:17.5,1,180.0857143,137500,19:32.6,27.38571429,1172600,4 +199,4000,02:18.7,1,179.9142857,138700,19:38.2,28.15714286,1178200,4 +200,4020,02:21.4,1,180.2571429,141400,19:43.8,28.81428571,1183800,4 +201,4040,02:18.7,1,180.7428571,138700,19:49.4,29.13714286,1189400,4 +202,4060,02:23.0,1,181.0857143,143000,19:55.1,28.86857143,1195100,4 +203,4080,02:19.5,1,181,139500,20:00.7,28.32857143,1200700,4 +204,4100,02:12.0,1,181,132000,20:05.9,28.18857143,1205900,4 +205,4120,02:14.4,1,181,134400,20:11.3,28.54571429,1211300,4 +206,4140,02:10.1,1,181,130100,20:16.5,27.95714286,1216500,4 +207,4160,02:17.9,1,181,137900,20:22.0,27.20857143,1222000,4 +208,4180,02:10.9,1,180.9142857,130900,20:27.3,27.03142857,1227300,4 +209,4200,02:16.7,1,182.2,136700,20:32.7,27.56285714,1232700,4 +210,4220,02:15.2,1,177.9714286,135200,20:38.1,27.39428571,1238100,4 +211,4240,02:23.4,1,176.7428571,143400,20:43.9,27.29714286,1243900,4 +212,4260,02:14.0,1,178.2285714,134000,20:49.2,27.35714286,1249200,4 +213,4280,02:20.6,1,182.9428571,140600,20:54.9,27.64,1254900,4 +214,4300,02:16.0,1,182,136000,21:00.3,27.76857143,1260300,4 +215,4320,02:19.1,1,182,139100,21:05.9,27.76571429,1265900,4 +216,4340,02:16.0,1,182,136000,21:11.3,27.46285714,1271300,4 +217,4360,02:18.3,1,182,138300,21:16.8,27.41714286,1276800,4 +218,4380,02:12.0,1,182,132000,21:22.1,27.64285714,1282100,4 +219,4400,02:17.5,1,182,137500,21:27.6,28.02857143,1287600,4 +220,4420,02:12.8,1,182,132800,21:32.9,27.86285714,1292900,4 +221,4440,02:19.5,1,182,139500,21:38.5,27.75428571,1298500,4 +222,4460,02:17.9,1,182,137900,21:44.0,27.56285714,1304000,4 +223,4480,02:13.6,1,182,133600,21:49.4,27.65428571,1309400,4 +224,4500,02:17.1,1,182,137100,21:54.8,27.64571429,1314800,4 +225,4520,02:16.3,1,181.9142857,136300,22:00.3,27.66857143,1320300,4 +226,4540,02:20.2,1,182.2571429,140200,22:05.9,27.82,1300.0001,4 +227,4560,02:14.4,1,182.7428571,134400,22:11.3,27.80857143,1331300,4 +228,4580,02:18.7,1,183.0857143,138700,22:16.8,27.68285714,1336800,4 +229,4600,02:12.4,1,183,132400,22:22.1,27.39428571,1342100,4 +230,4620,02:19.1,1,183,139100,22:27.7,27.61428571,1347700,4 +231,4640,02:11.7,1,183,131700,22:32.9,27.66,1352900,4 +232,4660,02:15.2,1,183,135200,22:38.4,27.98285714,1358400,4 +233,4680,02:10.9,1,183,130900,22:43.6,27.84,1363600,4 +234,4700,02:12.8,1,182.9142857,132800,22:48.9,27.81714286,1368900,4 +235,4720,02:13.6,1,183.2571429,133600,22:54.2,27.81428571,1374200,4 +236,4740,02:13.6,1,183.7428571,133600,22:59.6,27.78571429,1379600,4 +237,4760,02:18.7,1,184.0857143,138700,23:05.1,27.76,1385100,4 +238,4780,02:18.3,1,184,138300,23:10.7,27.95142857,1390700,4 +239,4800,02:07.7,1,184,127700,23:15.8,28.25714286,1395800,4 +240,4820,02:11.3,1,184,131300,23:21.0,28.85142857,1401000,4 +241,4840,02:09.3,1,183.9142857,129300,23:26.2,29.72285714,1406200,4 +242,4860,02:09.3,1,184.2571429,129300,23:31.4,30.53142857,1411400,4 +243,4880,02:03.1,1,184.8285714,123100,23:36.3,31.17142857,1416300,4 +244,4900,02:12.8,1,185.1714286,132800,23:41.6,28.64857143,1421600,4 +245,4920,03:32.5,1,183.5714286,212500,23:50.1,23.55428571,1430100,4 +246,4940,04:06.5,1,181.4571429,246500,24:00.0,17.26571429,1440000,4 +247,4960,04:53.0,1,172.3142857,293000,24:11.7,14.90285714,1451700,4 +249,5000,03:50.9,1,152.7714286,230900,24:33.6,18.27714286,1473600,4 +250,5020,03:38.8,1,150.2857143,218800,24:42.3,20.19142857,1482300,4 +251,5040,02:58.5,1,146.8,178500,24:49.5,18.47142857,1489500,4 +252,5060,03:29.0,1,146.4571429,209000,24:57.8,18.4,1497800,4 +253,5080,02:51.1,1,145.5428571,171100,25:04.7,17.55714286,1504700,4 +254,5100,03:15.7,1,144.6,195700,25:12.5,19.71714286,1512500,4 +255,5120,02:49.2,1,143.3428571,169200,25:19.3,20.26571429,1519300,4 +256,5140,02:45.2,1,143.4857143,165200,25:25.9,21.81714286,1525900,4 +257,5160,03:00.5,1,143.1714286,180500,25:33.1,21.63714286,1533100,4 +258,5180,02:47.2,1,141.9142857,167200,25:39.8,21.34,1539800,4 +259,5200,02:57.7,1,141.1714286,177700,25:46.9,21.07714286,1546900,4 +260,5220,02:53.5,1,141.3428571,173500,25:53.8,21.40285714,1553800,4 +261,5240,03:00.9,1,139.5428571,180900,26:01.1,20.84571429,1561100,4 +263,5280,04:33.1,1,136.4571429,273100,26:25.6,21.45714286,1585600,4 +264,5300,03:21.6,1,135.3428571,201600,26:33.7,20.42857143,1593700,4 +265,5320,03:02.0,1,133.3428571,182000,26:41.0,18.96857143,1601000,4 +266,5340,02:43.7,1,134.0857143,163700,26:47.5,20.21428571,1607500,4 +267,5360,02:39.0,1,135.5714286,159000,26:53.9,20.88857143,1613900,4 +268,5380,02:36.3,1,136.0857143,156300,27:00.1,20.68285714,1620100,4 +269,5400,02:37.8,1,136.2571429,157800,27:06.4,20.77142857,1626400,4 +270,5420,02:33.1,1,136.6571429,153100,27:12.6,20.93714286,1639.9999,4 +271,5440,02:36.7,1,137.2571429,156700,27:18.8,20.66,1638800,4 +272,5460,02:44.9,1,138,164900,27:25.4,20.41714286,1645400,4 +273,5480,02:42.1,1,138.7428571,162100,27:31.9,20.78,1651900,4 +274,5500,02:43.7,1,139.1714286,163700,27:38.5,21.37714286,1658500,4 +275,5520,02:36.7,1,140.1714286,156700,27:44.7,20.03142857,1664700,4 +276,5540,02:49.5,1,141.8285714,169500,27:51.5,19.53142857,1671500,4 +277,5560,02:52.7,1,142.9142857,172700,27:58.4,19.91142857,1678400,4 +278,5580,02:44.1,1,143.0857143,164100,28:05.0,21.20571429,1685000,4 +279,5600,02:44.5,1,143,164500,28:11.5,20.60857143,1691500,4 +280,5620,02:53.1,1,143.0857143,173100,28:18.5,20.82,1698500,4 +281,5640,02:40.6,1,142.8285714,160600,28:24.9,20.61714286,1704900,4 +282,5660,03:00.1,1,142.0857143,180100,28:32.1,19.02285714,1712100,4 +283,5680,03:15.3,1,141,195300,28:39.9,17.61714286,1719900,4 +284,5700,03:25.5,1,140.0857143,205500,28:48.1,18.15714286,1728100,4 +285,5720,03:13.0,1,138.7428571,193000,28:55.8,19.87142857,1735800,4 +286,5740,03:05.2,1,137.2571429,185200,29:03.2,19.95142857,1743200,4 +287,5760,02:55.0,1,135.8285714,175000,29:10.2,19.34,1750200,4 +288,5780,03:13.8,1,135.1714286,193800,29:18.0,19.10857143,1758000,4 +289,5800,03:05.2,1,135,185200,29:25.4,19.75428571,1765400,4 +290,5820,02:47.6,1,134.7428571,167600,29:32.1,19.80857143,1772100,4 +291,5840,02:57.7,1,134.1714286,177700,29:39.2,19.02285714,1779200,4 +292,5860,03:04.8,1,134.2571429,184800,29:46.6,17.70571429,1786600,4 +293,5880,03:01.7,1,134.4857143,181700,29:53.9,16.57714286,1793900,4 +294,5900,03:25.5,1,134.1714286,205500,30:02.1,17.24857143,1802100,4 +295,5920,02:58.9,1,134.4285714,178900,30:09.2,17.98857143,1809200,4 +296,5940,02:35.1,1,135.4857143,155100,30:15.5,19.07714286,1815500,4 +297,5960,02:29.6,1,136.0857143,149600,30:21.4,17.96285714,1821400,4 +298,5980,02:36.7,1,136.2571429,156700,30:27.7,18.49714286,1827700,4 +299,6000,03:03.6,1,136.7428571,183600,30:35.0,15.02857143,1835000,4 +300,6020,03:22.7,1,137.1714286,202700,30:43.2,13.74285714,1843200,4 +301,6040,03:20.4,1,136.7428571,200400,30:51.2,15.00571429,1851200,4 +302,6060,02:53.8,1,136.1714286,173800,30:58.1,19.22285714,1858100,4 +303,6080,02:38.2,1,136,158200,31:04.5,20.82,1864500,4 +304,6100,02:30.0,1,137.1714286,150000,31:10.5,20.95428571,1870500,4 +305,6120,02:29.6,1,138.6571429,149600,31:16.4,21.24857143,1876400,4 +306,6140,02:28.5,1,140.3428571,148500,31:22.4,21.18857143,1882400,4 +307,6160,02:27.3,1,141.9142857,147300,31:28.3,21.90857143,1888300,4 +308,6180,02:41.3,1,142.5714286,161300,31:34.7,17.56571429,1894700,4 +309,6200,03:59.9,1,142.6,239900,31:44.3,15.94,1904300,4 +310,6220,03:55.2,1,142.7428571,235200,31:53.7,17.42285714,1913700,4 +311,6240,02:41.7,1,142.8285714,161700,32:00.2,22.17142857,1920200,4 +312,6260,02:26.9,1,143.6285714,146900,32:06.1,22.28571429,1926100,4 +313,6280,03:09.1,1,138.0571429,189100,32:13.6,19.39714286,1933600,4 +315,6320,04:54.2,1,122.2285714,294200,32:51.5,14.22,1971500,4 +316,6340,04:40.1,1,123.2571429,280100,33:02.7,16.01428571,1982700,4 +317,6360,03:45.4,1,124.2285714,225400,33:11.7,16.48,1991700,4 +318,6380,03:25.9,1,125.8571429,205900,33:19.9,16.66571429,1999900,4 +319,6400,03:41.5,1,127.6571429,221500,33:28.8,16.66285714,2008800,4 +320,6420,03:34.5,1,128.4,214500,33:37.3,17.29142857,2017300,4 +321,6440,03:30.2,1,127.6857143,210200,33:45.8,16.38285714,2025800,4 +322,6460,03:04.8,1,128,184800,33:53.1,16.24,2033100,4 +323,6480,02:45.2,1,130,165200,33:59.8,17.13142857,2039800,4 +324,6500,04:58.8,1,130.7428571,298800,34:11.7,17.76857143,2051700,4 +325,6520,04:37.0,1,128.6571429,277000,34:22.8,17.44857143,2062800,4 +326,6540,04:17.0,1,125.6,257000,34:33.1,15.90571429,2073100,4 +327,6560,03:42.3,1,123.6571429,222300,34:42.0,17.48,2082000,4 +328,6580,03:22.4,1,124.4285714,202400,34:50.0,19.24285714,2090000,4 +329,6600,02:48.4,1,126.8285714,168400,34:56.8,20.73428571,2096800,4 +330,6620,02:51.5,1,129.7428571,171500,35:03.6,21.06,2103600,4 +331,6640,02:35.9,1,132.6857143,155900,35:09.9,24.12,2109900,4 +332,6660,02:42.5,1,133.7142857,162500,35:16.4,15.77428571,2116400,4 +334,6700,04:07.3,1,134.2285714,247300,35:34.6,11.19142857,2134600,4 +335,6720,03:03.6,1,134.0857143,183600,35:42.0,20.16,2142000,4 +336,6740,03:04.8,1,131.8285714,184800,35:49.4,19.37714286,2149400,4 +337,6760,03:04.8,1,130.7714286,184800,35:56.8,18.00571429,2156800,4 +338,6780,03:08.7,1,130.0571429,188700,36:04.3,17.85428571,2164300,4 +339,6800,03:06.0,1,129.5142857,186000,36:11.7,18.40571429,2171700,4 +340,6820,03:01.7,1,129.0857143,181700,36:19.0,19.38285714,2179000,4 +341,6840,02:51.5,1,129.7428571,171500,36:25.9,18.68571429,2185900,4 +342,6860,02:54.2,1,130.1714286,174200,36:32.8,18.47142857,2192800,4 +343,6880,02:55.0,1,129.7428571,175000,36:39.8,18.82285714,2199800,4 +344,6900,03:43.8,1,129.1714286,223800,36:48.8,17.32285714,2208800,4 +345,6920,03:35.6,1,129.3428571,215600,36:57.4,16.45428571,2217400,4 +346,6940,03:09.9,1,129.3142857,189900,37:05.0,16.78571429,2225000,4 +347,6960,03:14.2,1,128.2571429,194200,37:12.8,18.57428571,2232800,4 +348,6980,03:18.8,1,127.3428571,198800,37:20.7,18.82,2240700,4 +349,7000,03:27.4,1,127.7428571,207400,37:29.0,18.33428571,2249000,4 +350,7020,03:06.0,1,127.9142857,186000,37:36.5,16.97142857,2256500,4 +351,7040,03:07.5,1,127,187500,37:44.0,17.31428571,2264000,4 +352,7060,03:05.2,1,126.0857143,185200,37:51.4,15.52857143,2271400,4 +353,7080,03:42.7,1,126.1714286,222700,38:00.3,15.28285714,2280300,4 +354,7100,03:29.4,1,126.8285714,209400,38:08.6,16.79714286,2288600,4 +355,7120,03:10.2,1,126.5714286,190200,38:16.3,18.70571429,2296300,4 +356,7140,03:19.2,1,126.9428571,199200,38:24.2,17.78285714,2304200,4 +357,7160,02:56.2,1,128.4857143,176200,38:31.3,18.33142857,2311300,4 +358,7180,02:53.8,1,129.7428571,173800,38:38.2,20.31714286,2318200,4 +359,7200,02:55.8,1,129.1714286,175800,38:45.3,20.25714286,2325300,4 +360,7220,02:43.7,1,129.3428571,163700,38:51.8,20.09714286,2331800,4 +361,7240,02:42.9,1,130.6571429,162900,38:58.3,20.16571429,2338300,4 +362,7260,02:39.4,1,132.1714286,159400,39:04.7,20.67142857,2344700,4 +363,7280,02:35.9,1,132.5714286,155900,39:10.9,21.14857143,2350900,4 +364,7300,02:41.3,1,133.6857143,161300,39:17.4,20.89142857,2357400,4 +365,7320,02:35.9,1,135.6571429,155900,39:23.6,20.22285714,2363600,4 +366,7340,02:37.8,1,137.9142857,157800,39:29.9,20.23428571,2369900,4 +367,7360,02:37.0,1,139.0857143,157000,39:36.2,20.97142857,2376200,4 +368,7380,02:36.7,1,140,156700,39:42.5,20.93714286,2382500,4 +369,7400,02:35.1,1,141.1714286,155100,39:48.7,20.72571429,2388700,4 +370,7420,02:43.3,1,141.5714286,163300,39:55.2,19.34571429,2395200,4 +371,7440,02:59.3,1,141.3428571,179300,40:02.4,19.09714286,2402400,4 +372,7460,03:03.6,1,140.9142857,183600,40:09.7,19.59142857,2409700,4 +373,7480,02:40.6,1,140.9142857,160600,40:16.1,21.23142857,2416100,4 +374,7500,02:48.8,1,141.2571429,168800,40:22.9,21.16571429,2422900,4 +375,7520,02:39.0,1,141.8285714,159000,40:29.3,21.35428571,2429300,4 +376,7540,02:33.9,1,141.9142857,153900,40:35.4,21.19142857,2435400,4 +377,7560,02:47.6,1,141.0857143,167600,40:42.1,20.27428571,2442100,4 +378,7580,03:02.0,1,140.1714286,182000,40:49.4,19.01714286,2449400,4 +379,7600,03:09.5,1,138.4857143,189500,40:57.0,16.88,2457000,4 +380,7620,03:34.9,1,136.6,214900,41:05.6,14.68,2465600,4 +381,7640,03:27.4,1,134.5714286,207400,41:13.9,15.78285714,2473900,4 +382,7660,03:04.8,1,133.3428571,184800,41:21.3,18.14857143,2481300,4 +383,7680,03:11.8,1,131.8285714,191800,41:28.9,18.93428571,2488900,4 +384,7700,03:24.3,1,129.8285714,204300,41:37.1,20.09714286,2497100,4 +385,7720,03:25.9,1,127.2571429,205900,41:45.3,22.05428571,2505300,4 +386,7740,03:39.2,1,124.7428571,219200,41:54.1,20.40571429,2514100,4 +387,7760,04:09.6,1,123.3428571,249600,42:04.1,17.76,2524100,4 +388,7780,03:13.8,1,122.8285714,193800,42:11.8,17.50857143,2531800,4 +389,7800,03:03.2,1,122.7428571,183200,42:19.2,18.88571429,2539200,4 +390,7820,02:44.5,1,123.6857143,164500,42:25.7,19.37142857,2545700,4 +391,7840,02:35.5,1,125.5714286,155500,42:32.0,19.36,2552000,4 +392,7860,02:46.4,1,126.6571429,166400,42:38.6,18.94571429,2558600,4 +393,7880,02:53.1,1,126.5142857,173100,42:45.5,18.05714286,2565500,4 +394,7900,02:58.5,1,127,178500,42:52.7,18.42571429,2572700,4 +395,7920,02:50.7,1,127.5714286,170700,42:59.5,19.13428571,2579500,4 +396,7940,03:16.1,1,127.4285714,196100,43:07.3,18.88857143,2587300,4 +397,7960,03:12.6,1,126.6571429,192600,43:15.0,17.72285714,2595000,4 +398,7980,03:09.9,1,127.4571429,189900,43:22.6,17.56571429,2602600,4 +399,8000,03:21.2,1,120.9428571,201200,43:30.7,17.82571429,2610700,4 +400,8020,03:07.1,1,119.8,187100,43:38.2,17.67142857,2618200,4 +401,8040,02:55.0,1,122.6,175000,43:45.2,17.52571429,2625200,4 +402,8060,03:00.5,1,128.0285714,180500,43:52.4,19.36571429,2632400,4 +404,8100,03:02.8,1,125.4,182800,44:11.9,19.29714286,2651900,4 +405,8120,02:57.0,1,125,177000,44:19.0,18.31428571,2659000,4 +406,8140,03:05.6,1,124.5142857,185600,44:26.4,18.44285714,2666400,4 +407,8160,03:12.6,1,124.5714286,192600,44:34.1,18.39142857,2674100,4 +408,8180,03:02.0,1,123.8285714,182000,44:41.4,15.79714286,2681400,4 +409,8200,03:57.5,1,122.3428571,237500,44:50.9,15.76,2690900,4 +410,8220,03:24.3,1,122.0857143,204300,44:59.1,17.60571429,2699100,4 +411,8240,03:09.9,1,122.5714286,189900,45:06.7,19.90857143,2706700,4 +412,8260,02:55.4,1,123.3428571,175400,45:13.7,19.60857143,2713700,4 +413,8280,02:48.8,1,125.1714286,168800,45:20.5,20.53428571,2720500,4 +414,8300,02:45.6,1,127.5714286,165600,45:27.1,21.03714286,2727100,4 +415,8320,02:48.8,1,129.0857143,168800,45:33.8,20.94,2733800,4 +416,8340,02:45.2,1,130.3428571,165200,45:40.4,20.74285714,2740400,4 +417,8360,02:44.5,1,131.4857143,164500,45:47.0,21.22285714,2747000,4 +418,8380,02:44.1,1,132.4285714,164100,45:53.6,20.41428571,2753600,4 +419,8400,02:46.8,1,132.5714286,166800,46:00.3,20.10857143,2760300,4 +420,8420,02:39.4,1,133.6857143,159400,46:06.6,20.84,2766600,4 +421,8440,02:49.9,1,134.2285714,169900,46:13.4,19.14857143,2773400,4 +422,8460,03:00.9,1,134.4285714,180900,46:20.7,18.04285714,2780700,4 +423,8480,02:56.6,1,134.0857143,176600,46:27.7,17.96285714,2787700,4 +424,8500,02:55.0,1,133.4857143,175000,46:34.7,19.39428571,2794700,4 +425,8520,02:56.2,1,132.5142857,176200,46:41.8,19.5,2801800,4 +426,8540,02:53.8,1,131.7428571,173800,46:48.7,19.76285714,2808700,4 +427,8560,02:46.4,1,132.4285714,166400,46:55.4,19.37714286,2815400,4 +428,8580,02:42.5,1,132.3142857,162500,47:01.9,19.22571429,2821900,4 +429,8600,02:57.0,1,131.3428571,177000,47:09.0,19.37428571,2829000,4 +430,8620,03:09.9,1,130,189900,47:16.5,19.66571429,2836500,4 +431,8640,02:49.9,1,130.3428571,169900,47:23.3,18.85714286,2843300,4 +432,8660,02:46.4,1,130.4,166400,47:30.0,19.05714286,2850000,4 +433,8680,02:50.3,1,129.0857143,170300,47:36.8,17.12285714,2856800,4 +434,8700,02:58.1,1,127.4285714,178100,47:43.9,17.06571429,2863900,4 +435,8720,03:07.9,1,126.4857143,187900,47:51.5,17.68,2871500,4 +436,8740,02:58.1,1,126.4285714,178100,47:58.6,20.31428571,2878600,4 +437,8760,02:55.4,1,127,175400,48:05.6,18.96857143,2885600,4 +438,8780,03:12.6,1,127.4857143,192600,48:13.3,18.59714286,2893300,4 +439,8800,03:05.2,1,127.2571429,185200,48:20.7,19.44,2900700,4 +440,8820,02:58.9,1,128.8571429,178900,48:27.9,21.48857143,2907900,4 +441,8840,02:45.6,1,130.6285714,165600,48:34.5,18.81714286,2914500,4 +442,8860,03:02.4,1,130.7714286,182400,48:41.8,16.06,2921800,4 +443,8880,03:28.6,1,128.5714286,208600,48:50.1,15.00857143,2930100,4 +444,8900,03:20.8,1,127.4285714,200800,48:58.2,17.34571429,2938200,4 +445,8920,02:52.7,1,126.8285714,172700,49:05.1,18.52571429,2945100,4 +446,8940,02:50.3,1,127,170300,49:11.9,19.74857143,2951900,4 +447,8960,02:54.6,1,127,174600,49:18.9,20.26571429,2958900,4 +448,8980,02:47.6,1,126.8285714,167600,49:25.6,20.20571429,2965600,4 +449,9000,02:43.7,1,127.2571429,163700,49:32.1,19.37142857,2972100,4 +450,9020,02:46.0,1,129.0857143,166000,49:38.8,19.47142857,2978800,4 +451,9040,02:57.0,1,131.8285714,177000,49:45.8,20.43714286,2985800,4 +452,9060,02:35.5,1,133.8285714,155500,49:52.1,20.92857143,2992100,4 +453,9080,02:28.8,1,135.3428571,148800,49:58.0,20.89714286,2998000,4 +454,9100,02:30.4,1,136.7428571,150400,50:04.0,21.40285714,3004000,4 +455,9120,02:26.5,1,138.0857143,146500,50:09.9,22.31142857,3009900,4 +456,9140,02:26.9,1,138.9142857,146900,50:15.8,22.7,3015800,4 +457,9160,02:36.7,1,140.2571429,156700,50:22.0,22.59428571,3022000,4 +458,9180,02:30.0,1,141.7428571,150000,50:28.0,22.43142857,3028000,4 +459,9200,02:29.2,1,143.0857143,149200,50:34.0,22.20857143,3034000,4 +460,9220,02:27.3,1,144.2571429,147300,50:39.9,21.71142857,3039900,4 +461,9240,02:35.5,1,146.0285714,155500,50:46.1,23.12857143,3046100,4 +462,9260,03:08.3,1,138.9714286,188300,50:53.6,22.98857143,3053600,4 +463,9280,04:01.4,1,126.3428571,241400,51:03.3,13.11142857,3063300,4 +465,9320,03:36.4,1,117.5714286,216400,51:25.0,11.70571429,3085000,4 +466,9340,03:51.3,1,119.9142857,231300,51:34.3,19.73714286,3094300,4 +467,9360,03:22.0,1,122.0857143,202000,51:42.3,18.46857143,3102300,4 +468,9380,03:16.1,1,125.7142857,196100,51:50.2,15.80285714,3110200,4 +469,9400,03:25.9,1,118.5714286,205900,51:58.4,16.25428571,3118400,4 +471,9440,03:14.2,1,110.0285714,194200,52:23.5,20.32285714,3143500,4 +472,9460,02:58.9,1,118.1428571,178900,52:30.7,19.28285714,3150700,4 +473,9480,02:50.3,1,122.3142857,170300,52:37.5,17.68,3157500,4 +474,9500,04:10.0,1,127.4571429,250000,52:47.5,17.38,3167500,4 +475,9520,03:45.0,1,126.8857143,225000,52:56.5,16.28,3176500,4 +479,80,03:30.6,2,127.2857143,210600,01:02.5,18.89142857,62500,4 +480,100,03:25.9,2,132.5142857,205900,01:10.8,18.57714286,70799.99995,4 +481,120,03:00.5,2,135.2571429,180500,01:18.0,21.22571429,78000,4 +482,140,02:32.0,2,140,152000,01:24.1,24.74857143,84099.9999,4 +483,160,02:13.2,2,146.0857143,133200,01:29.4,27.41714286,89400.0001,4 +484,180,02:15.6,2,151.9142857,135600,01:34.8,27.46857143,94799.99995,4 +485,200,02:16.0,2,155.6571429,136000,01:40.3,27.24857143,100300,4 +486,220,02:23.8,2,157.1714286,143800,01:46.0,27.2,106000,4 +487,240,02:15.6,2,158.2571429,135600,01:51.4,27.46285714,111400.0001,4 +488,260,02:24.2,2,159.7428571,144200,01:57.2,27.71428571,117200,4 +489,280,02:11.7,2,161.1714286,131700,02:02.5,27.48285714,122500,4 +490,300,02:22.6,2,161.7428571,142600,02:08.2,27.20857143,128200,4 +491,320,02:18.7,2,162.2571429,138700,02:13.7,26.65142857,133700,4 +492,340,02:28.5,2,162.9142857,148500,02:19.6,26.58285714,139599.9999,4 +493,360,02:32.7,2,164,152700,02:25.8,26.19142857,145800,4 +494,380,02:26.9,2,165.0857143,146900,02:31.6,25.69428571,151599.9999,4 +495,400,02:31.6,2,165.8285714,151600,02:37.7,25.55714286,157700,4 +496,420,02:21.0,2,166.0857143,141000,02:43.3,25.83142857,163300,4 +497,440,02:33.5,2,166,153500,02:49.5,26.14857143,169500,4 +498,460,02:35.1,2,165.9142857,155100,02:55.7,26.13714286,175700,4 +499,480,02:25.3,2,166.2571429,145300,03:01.5,26.7,181500,4 +500,500,02:34.7,2,166.7428571,154700,03:07.7,26.58571429,187700,4 +501,520,02:34.7,2,167,154700,03:13.9,26.28857143,193900.0001,4 +502,540,02:32.0,2,167.2571429,152000,03:19.9,25.54,199900.0001,4 +503,560,02:41.0,2,167.6571429,161000,03:26.4,25.30571429,206400.0001,4 +504,580,02:35.1,2,168.3428571,155100,03:32.6,25.35142857,212599.9999,4 +505,600,02:29.2,2,168.8285714,149200,03:38.6,25.90571429,218599.9999,4 +506,620,02:33.1,2,168.7428571,153100,03:44.7,25.97142857,224700,4 +507,640,02:30.4,2,168.6,150400,03:50.7,25.86571429,230700,4 +508,660,02:29.6,2,168.4,149600,03:56.7,25.81142857,236700,4 +509,680,02:28.1,2,168.3428571,148100,04:02.6,25.72571429,242599.9999,4 +510,700,02:27.7,2,167.8285714,147700,04:08.5,25.31714286,248500,4 +511,720,02:30.0,2,168.2571429,150000,04:14.5,25.11714286,254500,4 +512,740,02:28.1,2,168.7428571,148100,04:20.4,25.24285714,260400.0001,4 +513,760,02:34.3,2,169.0857143,154300,04:26.6,25.32857143,266599.9999,4 +514,780,02:23.0,2,169,143000,04:32.3,25.67428571,272300,4 +515,800,02:26.1,2,169,146100,04:38.2,26.05142857,278200,4 +516,820,02:23.4,2,168.9142857,143400,04:43.9,26.58,283900.0001,4 +517,840,02:31.2,2,169.2571429,151200,04:49.9,26.56,289900.0001,4 +518,860,02:23.0,2,169.7428571,143000,04:55.7,26.81714286,295700,4 +519,880,02:30.0,2,170.0857143,150000,05:01.7,27.07714286,301700,4 +520,900,02:26.5,2,170,146500,05:07.5,27.39428571,307500,4 +521,920,02:20.6,2,170,140600,05:13.1,27.06285714,313099.9999,4 +522,940,02:24.2,2,170,144200,05:18.9,26.73714286,318900.0001,4 +523,960,02:18.3,2,170,138300,05:24.4,26.76,324400.0001,4 +524,980,02:19.9,2,170,139900,05:30.0,26.83428571,330000,4 +525,1000,02:16.7,2,169.9142857,136700,05:35.5,27.01714286,335500,4 +526,1020,02:22.2,2,170.2571429,142200,05:41.2,27.38857143,341200,4 +527,1040,02:23.4,2,170.7428571,143400,05:46.9,27.62857143,346900.0001,4 +528,1060,02:15.6,2,171,135600,05:52.3,27.37142857,352300,4 +529,1080,02:18.3,2,171.2571429,138300,05:57.9,27.40285714,357900.0001,4 +530,1100,02:16.7,2,171.7428571,136700,06:03.3,27.36571429,363300,4 +531,1120,02:24.9,2,172.0857143,144900,06:09.1,27.08285714,369099.9999,4 +532,1140,02:18.7,2,172,138700,06:14.7,26.83142857,374700,4 +533,1160,02:21.8,2,172.0857143,141800,06:20.4,26.92285714,380400.0001,4 +534,1180,02:14.4,2,171.7428571,134400,06:25.7,27.00285714,385700,4 +535,1200,02:18.7,2,171.2571429,138700,06:31.3,27.36857143,391300,4 +536,1220,02:10.5,2,170.9142857,130500,06:36.5,27.42571429,396500,4 +537,1240,02:10.9,2,170.9142857,130900,06:41.7,26.94571429,401700,4 +538,1260,02:15.6,2,171.2571429,135600,06:47.2,26.62857143,407200,4 +539,1280,02:12.4,2,171.7428571,132400,06:52.5,26.80285714,412500,4 +540,1300,02:13.2,2,172.0857143,133200,06:57.8,27.13714286,417800,4 +541,1320,02:09.3,2,172,129300,07:03.0,27.50857143,423000,4 +542,1340,02:06.2,2,171.9142857,126200,07:08.0,27.71142857,428000,4 +543,1360,02:16.0,2,172.2571429,136000,07:13.4,27.73142857,433400.0001,4 +544,1380,02:10.9,2,172.7428571,130900,07:18.7,27.68857143,438700,4 +545,1400,02:20.2,2,173.0857143,140200,07:24.3,27.54857143,444300,4 +546,1420,02:09.3,2,173,129300,07:29.5,27.03428571,449500,4 +547,1440,02:06.2,2,172.9142857,126200,07:34.5,26.83714286,454500,4 +548,1460,02:16.0,2,173.2571429,136000,07:39.9,26.74285714,459900.0001,4 +549,1480,02:10.9,2,173.7428571,130900,07:45.2,26.92571429,465200,4 +550,1500,02:10.5,2,174.0857143,130500,07:50.4,26.86571429,470400.0001,4 +551,1520,02:15.6,2,173.9142857,135600,07:55.8,26.92285714,475800,4 +552,1540,02:16.0,2,174.2571429,136000,08:01.3,26.84857143,481300,4 +553,1560,02:20.2,2,174.7428571,140200,08:06.9,26.97428571,486900.0001,4 +554,1580,02:18.3,2,175.0857143,138300,08:12.4,26.74857143,492400.0001,4 +555,1600,02:25.3,2,175.0857143,145300,08:18.2,26.52857143,498200,4 +556,1620,02:28.1,2,174.7428571,148100,08:24.1,26.40571429,504099.9999,4 +557,1640,02:19.9,2,174.2571429,139900,08:29.7,26.29142857,509700,4 +558,1660,02:12.0,2,173.9142857,132000,08:35.0,26.10857143,515000,4 +559,1680,02:20.2,2,174,140200,08:40.6,26.52285714,520599.9999,4 +560,1700,02:18.3,2,174,138300,08:46.1,26.82285714,526099.9999,4 +561,1720,02:24.9,2,174,144900,08:51.9,26.70571429,531900.0001,4 +562,1740,02:17.9,2,174,137900,08:57.5,26.29142857,537500,4 +563,1760,02:26.9,2,174,146900,09:03.3,26.23142857,543300,4 +564,1780,02:23.4,2,173.9142857,143400,09:09.1,26.46285714,549099.9999,4 +565,1800,02:26.9,2,174.2571429,146900,09:14.9,26.78,554900.0001,4 +566,1820,02:28.1,2,174.7428571,148100,09:20.9,26.66285714,560900.0001,4 +567,1840,02:20.2,2,175.0857143,140200,09:26.5,26.38285714,566500,4 +568,1860,02:15.2,2,175,135200,09:31.9,26.30285714,571900.0001,4 +569,1880,02:20.6,2,174.9142857,140600,09:37.5,26.46,577500,4 +570,1900,02:13.2,2,175.3428571,133200,09:42.8,26.49142857,582800,4 +571,1920,02:19.1,2,175.4,139100,09:48.4,26.88571429,588400.0001,4 +572,1940,02:10.5,2,175.6,130500,09:53.6,27.38285714,593599.9999,4 +573,1960,02:14.8,2,175.6571429,134800,09:59.0,27.04,599000,4 +574,1980,02:16.7,2,176.0857143,136700,10:04.5,26.7,604500,4 +575,2000,02:16.7,2,176,136700,10:09.9,26.51142857,609900.0001,4 +576,2020,02:18.3,2,176,138300,10:15.5,26.86571429,615500,4 +577,2040,02:13.2,2,176,133200,10:20.8,27.09142857,620800,4 +578,2060,02:21.0,2,175.9142857,141000,10:26.4,27.39428571,626400.0001,4 +579,2080,02:18.7,2,176.3428571,138700,10:32.0,27.6,632000,4 +580,2100,02:22.2,2,176.4,142200,10:37.7,27.51714286,637700,4 +581,2120,02:15.6,2,176.6,135600,10:43.1,27.26857143,643099.9999,4 +582,2140,02:19.5,2,176.6571429,139500,10:48.7,27.10571429,648700,4 +583,2160,02:14.0,2,177.0857143,134000,10:54.0,27.24285714,654000,4 +584,2180,02:16.3,2,177,136300,10:59.5,27.28571429,659500,4 +585,2200,02:07.7,2,177,127700,11:04.6,27.29428571,664599.9999,4 +586,2220,02:14.0,2,177,134000,11:10.0,27.52857143,670000,4 +587,2240,02:09.7,2,176.9142857,129700,11:15.1,28.00571429,675099.9999,4 +588,2260,02:15.2,2,177.2571429,135200,11:20.6,28.47142857,680599.9999,4 +589,2280,02:09.7,2,177.7428571,129700,11:25.7,28.77428571,685700,4 +590,2300,02:20.6,2,178.0857143,140600,11:31.4,28.68571429,691400.0001,4 +591,2320,02:20.2,2,177.9142857,140200,11:37.0,28.40571429,697000,4 +592,2340,02:19.9,2,178.2571429,139900,11:42.6,28.06857143,702599.9999,4 +593,2360,02:26.1,2,178.7428571,146100,11:48.4,27.66571429,708400.0001,4 +594,2380,02:15.2,2,179.0857143,135200,11:53.8,27.4,713800,4 +595,2400,02:16.3,2,179,136300,11:59.3,27.36857143,719300,4 +596,2420,02:09.7,2,179,129700,12:04.5,27.51428571,724500,4 +597,2440,02:14.4,2,179,134400,12:09.8,27.82857143,729800,4 +598,2460,02:13.6,2,179,133600,12:15.2,27.65714286,735200,4 +599,2480,02:28.5,2,178.9142857,148500,12:21.1,28.05142857,741099.9999,4 +600,2500,02:25.7,2,179.3428571,145700,12:26.9,28.2,746900.0001,4 +601,2520,02:18.7,2,179.4857143,138700,12:32.5,27.49142857,752500,4 +602,2540,02:30.8,2,179.4285714,150800,12:38.5,26.26285714,758500,4 +603,2560,02:25.7,2,178.5714286,145700,12:44.4,25.65428571,764400.0001,4 +604,2580,02:35.9,2,178.6,155900,12:50.6,25.76,770599.9999,4 +605,2600,02:29.2,2,178.4,149200,12:56.6,25.66857143,776599.9999,4 +606,2620,02:26.5,2,178.3428571,146500,13:02.4,25.59142857,782400.0001,4 +607,2640,02:24.9,2,177.9142857,144900,13:08.2,25.26,788200,4 +608,2660,02:30.0,2,178,150000,13:14.2,25.70571429,794200,4 +609,2680,02:25.3,2,178,145300,13:20.0,26.26571429,800000,4 +610,2700,02:22.6,2,178,142600,13:25.7,26.32,805700,4 +611,2720,02:32.0,2,178,152000,13:31.8,25.91714286,811800,4 +612,2740,02:26.1,2,178,146100,13:37.6,25.96857143,817599.9999,4 +613,2760,02:29.2,2,178,149200,13:43.6,26.02,823599.9999,4 +614,2780,02:23.4,2,178.0857143,143400,13:49.4,26.26571429,829400.0001,4 +615,2800,02:26.5,2,177.6571429,146500,13:55.2,26.35142857,835200,4 +616,2820,02:19.1,2,177.5142857,139100,14:00.8,26.14857143,840800,4 +617,2840,02:25.7,2,177.6571429,145700,14:06.6,26.26857143,846599.9999,4 +618,2860,02:18.7,2,178.0857143,138700,14:12.1,27.1,852099.9999,4 +619,2880,02:19.5,2,178,139500,14:17.7,28.33142857,857700,4 +620,2900,02:28.8,2,178,148800,14:23.7,28.55714286,863700,4 +621,2920,02:32.4,2,178,152400,14:29.8,28.26571429,869800,4 +622,2940,02:21.0,2,178,141000,14:35.4,27.36,875400.0001,4 +623,2960,02:23.0,2,178,143000,14:41.1,27.18571429,881099.9999,4 +624,2980,02:30.8,2,177.9142857,150800,14:47.2,27.18285714,887200,4 +625,3000,02:27.7,2,178.3428571,147700,14:53.1,27.18571429,893099.9999,4 +626,3020,02:25.7,2,178.4,145700,14:58.9,26.68285714,898900.0001,4 +627,3040,02:23.0,2,178.6857143,143000,15:04.6,26.50285714,904599.9999,4 +628,3060,02:23.8,2,178.4,143800,15:10.4,26.31142857,910400.0001,4 +629,3080,02:17.1,2,178.3428571,137100,15:15.9,26.28,915900.0001,4 +630,3100,02:23.8,2,177.9142857,143800,15:21.6,26.49142857,921599.9999,4 +631,3120,02:17.1,2,178,137100,15:27.1,26.78857143,927099.9999,4 +632,3140,02:21.4,2,178,141400,15:32.7,26.59142857,932700,4 +633,3160,02:19.5,2,178,139500,15:38.3,26.32857143,938300,4 +634,3180,02:24.2,2,178,144200,15:44.1,26.28,944099.9999,4 +635,3200,02:17.9,2,177.9142857,137900,15:49.6,26.52857143,949599.9999,4 +636,3220,02:23.0,2,178.3428571,143000,15:55.3,26.70571429,955300,4 +637,3240,02:23.8,2,178.4857143,143800,16:01.1,26.63142857,961099.9999,4 +638,3260,02:31.6,2,178.4285714,151600,16:07.1,26.42857143,967099.9999,4 +639,3280,02:28.8,2,177.6571429,148800,16:13.1,26.63428571,973099.9999,4 +640,3300,02:23.4,2,177.2571429,143400,16:18.8,26.91142857,978800,4 +641,3320,02:29.6,2,176.8285714,149600,16:24.8,27.17428571,984800,4 +642,3340,02:19.9,2,177.2571429,139900,16:30.4,26.91428571,990400.0001,4 +643,3360,02:19.1,2,177.7428571,139100,16:36.0,26.72571429,996000,4 +644,3380,02:20.2,2,178.0857143,140200,16:41.6,26.74857143,1001600,4 +645,3400,02:22.6,2,177.9142857,142600,16:47.3,27.23142857,1007300,4 +646,3420,02:24.5,2,178.3428571,144500,16:53.1,27.3,1013100,4 +647,3440,02:19.5,2,178.4857143,139500,16:58.6,27,1018600,4 +648,3460,02:25.7,2,178.3428571,145700,17:04.5,26.54,1024500,4 +649,3480,02:13.6,2,177.9142857,133600,17:09.8,26.55714286,1029800,4 +650,3500,02:18.3,2,178,138300,17:15.3,26.65714286,1035300,4 +651,3520,02:16.0,2,178,136000,17:20.8,26.85714286,1040800,4 +652,3540,02:16.0,2,178,136000,17:26.2,26.88,1046200,4 +653,3560,02:22.6,2,178,142600,17:31.9,27.08285714,1051900,4 +654,3580,02:21.8,2,177.9142857,141800,17:37.6,27.36285714,1057600,4 +655,3600,02:17.1,2,178.2571429,137100,17:43.1,27.56,1063100,4 +656,3620,02:20.2,2,178.7428571,140200,17:48.7,27.68,1068700,4 +657,3640,02:16.3,2,179.0857143,136300,17:54.1,27.63142857,1074100,4 +658,3660,02:20.6,2,179,140600,17:59.8,27.75142857,1079800,4 +659,3680,02:17.9,2,179,137900,18:05.3,27.38571429,1085300,4 +660,3700,02:21.0,2,179,141000,18:10.9,27.30285714,1090900,4 +661,3720,02:16.3,2,179,136300,18:16.4,27.20571429,1096400,4 +662,3740,02:26.9,2,179,146900,18:22.2,27.24,1102200,4 +663,3760,02:32.4,2,179,152400,18:28.3,26.96571429,1108300,4 +664,3780,02:27.7,2,179,147700,18:34.2,26.4,1114200,4 +665,3800,02:33.5,2,178.9142857,153500,18:40.4,26.11428571,1120400,4 +666,3820,02:22.2,2,179.2571429,142200,18:46.1,26.40857143,1126100,4 +667,3840,02:22.2,2,179.7428571,142200,18:51.8,26.98285714,1131800,4 +668,3860,02:30.4,2,180.1714286,150400,18:57.8,27.06285714,1137800,4 +669,3880,02:22.6,2,179.7428571,142600,19:03.5,26.66571429,1143500,4 +670,3900,02:33.5,2,179.2571429,153500,19:09.6,26.30857143,1149600,4 +671,3920,02:29.2,2,178.8285714,149200,19:15.6,26.57714286,1155600,4 +672,3940,02:24.5,2,179.2571429,144500,19:21.4,27.16571429,1161400,4 +673,3960,02:23.4,2,179.7428571,143400,19:27.1,27.26285714,1167100,4 +674,3980,02:17.5,2,180.0857143,137500,19:32.6,27.38571429,1172600,4 +675,4000,02:18.7,2,179.9142857,138700,19:38.2,28.15714286,1178200,4 +676,4020,02:21.4,2,180.2571429,141400,19:43.8,28.81428571,1183800,4 +677,4040,02:18.7,2,180.7428571,138700,19:49.4,29.13714286,1189400,4 +678,4060,02:23.0,2,181.0857143,143000,19:55.1,28.86857143,1195100,4 +679,4080,02:19.5,2,181,139500,20:00.7,28.32857143,1200700,4 +680,4100,02:12.0,2,181,132000,20:05.9,28.18857143,1205900,4 +681,4120,02:14.4,2,181,134400,20:11.3,28.54571429,1211300,4 +682,4140,02:10.1,2,181,130100,20:16.5,27.95714286,1216500,4 +683,4160,02:17.9,2,181,137900,20:22.0,27.20857143,1222000,4 +684,4180,02:10.9,2,180.9142857,130900,20:27.3,27.03142857,1227300,4 +685,4200,02:16.7,2,182.2,136700,20:32.7,27.56285714,1232700,4 +686,4220,02:15.2,2,177.9714286,135200,20:38.1,27.39428571,1238100,4 +687,4240,02:23.4,2,176.7428571,143400,20:43.9,27.29714286,1243900,4 +688,4260,02:14.0,2,178.2285714,134000,20:49.2,27.35714286,1249200,4 +689,4280,02:20.6,2,182.9428571,140600,20:54.9,27.64,1254900,4 +690,4300,02:16.0,2,182,136000,21:00.3,27.76857143,1260300,4 +691,4320,02:19.1,2,182,139100,21:05.9,27.76571429,1265900,4 +692,4340,02:16.0,2,182,136000,21:11.3,27.46285714,1271300,4 +693,4360,02:18.3,2,182,138300,21:16.8,27.41714286,1276800,4 +694,4380,02:12.0,2,182,132000,21:22.1,27.64285714,1282100,4 +695,4400,02:17.5,2,182,137500,21:27.6,28.02857143,1287600,4 +696,4420,02:12.8,2,182,132800,21:32.9,27.86285714,1292900,4 +697,4440,02:19.5,2,182,139500,21:38.5,27.75428571,1298500,4 +698,4460,02:17.9,2,182,137900,21:44.0,27.56285714,1304000,4 +699,4480,02:13.6,2,182,133600,21:49.4,27.65428571,1309400,4 +700,4500,02:17.1,2,182,137100,21:54.8,27.64571429,1314800,4 +701,4520,02:16.3,2,181.9142857,136300,22:00.3,27.66857143,1320300,4 +702,4540,02:20.2,2,182.2571429,140200,22:05.9,27.82,1300.0001,4 +703,4560,02:14.4,2,182.7428571,134400,22:11.3,27.80857143,1331300,4 +704,4580,02:18.7,2,183.0857143,138700,22:16.8,27.68285714,1336800,4 +705,4600,02:12.4,2,183,132400,22:22.1,27.39428571,1342100,4 +706,4620,02:19.1,2,183,139100,22:27.7,27.61428571,1347700,4 +707,4640,02:11.7,2,183,131700,22:32.9,27.66,1352900,4 +708,4660,02:15.2,2,183,135200,22:38.4,27.98285714,1358400,4 +709,4680,02:10.9,2,183,130900,22:43.6,27.84,1363600,4 +710,4700,02:12.8,2,182.9142857,132800,22:48.9,27.81714286,1368900,4 +711,4720,02:13.6,2,183.2571429,133600,22:54.2,27.81428571,1374200,4 +712,4740,02:13.6,2,183.7428571,133600,22:59.6,27.78571429,1379600,4 +713,4760,02:18.7,2,184.0857143,138700,23:05.1,27.76,1385100,4 +714,4780,02:18.3,2,184,138300,23:10.7,27.95142857,1390700,4 +715,4800,02:07.7,2,184,127700,23:15.8,28.25714286,1395800,4 +716,4820,02:11.3,2,184,131300,23:21.0,28.85142857,1401000,4 +717,4840,02:09.3,2,183.9142857,129300,23:26.2,29.72285714,1406200,4 +718,4860,02:09.3,2,184.2571429,129300,23:31.4,30.53142857,1411400,4 +719,4880,02:03.1,2,184.8285714,123100,23:36.3,31.17142857,1416300,4 +720,4900,02:12.8,2,185.1714286,132800,23:41.6,28.64857143,1421600,4 +721,4920,03:32.5,2,183.5714286,212500,23:50.1,23.55428571,1430100,4 +722,4940,04:06.5,2,181.4571429,246500,24:00.0,17.26571429,1440000,4 +723,4960,04:53.0,2,172.3142857,293000,24:11.7,14.90285714,1451700,4 +725,5000,03:50.9,2,152.7714286,230900,24:33.6,18.27714286,1473600,4 +726,5020,03:38.8,2,150.2857143,218800,24:42.3,20.19142857,1482300,4 +727,5040,02:58.5,2,146.8,178500,24:49.5,18.47142857,1489500,4 +728,5060,03:29.0,2,146.4571429,209000,24:57.8,18.4,1497800,4 +729,5080,02:51.1,2,145.5428571,171100,25:04.7,17.55714286,1504700,4 +730,5100,03:15.7,2,144.6,195700,25:12.5,19.71714286,1512500,4 +731,5120,02:49.2,2,143.3428571,169200,25:19.3,20.26571429,1519300,4 +732,5140,02:45.2,2,143.4857143,165200,25:25.9,21.81714286,1525900,4 +733,5160,03:00.5,2,143.1714286,180500,25:33.1,21.63714286,1533100,4 +734,5180,02:47.2,2,141.9142857,167200,25:39.8,21.34,1539800,4 +735,5200,02:57.7,2,141.1714286,177700,25:46.9,21.07714286,1546900,4 +736,5220,02:53.5,2,141.3428571,173500,25:53.8,21.40285714,1553800,4 +737,5240,03:00.9,2,139.5428571,180900,26:01.1,20.84571429,1561100,4 +739,5280,04:33.1,2,136.4571429,273100,26:25.6,21.45714286,1585600,4 +740,5300,03:21.6,2,135.3428571,201600,26:33.7,20.42857143,1593700,4 +741,5320,03:02.0,2,133.3428571,182000,26:41.0,18.96857143,1601000,4 +742,5340,02:43.7,2,134.0857143,163700,26:47.5,20.21428571,1607500,4 +743,5360,02:39.0,2,135.5714286,159000,26:53.9,20.88857143,1613900,4 +744,5380,02:36.3,2,136.0857143,156300,27:00.1,20.68285714,1620100,4 +745,5400,02:37.8,2,136.2571429,157800,27:06.4,20.77142857,1626400,4 +746,5420,02:33.1,2,136.6571429,153100,27:12.6,20.93714286,1639.9999,4 +747,5440,02:36.7,2,137.2571429,156700,27:18.8,20.66,1638800,4 +748,5460,02:44.9,2,138,164900,27:25.4,20.41714286,1645400,4 +749,5480,02:42.1,2,138.7428571,162100,27:31.9,20.78,1651900,4 +750,5500,02:43.7,2,139.1714286,163700,27:38.5,21.37714286,1658500,4 +751,5520,02:36.7,2,140.1714286,156700,27:44.7,20.03142857,1664700,4 +752,5540,02:49.5,2,141.8285714,169500,27:51.5,19.53142857,1671500,4 +753,5560,02:52.7,2,142.9142857,172700,27:58.4,19.91142857,1678400,4 +754,5580,02:44.1,2,143.0857143,164100,28:05.0,21.20571429,1685000,4 +755,5600,02:44.5,2,143,164500,28:11.5,20.60857143,1691500,4 +756,5620,02:53.1,2,143.0857143,173100,28:18.5,20.82,1698500,4 +757,5640,02:40.6,2,142.8285714,160600,28:24.9,20.61714286,1704900,4 +758,5660,03:00.1,2,142.0857143,180100,28:32.1,19.02285714,1712100,4 +759,5680,03:15.3,2,141,195300,28:39.9,17.61714286,1719900,4 +760,5700,03:25.5,2,140.0857143,205500,28:48.1,18.15714286,1728100,4 +761,5720,03:13.0,2,138.7428571,193000,28:55.8,19.87142857,1735800,4 +762,5740,03:05.2,2,137.2571429,185200,29:03.2,19.95142857,1743200,4 +763,5760,02:55.0,2,135.8285714,175000,29:10.2,19.34,1750200,4 +764,5780,03:13.8,2,135.1714286,193800,29:18.0,19.10857143,1758000,4 +765,5800,03:05.2,2,135,185200,29:25.4,19.75428571,1765400,4 +766,5820,02:47.6,2,134.7428571,167600,29:32.1,19.80857143,1772100,4 +767,5840,02:57.7,2,134.1714286,177700,29:39.2,19.02285714,1779200,4 +768,5860,03:04.8,2,134.2571429,184800,29:46.6,17.70571429,1786600,4 +769,5880,03:01.7,2,134.4857143,181700,29:53.9,16.57714286,1793900,4 +770,5900,03:25.5,2,134.1714286,205500,30:02.1,17.24857143,1802100,4 +771,5920,02:58.9,2,134.4285714,178900,30:09.2,17.98857143,1809200,4 +772,5940,02:35.1,2,135.4857143,155100,30:15.5,19.07714286,1815500,4 +773,5960,02:29.6,2,136.0857143,149600,30:21.4,17.96285714,1821400,4 +774,5980,02:36.7,2,136.2571429,156700,30:27.7,18.49714286,1827700,4 +775,6000,03:03.6,2,136.7428571,183600,30:35.0,15.02857143,1835000,4 +776,6020,03:22.7,2,137.1714286,202700,30:43.2,13.74285714,1843200,4 +777,6040,03:20.4,2,136.7428571,200400,30:51.2,15.00571429,1851200,4 +778,6060,02:53.8,2,136.1714286,173800,30:58.1,19.22285714,1858100,4 +779,6080,02:38.2,2,136,158200,31:04.5,20.82,1864500,4 +780,6100,02:30.0,2,137.1714286,150000,31:10.5,20.95428571,1870500,4 +781,6120,02:29.6,2,138.6571429,149600,31:16.4,21.24857143,1876400,4 +782,6140,02:28.5,2,140.3428571,148500,31:22.4,21.18857143,1882400,4 +783,6160,02:27.3,2,141.9142857,147300,31:28.3,21.90857143,1888300,4 +784,6180,02:41.3,2,142.5714286,161300,31:34.7,17.56571429,1894700,4 +785,6200,03:59.9,2,142.6,239900,31:44.3,15.94,1904300,4 +786,6220,03:55.2,2,142.7428571,235200,31:53.7,17.42285714,1913700,4 +787,6240,02:41.7,2,142.8285714,161700,32:00.2,22.17142857,1920200,4 +788,6260,02:26.9,2,143.6285714,146900,32:06.1,22.28571429,1926100,4 +789,6280,03:09.1,2,138.0571429,189100,32:13.6,19.39714286,1933600,4 +791,6320,04:54.2,2,122.2285714,294200,32:51.5,14.22,1971500,4 +792,6340,04:40.1,2,123.2571429,280100,33:02.7,16.01428571,1982700,4 +793,6360,03:45.4,2,124.2285714,225400,33:11.7,16.48,1991700,4 +794,6380,03:25.9,2,125.8571429,205900,33:19.9,16.66571429,1999900,4 +795,6400,03:41.5,2,127.6571429,221500,33:28.8,16.66285714,2008800,4 +796,6420,03:34.5,2,128.4,214500,33:37.3,17.29142857,2017300,4 +797,6440,03:30.2,2,127.6857143,210200,33:45.8,16.38285714,2025800,4 +798,6460,03:04.8,2,128,184800,33:53.1,16.24,2033100,4 +799,6480,02:45.2,2,130,165200,33:59.8,17.13142857,2039800,4 +800,6500,04:58.8,2,130.7428571,298800,34:11.7,17.76857143,2051700,4 +801,6520,04:37.0,2,128.6571429,277000,34:22.8,17.44857143,2062800,4 +802,6540,04:17.0,2,125.6,257000,34:33.1,15.90571429,2073100,4 +803,6560,03:42.3,2,123.6571429,222300,34:42.0,17.48,2082000,4 +804,6580,03:22.4,2,124.4285714,202400,34:50.0,19.24285714,2090000,4 +805,6600,02:48.4,2,126.8285714,168400,34:56.8,20.73428571,2096800,4 +806,6620,02:51.5,2,129.7428571,171500,35:03.6,21.06,2103600,4 +807,6640,02:35.9,2,132.6857143,155900,35:09.9,24.12,2109900,4 +808,6660,02:42.5,2,133.7142857,162500,35:16.4,15.77428571,2116400,4 +810,6700,04:07.3,2,134.2285714,247300,35:34.6,11.19142857,2134600,4 +811,6720,03:03.6,2,134.0857143,183600,35:42.0,20.16,2142000,4 +812,6740,03:04.8,2,131.8285714,184800,35:49.4,19.37714286,2149400,4 +813,6760,03:04.8,2,130.7714286,184800,35:56.8,18.00571429,2156800,4 +814,6780,03:08.7,2,130.0571429,188700,36:04.3,17.85428571,2164300,4 +815,6800,03:06.0,2,129.5142857,186000,36:11.7,18.40571429,2171700,4 +816,6820,03:01.7,2,129.0857143,181700,36:19.0,19.38285714,2179000,4 +817,6840,02:51.5,2,129.7428571,171500,36:25.9,18.68571429,2185900,4 +818,6860,02:54.2,2,130.1714286,174200,36:32.8,18.47142857,2192800,4 +819,6880,02:55.0,2,129.7428571,175000,36:39.8,18.82285714,2199800,4 +820,6900,03:43.8,2,129.1714286,223800,36:48.8,17.32285714,2208800,4 +821,6920,03:35.6,2,129.3428571,215600,36:57.4,16.45428571,2217400,4 +822,6940,03:09.9,2,129.3142857,189900,37:05.0,16.78571429,2225000,4 +823,6960,03:14.2,2,128.2571429,194200,37:12.8,18.57428571,2232800,4 +824,6980,03:18.8,2,127.3428571,198800,37:20.7,18.82,2240700,4 +825,7000,03:27.4,2,127.7428571,207400,37:29.0,18.33428571,2249000,4 +826,7020,03:06.0,2,127.9142857,186000,37:36.5,16.97142857,2256500,4 +827,7040,03:07.5,2,127,187500,37:44.0,17.31428571,2264000,4 +828,7060,03:05.2,2,126.0857143,185200,37:51.4,15.52857143,2271400,4 +829,7080,03:42.7,2,126.1714286,222700,38:00.3,15.28285714,2280300,4 +830,7100,03:29.4,2,126.8285714,209400,38:08.6,16.79714286,2288600,4 +831,7120,03:10.2,2,126.5714286,190200,38:16.3,18.70571429,2296300,4 +832,7140,03:19.2,2,126.9428571,199200,38:24.2,17.78285714,2304200,4 +833,7160,02:56.2,2,128.4857143,176200,38:31.3,18.33142857,2311300,4 +834,7180,02:53.8,2,129.7428571,173800,38:38.2,20.31714286,2318200,4 +835,7200,02:55.8,2,129.1714286,175800,38:45.3,20.25714286,2325300,4 +836,7220,02:43.7,2,129.3428571,163700,38:51.8,20.09714286,2331800,4 +837,7240,02:42.9,2,130.6571429,162900,38:58.3,20.16571429,2338300,4 +838,7260,02:39.4,2,132.1714286,159400,39:04.7,20.67142857,2344700,4 +839,7280,02:35.9,2,132.5714286,155900,39:10.9,21.14857143,2350900,4 +840,7300,02:41.3,2,133.6857143,161300,39:17.4,20.89142857,2357400,4 +841,7320,02:35.9,2,135.6571429,155900,39:23.6,20.22285714,2363600,4 +842,7340,02:37.8,2,137.9142857,157800,39:29.9,20.23428571,2369900,4 +843,7360,02:37.0,2,139.0857143,157000,39:36.2,20.97142857,2376200,4 +844,7380,02:36.7,2,140,156700,39:42.5,20.93714286,2382500,4 +845,7400,02:35.1,2,141.1714286,155100,39:48.7,20.72571429,2388700,4 +846,7420,02:43.3,2,141.5714286,163300,39:55.2,19.34571429,2395200,4 +847,7440,02:59.3,2,141.3428571,179300,40:02.4,19.09714286,2402400,4 +848,7460,03:03.6,2,140.9142857,183600,40:09.7,19.59142857,2409700,4 +849,7480,02:40.6,2,140.9142857,160600,40:16.1,21.23142857,2416100,4 +850,7500,02:48.8,2,141.2571429,168800,40:22.9,21.16571429,2422900,4 +851,7520,02:39.0,2,141.8285714,159000,40:29.3,21.35428571,2429300,4 +852,7540,02:33.9,2,141.9142857,153900,40:35.4,21.19142857,2435400,4 +853,7560,02:47.6,2,141.0857143,167600,40:42.1,20.27428571,2442100,4 +854,7580,03:02.0,2,140.1714286,182000,40:49.4,19.01714286,2449400,4 +855,7600,03:09.5,2,138.4857143,189500,40:57.0,16.88,2457000,4 +856,7620,03:34.9,2,136.6,214900,41:05.6,14.68,2465600,4 +857,7640,03:27.4,2,134.5714286,207400,41:13.9,15.78285714,2473900,4 +858,7660,03:04.8,2,133.3428571,184800,41:21.3,18.14857143,2481300,4 +859,7680,03:11.8,2,131.8285714,191800,41:28.9,18.93428571,2488900,4 +860,7700,03:24.3,2,129.8285714,204300,41:37.1,20.09714286,2497100,4 +861,7720,03:25.9,2,127.2571429,205900,41:45.3,22.05428571,2505300,4 +862,7740,03:39.2,2,124.7428571,219200,41:54.1,20.40571429,2514100,4 +863,7760,04:09.6,2,123.3428571,249600,42:04.1,17.76,2524100,4 +864,7780,03:13.8,2,122.8285714,193800,42:11.8,17.50857143,2531800,4 +865,7800,03:03.2,2,122.7428571,183200,42:19.2,18.88571429,2539200,4 +866,7820,02:44.5,2,123.6857143,164500,42:25.7,19.37142857,2545700,4 +867,7840,02:35.5,2,125.5714286,155500,42:32.0,19.36,2552000,4 +868,7860,02:46.4,2,126.6571429,166400,42:38.6,18.94571429,2558600,4 +869,7880,02:53.1,2,126.5142857,173100,42:45.5,18.05714286,2565500,4 +870,7900,02:58.5,2,127,178500,42:52.7,18.42571429,2572700,4 +871,7920,02:50.7,2,127.5714286,170700,42:59.5,19.13428571,2579500,4 +872,7940,03:16.1,2,127.4285714,196100,43:07.3,18.88857143,2587300,4 +873,7960,03:12.6,2,126.6571429,192600,43:15.0,17.72285714,2595000,4 +874,7980,03:09.9,2,127.4571429,189900,43:22.6,17.56571429,2602600,4 +875,8000,03:21.2,2,120.9428571,201200,43:30.7,17.82571429,2610700,4 +876,8020,03:07.1,2,119.8,187100,43:38.2,17.67142857,2618200,4 +877,8040,02:55.0,2,122.6,175000,43:45.2,17.52571429,2625200,4 +878,8060,03:00.5,2,128.0285714,180500,43:52.4,19.36571429,2632400,4 +880,8100,03:02.8,2,125.4,182800,44:11.9,19.29714286,2651900,4 +881,8120,02:57.0,2,125,177000,44:19.0,18.31428571,2659000,4 +882,8140,03:05.6,2,124.5142857,185600,44:26.4,18.44285714,2666400,4 +883,8160,03:12.6,2,124.5714286,192600,44:34.1,18.39142857,2674100,4 +884,8180,03:02.0,2,123.8285714,182000,44:41.4,15.79714286,2681400,4 +885,8200,03:57.5,2,122.3428571,237500,44:50.9,15.76,2690900,4 +886,8220,03:24.3,2,122.0857143,204300,44:59.1,17.60571429,2699100,4 +887,8240,03:09.9,2,122.5714286,189900,45:06.7,19.90857143,2706700,4 +888,8260,02:55.4,2,123.3428571,175400,45:13.7,19.60857143,2713700,4 +889,8280,02:48.8,2,125.1714286,168800,45:20.5,20.53428571,2720500,4 +890,8300,02:45.6,2,127.5714286,165600,45:27.1,21.03714286,2727100,4 +891,8320,02:48.8,2,129.0857143,168800,45:33.8,20.94,2733800,4 +892,8340,02:45.2,2,130.3428571,165200,45:40.4,20.74285714,2740400,4 +893,8360,02:44.5,2,131.4857143,164500,45:47.0,21.22285714,2747000,4 +894,8380,02:44.1,2,132.4285714,164100,45:53.6,20.41428571,2753600,4 +895,8400,02:46.8,2,132.5714286,166800,46:00.3,20.10857143,2760300,4 +896,8420,02:39.4,2,133.6857143,159400,46:06.6,20.84,2766600,4 +897,8440,02:49.9,2,134.2285714,169900,46:13.4,19.14857143,2773400,4 +898,8460,03:00.9,2,134.4285714,180900,46:20.7,18.04285714,2780700,4 +899,8480,02:56.6,2,134.0857143,176600,46:27.7,17.96285714,2787700,4 +900,8500,02:55.0,2,133.4857143,175000,46:34.7,19.39428571,2794700,4 +901,8520,02:56.2,2,132.5142857,176200,46:41.8,19.5,2801800,4 +902,8540,02:53.8,2,131.7428571,173800,46:48.7,19.76285714,2808700,4 +903,8560,02:46.4,2,132.4285714,166400,46:55.4,19.37714286,2815400,4 +904,8580,02:42.5,2,132.3142857,162500,47:01.9,19.22571429,2821900,4 +905,8600,02:57.0,2,131.3428571,177000,47:09.0,19.37428571,2829000,4 +906,8620,03:09.9,2,130,189900,47:16.5,19.66571429,2836500,4 +907,8640,02:49.9,2,130.3428571,169900,47:23.3,18.85714286,2843300,4 +908,8660,02:46.4,2,130.4,166400,47:30.0,19.05714286,2850000,4 +909,8680,02:50.3,2,129.0857143,170300,47:36.8,17.12285714,2856800,4 +910,8700,02:58.1,2,127.4285714,178100,47:43.9,17.06571429,2863900,4 +911,8720,03:07.9,2,126.4857143,187900,47:51.5,17.68,2871500,4 +912,8740,02:58.1,2,126.4285714,178100,47:58.6,20.31428571,2878600,4 +913,8760,02:55.4,2,127,175400,48:05.6,18.96857143,2885600,4 +914,8780,03:12.6,2,127.4857143,192600,48:13.3,18.59714286,2893300,4 +915,8800,03:05.2,2,127.2571429,185200,48:20.7,19.44,2900700,4 +916,8820,02:58.9,2,128.8571429,178900,48:27.9,21.48857143,2907900,4 +917,8840,02:45.6,2,130.6285714,165600,48:34.5,18.81714286,2914500,4 +918,8860,03:02.4,2,130.7714286,182400,48:41.8,16.06,2921800,4 +919,8880,03:28.6,2,128.5714286,208600,48:50.1,15.00857143,2930100,4 +920,8900,03:20.8,2,127.4285714,200800,48:58.2,17.34571429,2938200,4 +921,8920,02:52.7,2,126.8285714,172700,49:05.1,18.52571429,2945100,4 +922,8940,02:50.3,2,127,170300,49:11.9,19.74857143,2951900,4 +923,8960,02:54.6,2,127,174600,49:18.9,20.26571429,2958900,4 +924,8980,02:47.6,2,126.8285714,167600,49:25.6,20.20571429,2965600,4 +925,9000,02:43.7,2,127.2571429,163700,49:32.1,19.37142857,2972100,4 +926,9020,02:46.0,2,129.0857143,166000,49:38.8,19.47142857,2978800,4 +927,9040,02:57.0,2,131.8285714,177000,49:45.8,20.43714286,2985800,4 +928,9060,02:35.5,2,133.8285714,155500,49:52.1,20.92857143,2992100,4 +929,9080,02:28.8,2,135.3428571,148800,49:58.0,20.89714286,2998000,4 +930,9100,02:30.4,2,136.7428571,150400,50:04.0,21.40285714,3004000,4 +931,9120,02:26.5,2,138.0857143,146500,50:09.9,22.31142857,3009900,4 +932,9140,02:26.9,2,138.9142857,146900,50:15.8,22.7,3015800,4 +933,9160,02:36.7,2,140.2571429,156700,50:22.0,22.59428571,3022000,4 +934,9180,02:30.0,2,141.7428571,150000,50:28.0,22.43142857,3028000,4 +935,9200,02:29.2,2,143.0857143,149200,50:34.0,22.20857143,3034000,4 +936,9220,02:27.3,2,144.2571429,147300,50:39.9,21.71142857,3039900,4 +937,9240,02:35.5,2,146.0285714,155500,50:46.1,23.12857143,3046100,4 +938,9260,03:08.3,2,138.9714286,188300,50:53.6,22.98857143,3053600,4 +939,9280,04:01.4,2,126.3428571,241400,51:03.3,13.11142857,3063300,4 +941,9320,03:36.4,2,117.5714286,216400,51:25.0,11.70571429,3085000,4 +942,9340,03:51.3,2,119.9142857,231300,51:34.3,19.73714286,3094300,4 +943,9360,03:22.0,2,122.0857143,202000,51:42.3,18.46857143,3102300,4 +944,9380,03:16.1,2,125.7142857,196100,51:50.2,15.80285714,3110200,4 +945,9400,03:25.9,2,118.5714286,205900,51:58.4,16.25428571,3118400,4 +947,9440,03:14.2,2,110.0285714,194200,52:23.5,20.32285714,3143500,4 +948,9460,02:58.9,2,118.1428571,178900,52:30.7,19.28285714,3150700,4 +949,9480,02:50.3,2,122.3142857,170300,52:37.5,17.68,3157500,4 +950,9500,04:10.0,2,127.4571429,250000,52:47.5,17.38,3167500,4 +951,9520,03:45.0,2,126.8857143,225000,52:56.5,16.28,3176500,4 +955,80,03:30.6,3,127.2857143,210600,01:02.5,18.89142857,62500,4 +956,100,03:25.9,3,132.5142857,205900,01:10.8,18.57714286,70799.99995,4 +957,120,03:00.5,3,135.2571429,180500,01:18.0,21.22571429,78000,4 +958,140,02:32.0,3,140,152000,01:24.1,24.74857143,84099.9999,4 +959,160,02:13.2,3,146.0857143,133200,01:29.4,27.41714286,89400.0001,4 +960,180,02:15.6,3,151.9142857,135600,01:34.8,27.46857143,94799.99995,4 +961,200,02:16.0,3,155.6571429,136000,01:40.3,27.24857143,100300,4 +962,220,02:23.8,3,157.1714286,143800,01:46.0,27.2,106000,4 +963,240,02:15.6,3,158.2571429,135600,01:51.4,27.46285714,111400.0001,4 +964,260,02:24.2,3,159.7428571,144200,01:57.2,27.71428571,117200,4 +965,280,02:11.7,3,161.1714286,131700,02:02.5,27.48285714,122500,4 +966,300,02:22.6,3,161.7428571,142600,02:08.2,27.20857143,128200,4 +967,320,02:18.7,3,162.2571429,138700,02:13.7,26.65142857,133700,4 +968,340,02:28.5,3,162.9142857,148500,02:19.6,26.58285714,139599.9999,4 +969,360,02:32.7,3,164,152700,02:25.8,26.19142857,145800,4 +970,380,02:26.9,3,165.0857143,146900,02:31.6,25.69428571,151599.9999,4 +971,400,02:31.6,3,165.8285714,151600,02:37.7,25.55714286,157700,4 +972,420,02:21.0,3,166.0857143,141000,02:43.3,25.83142857,163300,4 +973,440,02:33.5,3,166,153500,02:49.5,26.14857143,169500,4 +974,460,02:35.1,3,165.9142857,155100,02:55.7,26.13714286,175700,4 +975,480,02:25.3,3,166.2571429,145300,03:01.5,26.7,181500,4 +976,500,02:34.7,3,166.7428571,154700,03:07.7,26.58571429,187700,4 +977,520,02:34.7,3,167,154700,03:13.9,26.28857143,193900.0001,4 +978,540,02:32.0,3,167.2571429,152000,03:19.9,25.54,199900.0001,4 +979,560,02:41.0,3,167.6571429,161000,03:26.4,25.30571429,206400.0001,4 +980,580,02:35.1,3,168.3428571,155100,03:32.6,25.35142857,212599.9999,4 +981,600,02:29.2,3,168.8285714,149200,03:38.6,25.90571429,218599.9999,4 +982,620,02:33.1,3,168.7428571,153100,03:44.7,25.97142857,224700,4 +983,640,02:30.4,3,168.6,150400,03:50.7,25.86571429,230700,4 +984,660,02:29.6,3,168.4,149600,03:56.7,25.81142857,236700,4 +985,680,02:28.1,3,168.3428571,148100,04:02.6,25.72571429,242599.9999,4 +986,700,02:27.7,3,167.8285714,147700,04:08.5,25.31714286,248500,4 +987,720,02:30.0,3,168.2571429,150000,04:14.5,25.11714286,254500,4 +988,740,02:28.1,3,168.7428571,148100,04:20.4,25.24285714,260400.0001,4 +989,760,02:34.3,3,169.0857143,154300,04:26.6,25.32857143,266599.9999,4 +990,780,02:23.0,3,169,143000,04:32.3,25.67428571,272300,4 +991,800,02:26.1,3,169,146100,04:38.2,26.05142857,278200,4 +992,820,02:23.4,3,168.9142857,143400,04:43.9,26.58,283900.0001,4 +993,840,02:31.2,3,169.2571429,151200,04:49.9,26.56,289900.0001,4 +994,860,02:23.0,3,169.7428571,143000,04:55.7,26.81714286,295700,4 +995,880,02:30.0,3,170.0857143,150000,05:01.7,27.07714286,301700,4 +996,900,02:26.5,3,170,146500,05:07.5,27.39428571,307500,4 +997,920,02:20.6,3,170,140600,05:13.1,27.06285714,313099.9999,4 +998,940,02:24.2,3,170,144200,05:18.9,26.73714286,318900.0001,4 +999,960,02:18.3,3,170,138300,05:24.4,26.76,324400.0001,4 +1000,980,02:19.9,3,170,139900,05:30.0,26.83428571,330000,4 +1001,1000,02:16.7,3,169.9142857,136700,05:35.5,27.01714286,335500,4 +1002,1020,02:22.2,3,170.2571429,142200,05:41.2,27.38857143,341200,4 +1003,1040,02:23.4,3,170.7428571,143400,05:46.9,27.62857143,346900.0001,4 +1004,1060,02:15.6,3,171,135600,05:52.3,27.37142857,352300,4 +1005,1080,02:18.3,3,171.2571429,138300,05:57.9,27.40285714,357900.0001,4 +1006,1100,02:16.7,3,171.7428571,136700,06:03.3,27.36571429,363300,4 +1007,1120,02:24.9,3,172.0857143,144900,06:09.1,27.08285714,369099.9999,4 +1008,1140,02:18.7,3,172,138700,06:14.7,26.83142857,374700,4 +1009,1160,02:21.8,3,172.0857143,141800,06:20.4,26.92285714,380400.0001,4 +1010,1180,02:14.4,3,171.7428571,134400,06:25.7,27.00285714,385700,4 +1011,1200,02:18.7,3,171.2571429,138700,06:31.3,27.36857143,391300,4 +1012,1220,02:10.5,3,170.9142857,130500,06:36.5,27.42571429,396500,4 +1013,1240,02:10.9,3,170.9142857,130900,06:41.7,26.94571429,401700,4 +1014,1260,02:15.6,3,171.2571429,135600,06:47.2,26.62857143,407200,4 +1015,1280,02:12.4,3,171.7428571,132400,06:52.5,26.80285714,412500,4 +1016,1300,02:13.2,3,172.0857143,133200,06:57.8,27.13714286,417800,4 +1017,1320,02:09.3,3,172,129300,07:03.0,27.50857143,423000,4 +1018,1340,02:06.2,3,171.9142857,126200,07:08.0,27.71142857,428000,4 +1019,1360,02:16.0,3,172.2571429,136000,07:13.4,27.73142857,433400.0001,4 +1020,1380,02:10.9,3,172.7428571,130900,07:18.7,27.68857143,438700,4 +1021,1400,02:20.2,3,173.0857143,140200,07:24.3,27.54857143,444300,4 +1022,1420,02:09.3,3,173,129300,07:29.5,27.03428571,449500,4 +1023,1440,02:06.2,3,172.9142857,126200,07:34.5,26.83714286,454500,4 +1024,1460,02:16.0,3,173.2571429,136000,07:39.9,26.74285714,459900.0001,4 +1025,1480,02:10.9,3,173.7428571,130900,07:45.2,26.92571429,465200,4 +1026,1500,02:10.5,3,174.0857143,130500,07:50.4,26.86571429,470400.0001,4 +1027,1520,02:15.6,3,173.9142857,135600,07:55.8,26.92285714,475800,4 +1028,1540,02:16.0,3,174.2571429,136000,08:01.3,26.84857143,481300,4 +1029,1560,02:20.2,3,174.7428571,140200,08:06.9,26.97428571,486900.0001,4 +1030,1580,02:18.3,3,175.0857143,138300,08:12.4,26.74857143,492400.0001,4 +1031,1600,02:25.3,3,175.0857143,145300,08:18.2,26.52857143,498200,4 +1032,1620,02:28.1,3,174.7428571,148100,08:24.1,26.40571429,504099.9999,4 +1033,1640,02:19.9,3,174.2571429,139900,08:29.7,26.29142857,509700,4 +1034,1660,02:12.0,3,173.9142857,132000,08:35.0,26.10857143,515000,4 +1035,1680,02:20.2,3,174,140200,08:40.6,26.52285714,520599.9999,4 +1036,1700,02:18.3,3,174,138300,08:46.1,26.82285714,526099.9999,4 +1037,1720,02:24.9,3,174,144900,08:51.9,26.70571429,531900.0001,4 +1038,1740,02:17.9,3,174,137900,08:57.5,26.29142857,537500,4 +1039,1760,02:26.9,3,174,146900,09:03.3,26.23142857,543300,4 +1040,1780,02:23.4,3,173.9142857,143400,09:09.1,26.46285714,549099.9999,4 +1041,1800,02:26.9,3,174.2571429,146900,09:14.9,26.78,554900.0001,4 +1042,1820,02:28.1,3,174.7428571,148100,09:20.9,26.66285714,560900.0001,4 +1043,1840,02:20.2,3,175.0857143,140200,09:26.5,26.38285714,566500,4 +1044,1860,02:15.2,3,175,135200,09:31.9,26.30285714,571900.0001,4 +1045,1880,02:20.6,3,174.9142857,140600,09:37.5,26.46,577500,4 +1046,1900,02:13.2,3,175.3428571,133200,09:42.8,26.49142857,582800,4 +1047,1920,02:19.1,3,175.4,139100,09:48.4,26.88571429,588400.0001,4 +1048,1940,02:10.5,3,175.6,130500,09:53.6,27.38285714,593599.9999,4 +1049,1960,02:14.8,3,175.6571429,134800,09:59.0,27.04,599000,4 +1050,1980,02:16.7,3,176.0857143,136700,10:04.5,26.7,604500,4 +1051,2000,02:16.7,3,176,136700,10:09.9,26.51142857,609900.0001,4 +1052,2020,02:18.3,3,176,138300,10:15.5,26.86571429,615500,4 +1053,2040,02:13.2,3,176,133200,10:20.8,27.09142857,620800,4 +1054,2060,02:21.0,3,175.9142857,141000,10:26.4,27.39428571,626400.0001,4 +1055,2080,02:18.7,3,176.3428571,138700,10:32.0,27.6,632000,4 +1056,2100,02:22.2,3,176.4,142200,10:37.7,27.51714286,637700,4 +1057,2120,02:15.6,3,176.6,135600,10:43.1,27.26857143,643099.9999,4 +1058,2140,02:19.5,3,176.6571429,139500,10:48.7,27.10571429,648700,4 +1059,2160,02:14.0,3,177.0857143,134000,10:54.0,27.24285714,654000,4 +1060,2180,02:16.3,3,177,136300,10:59.5,27.28571429,659500,4 +1061,2200,02:07.7,3,177,127700,11:04.6,27.29428571,664599.9999,4 +1062,2220,02:14.0,3,177,134000,11:10.0,27.52857143,670000,4 +1063,2240,02:09.7,3,176.9142857,129700,11:15.1,28.00571429,675099.9999,4 +1064,2260,02:15.2,3,177.2571429,135200,11:20.6,28.47142857,680599.9999,4 +1065,2280,02:09.7,3,177.7428571,129700,11:25.7,28.77428571,685700,4 +1066,2300,02:20.6,3,178.0857143,140600,11:31.4,28.68571429,691400.0001,4 +1067,2320,02:20.2,3,177.9142857,140200,11:37.0,28.40571429,697000,4 +1068,2340,02:19.9,3,178.2571429,139900,11:42.6,28.06857143,702599.9999,4 +1069,2360,02:26.1,3,178.7428571,146100,11:48.4,27.66571429,708400.0001,4 +1070,2380,02:15.2,3,179.0857143,135200,11:53.8,27.4,713800,4 +1071,2400,02:16.3,3,179,136300,11:59.3,27.36857143,719300,4 +1072,2420,02:09.7,3,179,129700,12:04.5,27.51428571,724500,4 +1073,2440,02:14.4,3,179,134400,12:09.8,27.82857143,729800,4 +1074,2460,02:13.6,3,179,133600,12:15.2,27.65714286,735200,4 +1075,2480,02:28.5,3,178.9142857,148500,12:21.1,28.05142857,741099.9999,4 +1076,2500,02:25.7,3,179.3428571,145700,12:26.9,28.2,746900.0001,4 +1077,2520,02:18.7,3,179.4857143,138700,12:32.5,27.49142857,752500,4 +1078,2540,02:30.8,3,179.4285714,150800,12:38.5,26.26285714,758500,4 +1079,2560,02:25.7,3,178.5714286,145700,12:44.4,25.65428571,764400.0001,4 +1080,2580,02:35.9,3,178.6,155900,12:50.6,25.76,770599.9999,4 +1081,2600,02:29.2,3,178.4,149200,12:56.6,25.66857143,776599.9999,4 +1082,2620,02:26.5,3,178.3428571,146500,13:02.4,25.59142857,782400.0001,4 +1083,2640,02:24.9,3,177.9142857,144900,13:08.2,25.26,788200,4 +1084,2660,02:30.0,3,178,150000,13:14.2,25.70571429,794200,4 +1085,2680,02:25.3,3,178,145300,13:20.0,26.26571429,800000,4 +1086,2700,02:22.6,3,178,142600,13:25.7,26.32,805700,4 +1087,2720,02:32.0,3,178,152000,13:31.8,25.91714286,811800,4 +1088,2740,02:26.1,3,178,146100,13:37.6,25.96857143,817599.9999,4 +1089,2760,02:29.2,3,178,149200,13:43.6,26.02,823599.9999,4 +1090,2780,02:23.4,3,178.0857143,143400,13:49.4,26.26571429,829400.0001,4 +1091,2800,02:26.5,3,177.6571429,146500,13:55.2,26.35142857,835200,4 +1092,2820,02:19.1,3,177.5142857,139100,14:00.8,26.14857143,840800,4 +1093,2840,02:25.7,3,177.6571429,145700,14:06.6,26.26857143,846599.9999,4 +1094,2860,02:18.7,3,178.0857143,138700,14:12.1,27.1,852099.9999,4 +1095,2880,02:19.5,3,178,139500,14:17.7,28.33142857,857700,4 +1096,2900,02:28.8,3,178,148800,14:23.7,28.55714286,863700,4 +1097,2920,02:32.4,3,178,152400,14:29.8,28.26571429,869800,4 +1098,2940,02:21.0,3,178,141000,14:35.4,27.36,875400.0001,4 +1099,2960,02:23.0,3,178,143000,14:41.1,27.18571429,881099.9999,4 +1100,2980,02:30.8,3,177.9142857,150800,14:47.2,27.18285714,887200,4 +1101,3000,02:27.7,3,178.3428571,147700,14:53.1,27.18571429,893099.9999,4 +1102,3020,02:25.7,3,178.4,145700,14:58.9,26.68285714,898900.0001,4 +1103,3040,02:23.0,3,178.6857143,143000,15:04.6,26.50285714,904599.9999,4 +1104,3060,02:23.8,3,178.4,143800,15:10.4,26.31142857,910400.0001,4 +1105,3080,02:17.1,3,178.3428571,137100,15:15.9,26.28,915900.0001,4 +1106,3100,02:23.8,3,177.9142857,143800,15:21.6,26.49142857,921599.9999,4 +1107,3120,02:17.1,3,178,137100,15:27.1,26.78857143,927099.9999,4 +1108,3140,02:21.4,3,178,141400,15:32.7,26.59142857,932700,4 +1109,3160,02:19.5,3,178,139500,15:38.3,26.32857143,938300,4 +1110,3180,02:24.2,3,178,144200,15:44.1,26.28,944099.9999,4 +1111,3200,02:17.9,3,177.9142857,137900,15:49.6,26.52857143,949599.9999,4 +1112,3220,02:23.0,3,178.3428571,143000,15:55.3,26.70571429,955300,4 +1113,3240,02:23.8,3,178.4857143,143800,16:01.1,26.63142857,961099.9999,4 +1114,3260,02:31.6,3,178.4285714,151600,16:07.1,26.42857143,967099.9999,4 +1115,3280,02:28.8,3,177.6571429,148800,16:13.1,26.63428571,973099.9999,4 +1116,3300,02:23.4,3,177.2571429,143400,16:18.8,26.91142857,978800,4 +1117,3320,02:29.6,3,176.8285714,149600,16:24.8,27.17428571,984800,4 +1118,3340,02:19.9,3,177.2571429,139900,16:30.4,26.91428571,990400.0001,4 +1119,3360,02:19.1,3,177.7428571,139100,16:36.0,26.72571429,996000,4 +1120,3380,02:20.2,3,178.0857143,140200,16:41.6,26.74857143,1001600,4 +1121,3400,02:22.6,3,177.9142857,142600,16:47.3,27.23142857,1007300,4 +1122,3420,02:24.5,3,178.3428571,144500,16:53.1,27.3,1013100,4 +1123,3440,02:19.5,3,178.4857143,139500,16:58.6,27,1018600,4 +1124,3460,02:25.7,3,178.3428571,145700,17:04.5,26.54,1024500,4 +1125,3480,02:13.6,3,177.9142857,133600,17:09.8,26.55714286,1029800,4 +1126,3500,02:18.3,3,178,138300,17:15.3,26.65714286,1035300,4 +1127,3520,02:16.0,3,178,136000,17:20.8,26.85714286,1040800,4 +1128,3540,02:16.0,3,178,136000,17:26.2,26.88,1046200,4 +1129,3560,02:22.6,3,178,142600,17:31.9,27.08285714,1051900,4 +1130,3580,02:21.8,3,177.9142857,141800,17:37.6,27.36285714,1057600,4 +1131,3600,02:17.1,3,178.2571429,137100,17:43.1,27.56,1063100,4 +1132,3620,02:20.2,3,178.7428571,140200,17:48.7,27.68,1068700,4 +1133,3640,02:16.3,3,179.0857143,136300,17:54.1,27.63142857,1074100,4 +1134,3660,02:20.6,3,179,140600,17:59.8,27.75142857,1079800,4 +1135,3680,02:17.9,3,179,137900,18:05.3,27.38571429,1085300,4 +1136,3700,02:21.0,3,179,141000,18:10.9,27.30285714,1090900,4 +1137,3720,02:16.3,3,179,136300,18:16.4,27.20571429,1096400,4 +1138,3740,02:26.9,3,179,146900,18:22.2,27.24,1102200,4 +1139,3760,02:32.4,3,179,152400,18:28.3,26.96571429,1108300,4 +1140,3780,02:27.7,3,179,147700,18:34.2,26.4,1114200,4 +1141,3800,02:33.5,3,178.9142857,153500,18:40.4,26.11428571,1120400,4 +1142,3820,02:22.2,3,179.2571429,142200,18:46.1,26.40857143,1126100,4 +1143,3840,02:22.2,3,179.7428571,142200,18:51.8,26.98285714,1131800,4 +1144,3860,02:30.4,3,180.1714286,150400,18:57.8,27.06285714,1137800,4 +1145,3880,02:22.6,3,179.7428571,142600,19:03.5,26.66571429,1143500,4 +1146,3900,02:33.5,3,179.2571429,153500,19:09.6,26.30857143,1149600,4 +1147,3920,02:29.2,3,178.8285714,149200,19:15.6,26.57714286,1155600,4 +1148,3940,02:24.5,3,179.2571429,144500,19:21.4,27.16571429,1161400,4 +1149,3960,02:23.4,3,179.7428571,143400,19:27.1,27.26285714,1167100,4 +1150,3980,02:17.5,3,180.0857143,137500,19:32.6,27.38571429,1172600,4 +1151,4000,02:18.7,3,179.9142857,138700,19:38.2,28.15714286,1178200,4 +1152,4020,02:21.4,3,180.2571429,141400,19:43.8,28.81428571,1183800,4 +1153,4040,02:18.7,3,180.7428571,138700,19:49.4,29.13714286,1189400,4 +1154,4060,02:23.0,3,181.0857143,143000,19:55.1,28.86857143,1195100,4 +1155,4080,02:19.5,3,181,139500,20:00.7,28.32857143,1200700,4 +1156,4100,02:12.0,3,181,132000,20:05.9,28.18857143,1205900,4 +1157,4120,02:14.4,3,181,134400,20:11.3,28.54571429,1211300,4 +1158,4140,02:10.1,3,181,130100,20:16.5,27.95714286,1216500,4 +1159,4160,02:17.9,3,181,137900,20:22.0,27.20857143,1222000,4 +1160,4180,02:10.9,3,180.9142857,130900,20:27.3,27.03142857,1227300,4 +1161,4200,02:16.7,3,182.2,136700,20:32.7,27.56285714,1232700,4 +1162,4220,02:15.2,3,177.9714286,135200,20:38.1,27.39428571,1238100,4 +1163,4240,02:23.4,3,176.7428571,143400,20:43.9,27.29714286,1243900,4 +1164,4260,02:14.0,3,178.2285714,134000,20:49.2,27.35714286,1249200,4 +1165,4280,02:20.6,3,182.9428571,140600,20:54.9,27.64,1254900,4 +1166,4300,02:16.0,3,182,136000,21:00.3,27.76857143,1260300,4 +1167,4320,02:19.1,3,182,139100,21:05.9,27.76571429,1265900,4 +1168,4340,02:16.0,3,182,136000,21:11.3,27.46285714,1271300,4 +1169,4360,02:18.3,3,182,138300,21:16.8,27.41714286,1276800,4 +1170,4380,02:12.0,3,182,132000,21:22.1,27.64285714,1282100,4 +1171,4400,02:17.5,3,182,137500,21:27.6,28.02857143,1287600,4 +1172,4420,02:12.8,3,182,132800,21:32.9,27.86285714,1292900,4 +1173,4440,02:19.5,3,182,139500,21:38.5,27.75428571,1298500,4 +1174,4460,02:17.9,3,182,137900,21:44.0,27.56285714,1304000,4 +1175,4480,02:13.6,3,182,133600,21:49.4,27.65428571,1309400,4 +1176,4500,02:17.1,3,182,137100,21:54.8,27.64571429,1314800,4 +1177,4520,02:16.3,3,181.9142857,136300,22:00.3,27.66857143,1320300,4 +1178,4540,02:20.2,3,182.2571429,140200,22:05.9,27.82,1300.0001,4 +1179,4560,02:14.4,3,182.7428571,134400,22:11.3,27.80857143,1331300,4 +1180,4580,02:18.7,3,183.0857143,138700,22:16.8,27.68285714,1336800,4 +1181,4600,02:12.4,3,183,132400,22:22.1,27.39428571,1342100,4 +1182,4620,02:19.1,3,183,139100,22:27.7,27.61428571,1347700,4 +1183,4640,02:11.7,3,183,131700,22:32.9,27.66,1352900,4 +1184,4660,02:15.2,3,183,135200,22:38.4,27.98285714,1358400,4 +1185,4680,02:10.9,3,183,130900,22:43.6,27.84,1363600,4 +1186,4700,02:12.8,3,182.9142857,132800,22:48.9,27.81714286,1368900,4 +1187,4720,02:13.6,3,183.2571429,133600,22:54.2,27.81428571,1374200,4 +1188,4740,02:13.6,3,183.7428571,133600,22:59.6,27.78571429,1379600,4 +1189,4760,02:18.7,3,184.0857143,138700,23:05.1,27.76,1385100,4 +1190,4780,02:18.3,3,184,138300,23:10.7,27.95142857,1390700,4 +1191,4800,02:07.7,3,184,127700,23:15.8,28.25714286,1395800,4 +1192,4820,02:11.3,3,184,131300,23:21.0,28.85142857,1401000,4 +1193,4840,02:09.3,3,183.9142857,129300,23:26.2,29.72285714,1406200,4 +1194,4860,02:09.3,3,184.2571429,129300,23:31.4,30.53142857,1411400,4 +1195,4880,02:03.1,3,184.8285714,123100,23:36.3,31.17142857,1416300,4 +1196,4900,02:12.8,3,185.1714286,132800,23:41.6,28.64857143,1421600,4 +1197,4920,03:32.5,3,183.5714286,212500,23:50.1,23.55428571,1430100,4 +1198,4940,04:06.5,3,181.4571429,246500,24:00.0,17.26571429,1440000,4 +1199,4960,04:53.0,3,172.3142857,293000,24:11.7,14.90285714,1451700,4 +1201,5000,03:50.9,3,152.7714286,230900,24:33.6,18.27714286,1473600,4 +1202,5020,03:38.8,3,150.2857143,218800,24:42.3,20.19142857,1482300,4 +1203,5040,02:58.5,3,146.8,178500,24:49.5,18.47142857,1489500,4 +1204,5060,03:29.0,3,146.4571429,209000,24:57.8,18.4,1497800,4 +1205,5080,02:51.1,3,145.5428571,171100,25:04.7,17.55714286,1504700,4 +1206,5100,03:15.7,3,144.6,195700,25:12.5,19.71714286,1512500,4 +1207,5120,02:49.2,3,143.3428571,169200,25:19.3,20.26571429,1519300,4 +1208,5140,02:45.2,3,143.4857143,165200,25:25.9,21.81714286,1525900,4 +1209,5160,03:00.5,3,143.1714286,180500,25:33.1,21.63714286,1533100,4 +1210,5180,02:47.2,3,141.9142857,167200,25:39.8,21.34,1539800,4 +1211,5200,02:57.7,3,141.1714286,177700,25:46.9,21.07714286,1546900,4 +1212,5220,02:53.5,3,141.3428571,173500,25:53.8,21.40285714,1553800,4 +1213,5240,03:00.9,3,139.5428571,180900,26:01.1,20.84571429,1561100,4 +1215,5280,04:33.1,3,136.4571429,273100,26:25.6,21.45714286,1585600,4 +1216,5300,03:21.6,3,135.3428571,201600,26:33.7,20.42857143,1593700,4 +1217,5320,03:02.0,3,133.3428571,182000,26:41.0,18.96857143,1601000,4 +1218,5340,02:43.7,3,134.0857143,163700,26:47.5,20.21428571,1607500,4 +1219,5360,02:39.0,3,135.5714286,159000,26:53.9,20.88857143,1613900,4 +1220,5380,02:36.3,3,136.0857143,156300,27:00.1,20.68285714,1620100,4 +1221,5400,02:37.8,3,136.2571429,157800,27:06.4,20.77142857,1626400,4 +1222,5420,02:33.1,3,136.6571429,153100,27:12.6,20.93714286,1639.9999,4 +1223,5440,02:36.7,3,137.2571429,156700,27:18.8,20.66,1638800,4 +1224,5460,02:44.9,3,138,164900,27:25.4,20.41714286,1645400,4 +1225,5480,02:42.1,3,138.7428571,162100,27:31.9,20.78,1651900,4 +1226,5500,02:43.7,3,139.1714286,163700,27:38.5,21.37714286,1658500,4 +1227,5520,02:36.7,3,140.1714286,156700,27:44.7,20.03142857,1664700,4 +1228,5540,02:49.5,3,141.8285714,169500,27:51.5,19.53142857,1671500,4 +1229,5560,02:52.7,3,142.9142857,172700,27:58.4,19.91142857,1678400,4 +1230,5580,02:44.1,3,143.0857143,164100,28:05.0,21.20571429,1685000,4 +1231,5600,02:44.5,3,143,164500,28:11.5,20.60857143,1691500,4 +1232,5620,02:53.1,3,143.0857143,173100,28:18.5,20.82,1698500,4 +1233,5640,02:40.6,3,142.8285714,160600,28:24.9,20.61714286,1704900,4 +1234,5660,03:00.1,3,142.0857143,180100,28:32.1,19.02285714,1712100,4 +1235,5680,03:15.3,3,141,195300,28:39.9,17.61714286,1719900,4 +1236,5700,03:25.5,3,140.0857143,205500,28:48.1,18.15714286,1728100,4 +1237,5720,03:13.0,3,138.7428571,193000,28:55.8,19.87142857,1735800,4 +1238,5740,03:05.2,3,137.2571429,185200,29:03.2,19.95142857,1743200,4 +1239,5760,02:55.0,3,135.8285714,175000,29:10.2,19.34,1750200,4 +1240,5780,03:13.8,3,135.1714286,193800,29:18.0,19.10857143,1758000,4 +1241,5800,03:05.2,3,135,185200,29:25.4,19.75428571,1765400,4 +1242,5820,02:47.6,3,134.7428571,167600,29:32.1,19.80857143,1772100,4 +1243,5840,02:57.7,3,134.1714286,177700,29:39.2,19.02285714,1779200,4 +1244,5860,03:04.8,3,134.2571429,184800,29:46.6,17.70571429,1786600,4 +1245,5880,03:01.7,3,134.4857143,181700,29:53.9,16.57714286,1793900,4 +1246,5900,03:25.5,3,134.1714286,205500,30:02.1,17.24857143,1802100,4 +1247,5920,02:58.9,3,134.4285714,178900,30:09.2,17.98857143,1809200,4 +1248,5940,02:35.1,3,135.4857143,155100,30:15.5,19.07714286,1815500,4 +1249,5960,02:29.6,3,136.0857143,149600,30:21.4,17.96285714,1821400,4 +1250,5980,02:36.7,3,136.2571429,156700,30:27.7,18.49714286,1827700,4 +1251,6000,03:03.6,3,136.7428571,183600,30:35.0,15.02857143,1835000,4 +1252,6020,03:22.7,3,137.1714286,202700,30:43.2,13.74285714,1843200,4 +1253,6040,03:20.4,3,136.7428571,200400,30:51.2,15.00571429,1851200,4 +1254,6060,02:53.8,3,136.1714286,173800,30:58.1,19.22285714,1858100,4 +1255,6080,02:38.2,3,136,158200,31:04.5,20.82,1864500,4 +1256,6100,02:30.0,3,137.1714286,150000,31:10.5,20.95428571,1870500,4 +1257,6120,02:29.6,3,138.6571429,149600,31:16.4,21.24857143,1876400,4 +1258,6140,02:28.5,3,140.3428571,148500,31:22.4,21.18857143,1882400,4 +1259,6160,02:27.3,3,141.9142857,147300,31:28.3,21.90857143,1888300,4 +1260,6180,02:41.3,3,142.5714286,161300,31:34.7,17.56571429,1894700,4 +1261,6200,03:59.9,3,142.6,239900,31:44.3,15.94,1904300,4 +1262,6220,03:55.2,3,142.7428571,235200,31:53.7,17.42285714,1913700,4 +1263,6240,02:41.7,3,142.8285714,161700,32:00.2,22.17142857,1920200,4 +1264,6260,02:26.9,3,143.6285714,146900,32:06.1,22.28571429,1926100,4 +1265,6280,03:09.1,3,138.0571429,189100,32:13.6,19.39714286,1933600,4 +1267,6320,04:54.2,3,122.2285714,294200,32:51.5,14.22,1971500,4 +1268,6340,04:40.1,3,123.2571429,280100,33:02.7,16.01428571,1982700,4 +1269,6360,03:45.4,3,124.2285714,225400,33:11.7,16.48,1991700,4 +1270,6380,03:25.9,3,125.8571429,205900,33:19.9,16.66571429,1999900,4 +1271,6400,03:41.5,3,127.6571429,221500,33:28.8,16.66285714,2008800,4 +1272,6420,03:34.5,3,128.4,214500,33:37.3,17.29142857,2017300,4 +1273,6440,03:30.2,3,127.6857143,210200,33:45.8,16.38285714,2025800,4 +1274,6460,03:04.8,3,128,184800,33:53.1,16.24,2033100,4 +1275,6480,02:45.2,3,130,165200,33:59.8,17.13142857,2039800,4 +1276,6500,04:58.8,3,130.7428571,298800,34:11.7,17.76857143,2051700,4 +1277,6520,04:37.0,3,128.6571429,277000,34:22.8,17.44857143,2062800,4 +1278,6540,04:17.0,3,125.6,257000,34:33.1,15.90571429,2073100,4 +1279,6560,03:42.3,3,123.6571429,222300,34:42.0,17.48,2082000,4 +1280,6580,03:22.4,3,124.4285714,202400,34:50.0,19.24285714,2090000,4 +1281,6600,02:48.4,3,126.8285714,168400,34:56.8,20.73428571,2096800,4 +1282,6620,02:51.5,3,129.7428571,171500,35:03.6,21.06,2103600,4 +1283,6640,02:35.9,3,132.6857143,155900,35:09.9,24.12,2109900,4 +1284,6660,02:42.5,3,133.7142857,162500,35:16.4,15.77428571,2116400,4 +1286,6700,04:07.3,3,134.2285714,247300,35:34.6,11.19142857,2134600,4 +1287,6720,03:03.6,3,134.0857143,183600,35:42.0,20.16,2142000,4 +1288,6740,03:04.8,3,131.8285714,184800,35:49.4,19.37714286,2149400,4 +1289,6760,03:04.8,3,130.7714286,184800,35:56.8,18.00571429,2156800,4 +1290,6780,03:08.7,3,130.0571429,188700,36:04.3,17.85428571,2164300,4 +1291,6800,03:06.0,3,129.5142857,186000,36:11.7,18.40571429,2171700,4 +1292,6820,03:01.7,3,129.0857143,181700,36:19.0,19.38285714,2179000,4 +1293,6840,02:51.5,3,129.7428571,171500,36:25.9,18.68571429,2185900,4 +1294,6860,02:54.2,3,130.1714286,174200,36:32.8,18.47142857,2192800,4 +1295,6880,02:55.0,3,129.7428571,175000,36:39.8,18.82285714,2199800,4 +1296,6900,03:43.8,3,129.1714286,223800,36:48.8,17.32285714,2208800,4 +1297,6920,03:35.6,3,129.3428571,215600,36:57.4,16.45428571,2217400,4 +1298,6940,03:09.9,3,129.3142857,189900,37:05.0,16.78571429,2225000,4 +1299,6960,03:14.2,3,128.2571429,194200,37:12.8,18.57428571,2232800,4 +1300,6980,03:18.8,3,127.3428571,198800,37:20.7,18.82,2240700,4 +1301,7000,03:27.4,3,127.7428571,207400,37:29.0,18.33428571,2249000,4 +1302,7020,03:06.0,3,127.9142857,186000,37:36.5,16.97142857,2256500,4 +1303,7040,03:07.5,3,127,187500,37:44.0,17.31428571,2264000,4 +1304,7060,03:05.2,3,126.0857143,185200,37:51.4,15.52857143,2271400,4 +1305,7080,03:42.7,3,126.1714286,222700,38:00.3,15.28285714,2280300,4 +1306,7100,03:29.4,3,126.8285714,209400,38:08.6,16.79714286,2288600,4 +1307,7120,03:10.2,3,126.5714286,190200,38:16.3,18.70571429,2296300,4 +1308,7140,03:19.2,3,126.9428571,199200,38:24.2,17.78285714,2304200,4 +1309,7160,02:56.2,3,128.4857143,176200,38:31.3,18.33142857,2311300,4 +1310,7180,02:53.8,3,129.7428571,173800,38:38.2,20.31714286,2318200,4 +1311,7200,02:55.8,3,129.1714286,175800,38:45.3,20.25714286,2325300,4 +1312,7220,02:43.7,3,129.3428571,163700,38:51.8,20.09714286,2331800,4 +1313,7240,02:42.9,3,130.6571429,162900,38:58.3,20.16571429,2338300,4 +1314,7260,02:39.4,3,132.1714286,159400,39:04.7,20.67142857,2344700,4 +1315,7280,02:35.9,3,132.5714286,155900,39:10.9,21.14857143,2350900,4 +1316,7300,02:41.3,3,133.6857143,161300,39:17.4,20.89142857,2357400,4 +1317,7320,02:35.9,3,135.6571429,155900,39:23.6,20.22285714,2363600,4 +1318,7340,02:37.8,3,137.9142857,157800,39:29.9,20.23428571,2369900,4 +1319,7360,02:37.0,3,139.0857143,157000,39:36.2,20.97142857,2376200,4 +1320,7380,02:36.7,3,140,156700,39:42.5,20.93714286,2382500,4 +1321,7400,02:35.1,3,141.1714286,155100,39:48.7,20.72571429,2388700,4 +1322,7420,02:43.3,3,141.5714286,163300,39:55.2,19.34571429,2395200,4 +1323,7440,02:59.3,3,141.3428571,179300,40:02.4,19.09714286,2402400,4 +1324,7460,03:03.6,3,140.9142857,183600,40:09.7,19.59142857,2409700,4 +1325,7480,02:40.6,3,140.9142857,160600,40:16.1,21.23142857,2416100,4 +1326,7500,02:48.8,3,141.2571429,168800,40:22.9,21.16571429,2422900,4 +1327,7520,02:39.0,3,141.8285714,159000,40:29.3,21.35428571,2429300,4 +1328,7540,02:33.9,3,141.9142857,153900,40:35.4,21.19142857,2435400,4 +1329,7560,02:47.6,3,141.0857143,167600,40:42.1,20.27428571,2442100,4 +1330,7580,03:02.0,3,140.1714286,182000,40:49.4,19.01714286,2449400,4 +1331,7600,03:09.5,3,138.4857143,189500,40:57.0,16.88,2457000,4 +1332,7620,03:34.9,3,136.6,214900,41:05.6,14.68,2465600,4 +1333,7640,03:27.4,3,134.5714286,207400,41:13.9,15.78285714,2473900,4 +1334,7660,03:04.8,3,133.3428571,184800,41:21.3,18.14857143,2481300,4 +1335,7680,03:11.8,3,131.8285714,191800,41:28.9,18.93428571,2488900,4 +1336,7700,03:24.3,3,129.8285714,204300,41:37.1,20.09714286,2497100,4 +1337,7720,03:25.9,3,127.2571429,205900,41:45.3,22.05428571,2505300,4 +1338,7740,03:39.2,3,124.7428571,219200,41:54.1,20.40571429,2514100,4 +1339,7760,04:09.6,3,123.3428571,249600,42:04.1,17.76,2524100,4 +1340,7780,03:13.8,3,122.8285714,193800,42:11.8,17.50857143,2531800,4 +1341,7800,03:03.2,3,122.7428571,183200,42:19.2,18.88571429,2539200,4 +1342,7820,02:44.5,3,123.6857143,164500,42:25.7,19.37142857,2545700,4 +1343,7840,02:35.5,3,125.5714286,155500,42:32.0,19.36,2552000,4 +1344,7860,02:46.4,3,126.6571429,166400,42:38.6,18.94571429,2558600,4 +1345,7880,02:53.1,3,126.5142857,173100,42:45.5,18.05714286,2565500,4 +1346,7900,02:58.5,3,127,178500,42:52.7,18.42571429,2572700,4 +1347,7920,02:50.7,3,127.5714286,170700,42:59.5,19.13428571,2579500,4 +1348,7940,03:16.1,3,127.4285714,196100,43:07.3,18.88857143,2587300,4 +1349,7960,03:12.6,3,126.6571429,192600,43:15.0,17.72285714,2595000,4 +1350,7980,03:09.9,3,127.4571429,189900,43:22.6,17.56571429,2602600,4 +1351,8000,03:21.2,3,120.9428571,201200,43:30.7,17.82571429,2610700,4 +1352,8020,03:07.1,3,119.8,187100,43:38.2,17.67142857,2618200,4 +1353,8040,02:55.0,3,122.6,175000,43:45.2,17.52571429,2625200,4 +1354,8060,03:00.5,3,128.0285714,180500,43:52.4,19.36571429,2632400,4 +1356,8100,03:02.8,3,125.4,182800,44:11.9,19.29714286,2651900,4 +1357,8120,02:57.0,3,125,177000,44:19.0,18.31428571,2659000,4 +1358,8140,03:05.6,3,124.5142857,185600,44:26.4,18.44285714,2666400,4 +1359,8160,03:12.6,3,124.5714286,192600,44:34.1,18.39142857,2674100,4 +1360,8180,03:02.0,3,123.8285714,182000,44:41.4,15.79714286,2681400,4 +1361,8200,03:57.5,3,122.3428571,237500,44:50.9,15.76,2690900,4 +1362,8220,03:24.3,3,122.0857143,204300,44:59.1,17.60571429,2699100,4 +1363,8240,03:09.9,3,122.5714286,189900,45:06.7,19.90857143,2706700,4 +1364,8260,02:55.4,3,123.3428571,175400,45:13.7,19.60857143,2713700,4 +1365,8280,02:48.8,3,125.1714286,168800,45:20.5,20.53428571,2720500,4 +1366,8300,02:45.6,3,127.5714286,165600,45:27.1,21.03714286,2727100,4 +1367,8320,02:48.8,3,129.0857143,168800,45:33.8,20.94,2733800,4 +1368,8340,02:45.2,3,130.3428571,165200,45:40.4,20.74285714,2740400,4 +1369,8360,02:44.5,3,131.4857143,164500,45:47.0,21.22285714,2747000,4 +1370,8380,02:44.1,3,132.4285714,164100,45:53.6,20.41428571,2753600,4 +1371,8400,02:46.8,3,132.5714286,166800,46:00.3,20.10857143,2760300,4 +1372,8420,02:39.4,3,133.6857143,159400,46:06.6,20.84,2766600,4 +1373,8440,02:49.9,3,134.2285714,169900,46:13.4,19.14857143,2773400,4 +1374,8460,03:00.9,3,134.4285714,180900,46:20.7,18.04285714,2780700,4 +1375,8480,02:56.6,3,134.0857143,176600,46:27.7,17.96285714,2787700,4 +1376,8500,02:55.0,3,133.4857143,175000,46:34.7,19.39428571,2794700,4 +1377,8520,02:56.2,3,132.5142857,176200,46:41.8,19.5,2801800,4 +1378,8540,02:53.8,3,131.7428571,173800,46:48.7,19.76285714,2808700,4 +1379,8560,02:46.4,3,132.4285714,166400,46:55.4,19.37714286,2815400,4 +1380,8580,02:42.5,3,132.3142857,162500,47:01.9,19.22571429,2821900,4 +1381,8600,02:57.0,3,131.3428571,177000,47:09.0,19.37428571,2829000,4 +1382,8620,03:09.9,3,130,189900,47:16.5,19.66571429,2836500,4 +1383,8640,02:49.9,3,130.3428571,169900,47:23.3,18.85714286,2843300,4 +1384,8660,02:46.4,3,130.4,166400,47:30.0,19.05714286,2850000,4 +1385,8680,02:50.3,3,129.0857143,170300,47:36.8,17.12285714,2856800,4 +1386,8700,02:58.1,3,127.4285714,178100,47:43.9,17.06571429,2863900,4 +1387,8720,03:07.9,3,126.4857143,187900,47:51.5,17.68,2871500,4 +1388,8740,02:58.1,3,126.4285714,178100,47:58.6,20.31428571,2878600,4 +1389,8760,02:55.4,3,127,175400,48:05.6,18.96857143,2885600,4 +1390,8780,03:12.6,3,127.4857143,192600,48:13.3,18.59714286,2893300,4 +1391,8800,03:05.2,3,127.2571429,185200,48:20.7,19.44,2900700,4 +1392,8820,02:58.9,3,128.8571429,178900,48:27.9,21.48857143,2907900,4 +1393,8840,02:45.6,3,130.6285714,165600,48:34.5,18.81714286,2914500,4 +1394,8860,03:02.4,3,130.7714286,182400,48:41.8,16.06,2921800,4 +1395,8880,03:28.6,3,128.5714286,208600,48:50.1,15.00857143,2930100,4 +1396,8900,03:20.8,3,127.4285714,200800,48:58.2,17.34571429,2938200,4 +1397,8920,02:52.7,3,126.8285714,172700,49:05.1,18.52571429,2945100,4 +1398,8940,02:50.3,3,127,170300,49:11.9,19.74857143,2951900,4 +1399,8960,02:54.6,3,127,174600,49:18.9,20.26571429,2958900,4 +1400,8980,02:47.6,3,126.8285714,167600,49:25.6,20.20571429,2965600,4 +1401,9000,02:43.7,3,127.2571429,163700,49:32.1,19.37142857,2972100,4 +1402,9020,02:46.0,3,129.0857143,166000,49:38.8,19.47142857,2978800,4 +1403,9040,02:57.0,3,131.8285714,177000,49:45.8,20.43714286,2985800,4 +1404,9060,02:35.5,3,133.8285714,155500,49:52.1,20.92857143,2992100,4 +1405,9080,02:28.8,3,135.3428571,148800,49:58.0,20.89714286,2998000,4 +1406,9100,02:30.4,3,136.7428571,150400,50:04.0,21.40285714,3004000,4 +1407,9120,02:26.5,3,138.0857143,146500,50:09.9,22.31142857,3009900,4 +1408,9140,02:26.9,3,138.9142857,146900,50:15.8,22.7,3015800,4 +1409,9160,02:36.7,3,140.2571429,156700,50:22.0,22.59428571,3022000,4 +1410,9180,02:30.0,3,141.7428571,150000,50:28.0,22.43142857,3028000,4 +1411,9200,02:29.2,3,143.0857143,149200,50:34.0,22.20857143,3034000,4 +1412,9220,02:27.3,3,144.2571429,147300,50:39.9,21.71142857,3039900,4 +1413,9240,02:35.5,3,146.0285714,155500,50:46.1,23.12857143,3046100,4 +1414,9260,03:08.3,3,138.9714286,188300,50:53.6,22.98857143,3053600,4 +1415,9280,04:01.4,3,126.3428571,241400,51:03.3,13.11142857,3063300,4 +1417,9320,03:36.4,3,117.5714286,216400,51:25.0,11.70571429,3085000,4 +1418,9340,03:51.3,3,119.9142857,231300,51:34.3,19.73714286,3094300,4 +1419,9360,03:22.0,3,122.0857143,202000,51:42.3,18.46857143,3102300,4 +1420,9380,03:16.1,3,125.7142857,196100,51:50.2,15.80285714,3110200,4 +1421,9400,03:25.9,3,118.5714286,205900,51:58.4,16.25428571,3118400,4 +1423,9440,03:14.2,3,110.0285714,194200,52:23.5,20.32285714,3143500,4 +1424,9460,02:58.9,3,118.1428571,178900,52:30.7,19.28285714,3150700,4 +1425,9480,02:50.3,3,122.3142857,170300,52:37.5,17.68,3157500,4 +1426,9500,04:10.0,3,127.4571429,250000,52:47.5,17.38,3167500,4 +1427,9520,03:45.0,3,126.8857143,225000,52:56.5,16.28,3176500,4 diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index 039dc3180f195130f507fd2ea2d80f6ec2b9ce99..c8e1107351aae1553cc73d50275a17f91d536e0d 100644 GIT binary patch literal 11511 zcmV5Hb^v`{TaTo-aedFP(4zu0+PoIY$HY#M z0D)m70rD8ErGc}tv@5Juwv%6|U9{>LF$CrQm z`r*f)zWMg&m+$`e@y&K740y{T2TUzxwru?_WOY zYhUq}pMUk^$4~r}fBp3@U%vVF_doG1zx({>7yQScKYacAv;M^opz-qaH{bpdKl0Om zdU^RC)P7|MjM%R~|MKbU`j6jy{Q2t#rLrOY=F7)Fz5L6|r$2oCuh*~I-v7wozVm^GBK@`(JwYM}3w@ z68tnC0l$c;JtBU5#ODb05%KSy@tf8jL-1B)qMH$}{7=CF1w3 z^3O}c=S#ysV$k>YUZjoP@twC@$6t<0rsq{dW?qO_NJKdIgbV`z*PCpoN-1Y zwZanv?K&zRB_}X+;AebHHc|^yaZG*jiLX8J=B!619gjLOO}goM``&#rVla1CV;MOEQm#X}G|IrOQcStmI(Wycky@Cy{cMBH`I;iW#>k*FqK! zy-;Gr7OLi`o}H;QwEWC_Km4$AsOh5OIj4Kcx;?Ld{1on9A5#iwpn?>wJ4#afFsMiAz_H2Qeq2LcT{*f;~|7qo|5^=I7$i6Sl0Ogl}uFeG03Z`2iQ9g zP$sCtKOGxXO438D1sso%fsuQ`0cJ2Kjy|Xln$cRI#s&p>8wM7CJe~sj6^aA8@QFWk zR`EkXs!|D&SHn(_S1Lm5@KW-U|h9An=L9sBPsL z99MnH)SgfaiHZPff=U`ccjp#WB9SHN_y~@v@_h0{RadD-Z`9}!Dpw}7)JBX@OW+hf zyWoNZD6tAMA+!iZNMuTGBa4mieyUd({6=RgW2Ji#Yu7edRb-bt+r{x|{J-~}sS zW^!nOpdig@Lc<{fX{U~W_AHRjlJS_h{$O{+!9Mf^jN(SO^?Sqn)WlI`g4fRg+EFhs zuEW^Z3?GuKqQjrzXM7-7Xq;<$re(s*%DFhl zZg|<@6(Ul2P+x%p5tH7T3`M!D5ui~hg#;TF-~~@5At^l3cgq$9kp$*7mFbx?66{1-fqARQtC*1<z;wsNPZSqZd!MedzWuWou&a zPJk$Pd~Sxd$?y#z6?g|c+GM_2n-n)XHxUq1ndk;BF8D>aljtHodohnjqbj><|*4!-ZBeg4p+M1-a{;K~4zF}ICeNmZQV+Mk6N!V%q=6gN7z77*0w+u}ud zY9VUyP?Q8jU>+@QTa9W^aMgjC=HQvj9QA1QjH-O8K=RoU{{6<$@f60;sI1Jc3R zLftzM+~CSom;2@+hQZB5@EI@G4VV^0gGs?Hf*YJ$j5?+~<248!sHHll!H{->OA{QF z7K1DEqlhj!I+=gza?v5?xOfNzGWgTLznWeNMx7)#IyV>yVDg057?;q(nm0symR`Xt z)1ak(!Xxu~m~uh4qn-Aw3!-?K4ah~MnLsS{s0bZW#a&gokV$gGbBh5{4Q5L4A{0KJ zGIjMOX)(51;Z;x$F}Znd(NURQTu%SDZlNl?S(&jlWP$_XY)0%AOP3Q6Un zO`02@+YDH`HrWSPygV!O6G0uS%<#`8qlSf#VZY;Bmv70f{b_M`rFY!M+Nxf@1cwmv zUI&8K0U4puNQ>sqIJnUOUyI?xi%{jD3GY>zko79&lYi>#Ask^yroMy2>j(R?3vLb2 zDX_c1bg&P>G{gjfyxzVsNp5&^|{er>s(DXx$D!5E<`04WUnKy-hrZ=Z+{t6C> zD(KKFuxY)FP-$}MGG*y-T}0p}R=DZ)H3wTxU?Qbw+uQ94?PK^xY4=IfFC0>os=2H6}sC|?Pg{k zZaM^0?Wwods3eH4)>AgZJlv|$lkCIA^}%^Y-aV>b@D9d_nJb)oqiBFFMsmY*lL2YX zrj+q7OEam%Z6-G_=82hHgNJ|CzwQxGDTPDx6`1=z^zM0LqEd;$?<;z^dD7hY+-N{r z!(<<6YD}9MbsIo=1#nECAZw@*^LzZ8V(&gdMy!!qGvOe~M%hhFT7|9*ER*I2=!T;U zQ7AytWYmYB^5kGFC%{bahdw5rp}pbY3^uxjCN3Uum8Di_WIP-kIK+-n0SGM-3;??_ zuuhU2pPP=ZX%xlBPZWj_x#h{gvYnQu;ydvnR)2f{(u8LQdmnHUXr-RPN5F$W9_j$o z$iEt(@f4p-k{h4f4!kc<eXxS-wGk#lSdygA(5ORb%;8@%H*){{==OXe5sN zF8JVddwn2nGaaJK1IikWOcm4Ad?a&A@fM9aT01!y<`MIFq60+8 zJp}#>JlhNhs>abWuOOIN7^EA(a%F+awjcP^rx2Q_pFljMe%93In71}|BdpYhWQyhc6o#fh&mBlE_< zS(>(49wZ%MN9c$#bEWP_fLH>(Du@W!57?S#CliyL{L2nd{ZXrPXt2t^$TB1H9M=JN zJK!??gQ7O1$r)6Z>Hp>1vxgb0FuR2}kSOR>$?e$_pwip`ivt|HJW(v4)$o%{BUkgm zK?1Dn2Hv5EE9tJDbBP}HmQo-lLl}B6Fa#8EkT(#qu1W|kiIUv-wh`&@9HtHCi+FIz zLaBx?GL<*+(K!{v*Ky88E*(=(Bf`^hB}mz=;9Q{iL-*t{B6ulG26jZmWdf`hKyiSD zWUNA?m~g1@$Dj5ea^kD>#Oaj)pW2WlZzV(@4bH$$_Kg8Y6ka|5_QvL?+K1-Fq2CMx-6O-;5H)A{438~EO|?z@5Aano_0}y8Y++^GlK-!-;K<*%I6;b zpm4*FuFTQ1X4DgtrS%ElK}7NONpj;GjxSBmx|nSu=`juI368adZqe+chPSEQa#*;o z;4~O0sp4`pmJKco2SLe{>WNNC?n+*8bd|{qt(s_hg*8Q7+NA)`(~T1!v`V#{)#YLp zKi%vF4ur3kY9{l}(?$3O)vXl{Jg1S|_}qRZEw8e2t)B9e=*Dyq@+lix!x$V^e$?dY z(&^uCbowxd^%#iD%h0q2&=tf=U>;&J9D3E95FXtqZg6frvibdy|AYH8+N0($or6|S zbWx)iTIZVGw5`ZI9ry0=?nQ9vA+q%D{oX-PVez_p_sk>YGw`i$Ihb>7iZ1Ch3lq94 zux#x>SNcT9vp*^vE3zDi^Jj?zD>*QA&@&xc_x*%srv%a1i15l8SXQ?iv?m5H^YobG zsCB_B?KT@(JuBQhwHj$fZe@q%qIV)4u6==R4e+ab)Y|{Zp_2PRS_xaZmnX>$&&>v% zNWF8K&WBmVdnL@oQ;#RSGU3thkR6tgTNR`XsqKE!<|*WML)S0-|Ua5#rJrRmQqfRu;7xJg7#Ae*5l} zn!f$4!}N^vg&>S^7RApp447pkH#|2PwOUjewLIMv5<})b9rFWT)bN>R0Pj$E?_?y$ zj8?YCES3Eruoa@IfyOvU)TK|YH*He^w~XY*=T@UK@oV@ZdBD1dSPd_0k>NPrs_`=w zj+ou3XVPkT$d(U>dElbaAEiO`kPTq?Esw7BXK^+^)ev>5$$=ccL)pukgw!yQ~dX#kWXqd~P@->+4ZV)R1s`6E#hD zFYJ7H*OXsYcQ4}|E*s#Ux3qP8Ft3fnc}aZX#64u5gPl_9z+YS6h zoR^Qq!lXwhdU@EHaG+zVlKxc3XNq_QRnCm0B}@;^huaNTG)A^=N zAu}TxwMN}5eN379OOr(hzC7_!wX`c89(TUEM?GBcmcqG0!9g}y#sZ3(5Pp~}2vJXb z?d%B@Hyki1WuC6J6oMzx=_qUe!s+o5pVoL0k4wLz$#mkgjM~yIxZV+hn;J`qUV%>R zr>uk76CQ?<-1yvb&`B$Xj~$#EK*-3mme1x_-^CAAF>ZuR_DYLkYd! z*H2h!h}uF0ei_XT&`k$(#KQmr6N?c20WV_$^a?%!YH9?(f_$`abr_@#uqo>xi@c#l zAE&nlH&yfKP_+d=(=~uwgdi@eTPlm@ZisW^(bQfjKo+ZoZdQwB3COyEw65${h?9dY zx`g2Acl!tqs%ncte2;;=PKkX*LKc&i3U5q`8=f1Fo~)b|wQpc_`q1nZ8YUoe1VkGi z{=BL6kaYnMC6{UbAqk#^6@$orXU{*<(H4UyI2&R z8;{w51>bMZ(;nlPVB@dYs$IqD~9 z!am@RDfbr5jn9n-BsNZbS=(L*yDGPLezH%>1lZ~9T>#T|4ov?Q@6o_zfUAr<$U?E} zKW1{^;nOu}c~ac)+M$tF2m>``H>eqp+n1SDB0*eGH6K+@{?+65x$TAZ z3^-gIR6TFsWqiRdqqzaP{a_Kx^fOD=F)ai< z;(^dXSn@3_G#1{vz>f5*AlLpEW=J<-WT~oEg1V@S_{EFEOS629@ z_!`rjBq^LpI1|oc7xZU%bSP&WQ3cBq>k!*LV5eG;sL6V8%P4MmZacu`I@t#(kUO9R z(`WRS&9vZbmGFNBsV^{9(4zA>|MrF@Xfu?#A)a! zzQzo;hO_uQJ>hq5pmif2rF{4@!T}iek{!vlvy>0$Msovn^HDi}X#iOYAG}s$to*E8 z46G9%Vvf--fW=Q(U6&$Wml=aC_K~qYuV7#SpBXjsa%kfRkHctgfNnq_w0&wAb`hti zW^KbbYL<>LGRv+t%b^COo$XBdC~GyZ%bX=kFKfXP!^#AXx$0qr)4v*SLFlRt9SCN# zbA4(-D6M86&Xb`-e$pEGhj-ut!&Xl3^;0Lg+;OtoIY^;IN)PcKA)u#d7 zh{&7+NE*SZmcfxMJ73pOr(&$E1F$m4_b}bh2-!>eqfRDTGr-Q@<8ovub}K%?IEPV7 z(rOXAn^a0RQHSVu1d^*sUJi0Yz@FM`Q__UkE;ec{fDkF8>AHs(8*RpGYnlLM0XJWG z2A;y_NKTQVibeq$RmbSIL^SZ#0byV)8k+@E6~tH;8>_L=F!DWWPR4Z?>lEf>4Gf!& z0bWjp7&6clMwe_k6|IYNuy0|k`J508Zc*5ptwZtJ!ma*H3{vKC?TK~8*jTgRb!?g^ zjhfMYebSa}I}~=#oOX^{NZHA@t2fLJMTt5@w<+wbG>NI&Vy-uBHsV$tPjxoZ57x6Y ze~K;D%O%vK7B96%?|u>Z)IAC~*v?XGrBHFGNQa{IRN6IZ8QiYW4>6H}RvcOD_o2(| zC#dIHv$c>QrPw$>MMh4L!_PXqUIaWC;J{Aa>#Pyjb+&KYtZG?g9i$rrP?2nXFWRi5 zc#Nn+bPEHUuRZ07^LLCCc$=bT7_$EAz?dgS<)NCG(ci;p_hb+Ljsnet%Px2035VL* zVD2E}nPyN53uIq>cib`Xoi)ylMcIq->k+m6wmK-vTclqp_x50L)@D<9PW#ghc|J0 z+=|G^I!HG)qpaiRb54~KXOF%PJREY97D|5Xk?~q`)25O%kKH+`<=7kJ_DxXQP}fC&qk~+&!@b%a;*1 zGdXf~Nk@uMkD6FgL{Tndv**!iXrB`!`-yb?8~QcRf%LE-7SlgN8N-u#D>ivXSIU4x z{lFIs?0hPkw}wqB?D+uK=x#KJ*v`sb+(YSrn63DkbWSSj5{Vf59>?oP2uKAqtV@hX z;}PmI+N->6&7eC%NKoIYF{epA4h>S0^@3IiP`4YI7gYyY9i(iKq6=0O*33C_+4I+8_iDRI|AcGE#%vhbb{B1K{Tjm=WqKAvJ39AKL+!wg=t3RL0Z-PUI7A1RmGcbt zyhhR&b%c$Ott|#HY7a48pH#-2G1yB9v@4g@35(=;E`HKWWY(G!>*E~nbz`#Z(7LcC z2?By&h)vcLk&$(f(LrYG8%R3EQmhvsS@N9@+P2xz?xT5Ve3EoEdLQ>ui+V?CPna1) zRNNUc__*Iy+EYmB%D=}w#SWBW?aDUGQnH#F&d%D7i`GwGZj`*W`Avvjy=D0r=oBb$ zc;Hpy*|L1ib1EPs>KNV9un)xC@#*CSO~1#fA!VFR>6O)1-5A2d*%+;XZ-s|#jr;D< zE2Y#!8!SPxX}ibXUd@FmBBSac-PY&;wPIu)Sk)!$ewsp4(|Ov71y@Q9Ke28tz8ti0 ztQqNtejEk*Ce?nAMI1elipPjLM7K0~PCh4{dSGum85r{PefoHHBW1-5Nj!#~TV%F| zlxsK#F#`f>IN_?rxg@TonC{^mg=AzMrJEXV^qA_WX-%$aHmXcL?%9Bevh5q$-ss3> zvsb*aZ)8-XO&h@G#ttos!-hgEp;>^KWD#|YZfn?_WBxc>0&8RZA88iTE1Mn7X7^>Y zQ-7_2mWQTS(iR|S+tOvU{Ypw=tjVP}in1-Tj?#@ynGN+xCk>ziL=~h=4U~4UJvDi^ zM2T*UqaT^y3U^;F=+@+d1LF{C)?3f@Y)N!&P@v^8lzowPlx}Y5^4YCqPe0tvs$)Ac z4V&k|lV*R~n62y4M&5fl(-wW|$+|oLXY)FAVim1H^QM=;hSIb1UlHYNCM#yQI4rQ* zrDW^8Xnr8_;HT)EoQ#H1@1zFhuXK61cDcBkWRDAEL%o+{mkX{$;XtVFI0}oZgLI2S z&)7UkcF@bv990&JN7?M{jLd9UFn3|@0-LQG`Sf;YXp@exfs;FUjFivN=4>QZKt|Lt zy1iio-b|z6Bfte!2GeM8KC0<^Sn?8+ek2I&4?f zNFfa?;__bKT0_z5wJB;N9~B&+Upk7Pv$ zF4^3!9T=^0atNLp7tWboR6Ow_5F(2c6;evqophT6_bALe$zBUlStypA%~~e8tamRfzOnK6 zUQcaareUT4YUAB(w4osTJS3r9Ok}cD7bJKQRi64QhY#E9= zEqBZ(AG7Yg1Y<0)eOLeV;2Zg-NrYU(_GwoyH&(L3Q0~6UiRfB0S=`)k8>N{WcI}R? z{Ul`$d={VOS4P$eGTTb5!w1S+llQsV#_e`Q&;@lq7+&);03hJ~|y>C`G$8>!p3fIXPx0_eKeSCkf=6UYcj1&(#-m?a|rF z7>nDQku7hUb$f$G+I6S$Lp@WH+IXWk%+{TRxqE6!_Bi&hRJYo2d~zzH5Pkm&2hZ3; zXimAV$GKDa#f=RI2)gZS2F9#jHb-K^E6KJK8DUFyb5C+b4(A4kqa1sR_PN2q%dvCA z%Q?avi<_D;tm`eS0;-I4Vl8J*ARL*r5tg@WGxR%7Y^P(9uDbh`6!3w*v+zC#wyvbW zo}y1N%yb`&F)->xY2?IRe#J+Vnh`f2-?21HMe6e$hkdF@_6sKV%rLhbdKatF+0ffn zZP=sqNmtDl1<9QhQA1e-NYfnVdZ%_rvYm;R$+%OJ>##K?d3b2Fd61gKI5MAI25VyhRh_$c-kQTvra83v`f=_`oqTMnecG`r^)QE} z(onNk;4UQEAWgXrJ3B^pg)2r*v*@~$C_$F?Nq277Fj8u4%6=C_#H*dwE?G~E97#raNRf^nET4Gk5d!&t#b&++H;wY<)MzF{M=R$j#qvTaYANfwL409ug z?Vfv`wrIz?K2HF(P`O4mv#tHwc6cU$>L%+bo1^R-C0(G(0Xy89U4p+-r~KA}<&f7S zuvsQC9i5QAP#t12O3gNf<(-fc=nHjQsIHKVtfO>$L)|*D+79+M-S?Hl& z8tt`>;*WO=O#QBI_Yx}1a@PXZv9S3pZ!5}n?t+No7AH5Gh{?K+yK2jPWK*RH&)(>- zC8hr4!K+ieol+^s_P&weN7cYBrrO z`DEovM8{V}&m%EexMQqwH^*J|bh3`ptxl;MC9a2P?{I`&dD?=eacvc{E;ro_u2TW8 z8YO4$Vos4A`%?n^My5|xdVGqEqv)J?GnjeNb(n5R?s7Ob-i?DVV!PL`Ky?y5*^}Yh2ee7WjE|Gg@A$fi6qL z*O8}{2eO&{{*Ls>ywl;`I`?iEpt>AfbfGBgBI_vK^3-CfXkCI>ntnM*Su;pFY>^Dkh`rFx~WsZXr>a+@ofhKTf=w z>1p}a>Q+B8wLY#AN#8I<`z6!Sq}FreYNRx*c?+hCt&+?~XPnF2!`~KNhv~*g@`lL; zXv1JmeWJbZK1--M$+BEG8|F`MizIO_Njf~Y#BTDYeNpV^X@PtHuZ8!7WMuu@4BYt0 zO#g9b_M>nhi)Y^3-1)J;=VPPX4yH}?mvP?AWqs1Mh4+G~W5y7gS8I3`lhJjUZhg4- z!crLw*x97Wry6ah@zOchuL2|%RqLGGx%%Q*)>>yfohMx26mfeZy`rOifK4jQVyVMH zOh(sXy8Xck)yYlRA3PtU*B<&CQ+~rF%kwpaajYDTT2l^wHBT!U$--21j~LjVSw>Nq zY0-6Gp@^HVe)Y><<@a@S#$l3Dt5g>rngCmi@7D|8gnK;u3VOAB6(w zrMA%OB|+!@QN?6*9j05L9#&E#b4Q@5qi$nmS-*S8nW^f?yiDF-c>{CgW67r+PKPAe zY`PuSl2756BNegqG%*=nhv_D$r=&vw?Po?X8H*Ct%hn}WiqdqC#f}wn6(LahCj9k zpw_opYV)hkzS%QN?UlSMvLGZQ>nPm>F~wdP!=9yPM7Os`*PG_HJGck{zKz&vg)&n()! zHbR->Eh=vdaP1!*V0=7L(jTT+S+qDQkhI+a{9o&8H<>V zuEWd@GjDF<50mZW8)@aVN<4gay_S~0x#_U3PYz_jYf3 z6WGhjFSb*)PDn=9QC3H(Unrs}b$)SP)vkw8);Ci1tAV6UnCczK+v3FCF65ykT#h^j zP3zGvbfsDQrs^QK?a@6m*+549hBx{fqmCJ*)qZ!mMEe>KbxPW+c0kvb7D>8=Y`u;u zlJD=3VSy5IZOH@j&B!{+<|ymR!>}9NuKchsCe6AP?kefUXucbbZhxH(_WrPRRqLT! z1^O!_-Hzi1@+{YrZ${QZb_dy48U}WyT0{IM3nt0=EB1TclYm|HX#kL9b^xk}6ymmz( z@a&bNs^iWFAFCpiacdA~eH&SDl-a&lSN8~2dQL?PORE!qoW;kced4;XnY!)&MR|5k dgL#=-cIyT6?wnRB4QKiB{{YL={$!AP003)qd%pkx literal 7866 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 Yr{S&QKZM-J<7zAXKV-GNzZg^i0KsbzivR!s diff --git a/rowers/tests/tests.py b/rowers/tests/tests.py index 9a298642..b83d27fa 100644 --- a/rowers/tests/tests.py +++ b/rowers/tests/tests.py @@ -86,7 +86,7 @@ class NewUserRegistrationTest(TestCase): form = RegistrationFormUniqueEmail(form_data) self.assertTrue(form.is_valid()) - response = self.c.post('/rowers/register', form_data, follow=True) + response = self.c.post('/rowers/register/', form_data, follow=True) self.assertRedirects(response, expected_url='/rowers/me/gdpr-optin/?next=/rowers/list-workouts/', @@ -408,7 +408,8 @@ class ViewTest(TestCase): @patch('rowers.dataprep.create_engine') def test_upload_view_sled(self, mocked_sqlalchemy): - self.c.login(username='john',password='koeinsloot') + login = self.c.login(username='john',password='koeinsloot') + self.assertTrue(login) filename = 'rowers/tests/testdata/testdata.csv' f = open(filename,'rb') @@ -429,7 +430,7 @@ class ViewTest(TestCase): f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -437,14 +438,14 @@ class ViewTest(TestCase): response = self.c.get('/rowers/workout/1/', form_data, follow=True) self.assertEqual(response.status_code, 200) - response = self.c.get('/rowers/workout/1/edit', form_data, follow=True) + response = self.c.get('/rowers/workout/1/edit/', form_data, follow=True) self.assertEqual(response.status_code, 200) - response = self.c.get('/rowers/workout/1/histo', form_data, follow=True) + response = self.c.get('/rowers/workout/1/histo/', form_data, follow=True) self.assertEqual(response.status_code, 200) - response = self.c.get('/rowers/workout/1/workflow', + response = self.c.get('/rowers/workout/1/workflow/', follow=True) self.assertEqual(response.status_code, 200) @@ -465,7 +466,7 @@ class ViewTest(TestCase): } form = WorkoutForm(data=form_data) self.assertTrue(form.is_valid()) - response = self.c.post('/rowers/workout/1/edit', form_data, follow=True) + response = self.c.post('/rowers/workout/1/edit/', form_data, follow=True) self.assertEqual(response.status_code, 200) @@ -518,7 +519,7 @@ class ViewTest(TestCase): f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -560,7 +561,7 @@ class ViewTest(TestCase): f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -629,7 +630,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -679,7 +680,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -716,7 +717,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -755,7 +756,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -791,7 +792,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -828,7 +829,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -867,7 +868,7 @@ class ViewTest(TestCase): response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -903,7 +904,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -936,7 +937,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -969,7 +970,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1002,7 +1003,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1036,7 +1037,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1068,7 +1069,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1100,7 +1101,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1132,7 +1133,7 @@ class ViewTest(TestCase): form = DocumentsForm(form_data,file_data) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', status_code=302,target_status_code=200) self.assertEqual(response.status_code, 200) @@ -1169,7 +1170,7 @@ class ViewTest(TestCase): # form_data, follow=True, # format='multipart') # f.close() -# self.assertRedirects(response, expected_url='/rowers/workout/1/edit', +# self.assertRedirects(response, expected_url='/rowers/workout/1/edit/', # status_code=302,target_status_code=200) # self.assertEqual(response.status_code, 200) diff --git a/rowers/urls.py b/rowers/urls.py index f37951da..f4d2aa88 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -108,9 +108,9 @@ urlpatterns = [ url(r'^o/authorize/$', base.AuthorizationView.as_view(), name="authorize"), url(r'^o/token/$', base.TokenView.as_view(), name="token"), url(r'^', include(router.urls)), - url(r'^api-docs$', views.schema_view), + url(r'^api-docs/$', views.schema_view), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/workouts/(?P\d+)/strokedata$',views.strokedatajson), + url(r'^api/workouts/(?P\d+)/strokedata/$',views.strokedatajson), url(r'^500v/$',views.error500_view), url(r'^502/$', TemplateView.as_view(template_name='502.html'),name='502'), url(r'^500/$', TemplateView.as_view(template_name='500.html'),name='500'), @@ -118,244 +118,244 @@ urlpatterns = [ url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'), url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'), # url(r'^imports/$', views.imports_view), - url(r'^exportallworkouts/?$',views.workouts_summaries_email_view), - url(r'^update_empower$',views.rower_update_empower_view), - url(r'^agegroupcp/(?P\d+)$',views.agegroupcpview), - url(r'^agegroupcp/(?P\d+)/(?P\d+)$',views.agegroupcpview), - url(r'^ajax_agegroup/(?P\d+)/(?P\w+.*)/(?P\w+.*)/(?P\d+)$', + url(r'^exportallworkouts/?/$',views.workouts_summaries_email_view), + url(r'^update_empower/$',views.rower_update_empower_view), + url(r'^agegroupcp/(?P\d+)/$',views.agegroupcpview), + url(r'^agegroupcp/(?P\d+)/(?P\d+)/$',views.agegroupcpview), + url(r'^ajax_agegroup/(?P\d+)/(?P\w+.*)/(?P\w+.*)/(?P\d+)/$', views.ajax_agegrouprecords), - url(r'^updatefitness/(?P\w+.*)/(?P\d+)$',views.fitness_metric_view), - url(r'^updatefitness/(?P\w+.*)$',views.fitness_metric_view), - url(r'^updatefitness$',views.fitness_metric_view), - url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)m$', + url(r'^updatefitness/(?P\w+.*)/(?P\d+)/$',views.fitness_metric_view), + url(r'^updatefitness/(?P\w+.*)/$',views.fitness_metric_view), + url(r'^updatefitness/$',views.fitness_metric_view), + url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)m/$', views.agegrouprecordview), - url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)min$', + url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)min/$', views.agegrouprecordview), - url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)$', + url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/$', views.agegrouprecordview), - url(r'^list-workouts/ranking$',views.workouts_view,{'rankingonly':True}), - url(r'^list-workouts/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workouts_view), + url(r'^list-workouts/ranking/$',views.workouts_view,{'rankingonly':True}), + url(r'^list-workouts/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view), url(r'^list-workouts/team/(?P\d+)/$',views.workouts_view), url(r'^(?P\d+)/list-workouts/$',views.workouts_view), - url(r'^(?P\d+)/list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workouts_view), + url(r'^(?P\d+)/list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view), url(r'^list-workouts/user/(?P\d+)/$',views.workouts_view), url(r'^list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.workouts_view), - url(r'^list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workouts_view), - url(r'^virtualevents$',views.virtualevents_view), - url(r'^virtualevent/create$',views.virtualevent_create_view), - url(r'^virtualevent/createindoor$',views.indoorvirtualevent_create_view), + url(r'^list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view), + url(r'^virtualevents/$',views.virtualevents_view), + url(r'^virtualevent/create/$',views.virtualevent_create_view), + url(r'^virtualevent/createindoor/$',views.indoorvirtualevent_create_view), url(r'^raceregistration/togglenotification/(?P\d+)/$', views.virtualevent_toggle_email_view), url(r'^indoorraceregistration/togglenotification/(?P\d+)/$', views.indoorvirtualevent_toggle_email_view), - url(r'^virtualevent/(?P\d+)$',views.virtualevent_view), - url(r'^virtualevent/(?P\d+)/edit$',views.virtualevent_edit_view), - url(r'^virtualevent/(?P\d+)/editindoor$',views.indoorvirtualevent_edit_view), - url(r'^virtualevent/(?P\d+)/register$',views.virtualevent_register_view), - url(r'^virtualevent/(?P\d+)/registerindoor$',views.indoorvirtualevent_register_view), - url(r'^virtualevent/(?P\d+)/adddiscipline$',views.virtualevent_addboat_view), - url(r'^virtualevent/(?P\d+)/withdraw/(?P\d+)$',views.virtualevent_withdraw_view), - url(r'^virtualevent/(?P\d+)/withdraw$',views.virtualevent_withdraw_view), - url(r'^virtualevent/(?P\d+)/submit$', + url(r'^virtualevent/(?P\d+)/$',views.virtualevent_view), + url(r'^virtualevent/(?P\d+)/edit/$',views.virtualevent_edit_view), + url(r'^virtualevent/(?P\d+)/editindoor/$',views.indoorvirtualevent_edit_view), + url(r'^virtualevent/(?P\d+)/register/$',views.virtualevent_register_view), + url(r'^virtualevent/(?P\d+)/registerindoor/$',views.indoorvirtualevent_register_view), + url(r'^virtualevent/(?P\d+)/adddiscipline/$',views.virtualevent_addboat_view), + url(r'^virtualevent/(?P\d+)/withdraw/(?P\d+)/$',views.virtualevent_withdraw_view), + url(r'^virtualevent/(?P\d+)/withdraw/$',views.virtualevent_withdraw_view), + url(r'^virtualevent/(?P\d+)/submit/$', views.virtualevent_submit_result_view), - url(r'^virtualevent/(?P\d+)/submit/(?P\d+)$', + url(r'^virtualevent/(?P\d+)/submit/(?P\d+)/$', views.virtualevent_submit_result_view), url(r'^virtualevent/(?P\d+)/disqualify/(?P\d+)/', views.virtualevent_disqualify_view), url(r'^list-workouts/$',views.workouts_view), url(r'^list-courses/$',views.courses_view), - url(r'^courses/upload$',views.course_upload_view), + url(r'^courses/upload/$',views.course_upload_view), url(r'^workout/addmanual/$',views.addmanual_view), url(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select), - url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.team_comparison_select), + url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/$',views.team_comparison_select), - url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.team_comparison_select), + url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select), url(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select), - url(r'^team-compare-select/workout/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.team_comparison_select), + url(r'^team-compare-select/workout/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select), - url(r'^team-compare-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.team_comparison_select), + url(r'^team-compare-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/workout/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/team/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/user/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/$',views.team_comparison_select), - url(r'^workouts-join-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workouts_join_select), - url(r'^workouts-join$',views.workouts_join_view), + url(r'^workouts-join-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select), + url(r'^workouts-join/$',views.workouts_join_view), url(r'^workouts-join-select/team/(?P\d+)/$',views.workouts_join_select), - url(r'^workouts-join-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workouts_join_select), + url(r'^workouts-join-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select), url(r'^workouts-join-select/$',views.workouts_join_select), url(r'^user-boxplot-select/user/(?P\d+)/$',views.user_boxplot_select), url(r'^user-boxplot-select/$',views.user_boxplot_select), - url(r'^user-multiflex-select/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.user_multiflex_select), + url(r'^user-multiflex-select/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.user_multiflex_select), url(r'^user-multiflex-select/user/(?P\d+)/$',views.user_multiflex_select), - url(r'^user-multiflex-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.user_multiflex_select), + url(r'^user-multiflex-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.user_multiflex_select), url(r'^user-multiflex-select/$',views.user_multiflex_select), url(r'^list-jobs/$',views.session_jobs_view), url(r'^jobs-status/$',views.session_jobs_status), - url(r'^job-kill/(?P.*)$',views.kill_async_job), - url(r'^test-job/(?P\d+)$',views.test_job_view), - url(r'^test-job2/(?P\d+)$',views.test_job_view2), - url(r'^record-progress/(?P\d+)/(?P.*)$',views.post_progress), - url(r'^record-progress/(?P.*)$',views.post_progress), - url(r'^record-progress$',views.post_progress), + url(r'^job-kill/(?P.*)/$',views.kill_async_job), + url(r'^test-job/(?P\d+)/$',views.test_job_view), + url(r'^test-job2/(?P\d+)/$',views.test_job_view2), + url(r'^record-progress/(?P\d+)/(?P.*)/$',views.post_progress), + url(r'^record-progress/(?P.*)/$',views.post_progress), + url(r'^record-progress/$',views.post_progress), url(r'^list-graphs/$',views.graphs_view), url(r'^fitness-progress/$',views.fitnessmetric_view), - url(r'^fitness-progress/user/(?P\d+)$',views.fitnessmetric_view), - url(r'^fitness-progress/user/(?P\d+)/(?P\w+.*)$',views.fitnessmetric_view), - url(r'^ote-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.rankings_view), - url(r'^ote-bests/user/(?P\d+)$',views.rankings_view), - url(r'^ote-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.rankings_view), + url(r'^fitness-progress/user/(?P\d+)/$',views.fitnessmetric_view), + url(r'^fitness-progress/user/(?P\d+)/(?P\w+.*)/$',views.fitnessmetric_view), + url(r'^ote-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view), + url(r'^ote-bests/user/(?P\d+)/$',views.rankings_view), + url(r'^ote-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view), url(r'^ote-bests/$',views.rankings_view), url(r'^(?P\d+)/ote-bests/$',views.rankings_view), - url(r'^(?P\d+)/ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.rankings_view2), - url(r'^ote-bests2/user/(?P\d+)$',views.rankings_view2), - url(r'^ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.rankings_view2), + url(r'^(?P\d+)/ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2), + url(r'^ote-bests2/user/(?P\d+)/$',views.rankings_view2), + url(r'^ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2), url(r'^ote-bests2/$',views.rankings_view2), - url(r'^otw-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.otwrankings_view), - url(r'^otw-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.otwrankings_view), + url(r'^otw-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view), + url(r'^otw-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view), url(r'^otw-bests/user/(?P\d+)/$',views.otwrankings_view), url(r'^otw-bests/$',views.otwrankings_view), - url(r'^ote-ranking/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.oterankings_view), - url(r'^ote-ranking/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.oterankings_view), + url(r'^ote-ranking/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view), + url(r'^ote-ranking/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view), url(r'^ote-ranking/$',views.oterankings_view), url(r'^ote-ranking/user/(?P\d+)/$',views.oterankings_view), - url(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)$',views.cum_flex), + url(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.cum_flex), url(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cum_flex), url(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/$',views.cum_flex), url(r'^flexall/user/(?P\d+)/$',views.cum_flex), url(r'^flexall/$',views.cum_flex), url(r'^flexalldata/$',views.cum_flex_data), - url(r'^histo/user/(?P\d+)$',views.histo), - url(r'^histodata$',views.histo_data), - url(r'^histo/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.histo), + url(r'^histo/user/(?P\d+)/$',views.histo), + url(r'^histodata/$',views.histo_data), + url(r'^histo/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.histo), url(r'^histo/$',views.histo), - url(r'^cumstats/user/(?P\d+)$',views.cumstats), - url(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.cumstats), - url(r'^cumstats/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.cumstats), - url(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.cumstats), + url(r'^cumstats/user/(?P\d+)/$',views.cumstats), + url(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats), + url(r'^cumstats/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats), + url(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats), url(r'^cumstats/$',views.cumstats), url(r'^graph/(?P\d+)/$',views.graph_show_view), - url(r'^graph/(?P\d+)/delete$',views.GraphDelete.as_view(),name='graph_delete'), - url(r'^workout/(?P\d+)/get-thumbnails$',views.get_thumbnails), - url(r'^workout/(?P\d+)/toggle-ranking$',views.workout_toggle_ranking), - url(r'^workout/(?P\d+)/get-testscript$',views.get_testscript), + url(r'^graph/(?P\d+)/delete/$',views.GraphDelete.as_view(),name='graph_delete'), + url(r'^workout/(?P\d+)/get-thumbnails/$',views.get_thumbnails), + url(r'^workout/(?P\d+)/toggle-ranking/$',views.workout_toggle_ranking), + url(r'^workout/(?P\d+)/get-testscript/$',views.get_testscript), url(r'^workout/upload/team/$',views.team_workout_upload_view), url(r'^workout/upload/$',views.workout_upload_view,name='workout_upload_view'), - url(r'^workout/(?P\d+)/histo$',views.workout_histo_view), - url(r'^workout/(?P\d+)/task$',views.workout_test_task_view), - url(r'^workout/(?P\d+)/forcecurve$',views.workout_forcecurve_view), - url(r'^workout/(?P\d+)/unsubscribe$',views.workout_unsubscribe_view), -# url(r'^workout/(?P\d+)/export$',views.workout_export_view), - url(r'^workout/(?P\d+)/comment$',views.workout_comment_view), - url(r'^workout/(?P\d+)/emailtcx$',views.workout_tcxemail_view), - url(r'^workout/(?P\d+)/emailgpx$',views.workout_gpxemail_view), - url(r'^workout/(?P\d+)/emailcsv$',views.workout_csvemail_view), - url(r'^workout/(?P\d+)/csvtoadmin$',views.workout_csvtoadmin_view), - url(r'^ergcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.otecp_toadmin_view), - url(r'^otwcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.otwcp_toadmin_view), + url(r'^workout/(?P\d+)/histo/$',views.workout_histo_view), + url(r'^workout/(?P\d+)/task/$',views.workout_test_task_view), + url(r'^workout/(?P\d+)/forcecurve/$',views.workout_forcecurve_view), + url(r'^workout/(?P\d+)/unsubscribe/$',views.workout_unsubscribe_view), +# url(r'^workout/(?P\d+)/export/$',views.workout_export_view), + url(r'^workout/(?P\d+)/comment/$',views.workout_comment_view), + url(r'^workout/(?P\d+)/emailtcx/$',views.workout_tcxemail_view), + url(r'^workout/(?P\d+)/emailgpx/$',views.workout_gpxemail_view), + url(r'^workout/(?P\d+)/emailcsv/$',views.workout_csvemail_view), + url(r'^workout/(?P\d+)/csvtoadmin/$',views.workout_csvtoadmin_view), + url(r'^ergcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otecp_toadmin_view), + url(r'^otwcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwcp_toadmin_view), # url(r'^workout/compare/(?P\d+)/$',views.workout_comparison_list), # url(r'^workout/compare2/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P\w+.*)/$',views.workout_comparison_view), - url(r'^workout/compare/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workout_comparison_list), - url(r'^workout/(?P\d+)/edit$',views.workout_edit_view, + url(r'^workout/compare/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workout_comparison_list), + url(r'^workout/(?P\d+)/edit/$',views.workout_edit_view, name='workout_edit_view'), - url(r'^workout/(?P\d+)/map$',views.workout_map_view), -# url(r'^workout/(?P\d+)/setprivate$',views.workout_setprivate_view), - url(r'^workout/(?P\d+)/updatecp$',views.workout_update_cp_view), -# url(r'^workout/(?P\d+)/makepublic$',views.workout_makepublic_view), -# url(r'^workout/(?P\d+)/geeky$',views.workout_geeky_view), -# url(r'^workout/(?P\d+)/advanced$',views.workout_advanced_view), - url(r'^workout/(?P\d+)/instroke/(?P\w+.*)$',views.instroke_chart), - url(r'^workout/(?P\d+)/instroke$',views.instroke_view), - url(r'^workout/(?P\d+)/stats$',views.workout_stats_view,name='workout_stats_view'), - url(r'^workout/(?P\d+)/data$',views.workout_data_view, + url(r'^workout/(?P\d+)/map/$',views.workout_map_view), +# url(r'^workout/(?P\d+)/setprivate/$',views.workout_setprivate_view), + url(r'^workout/(?P\d+)/updatecp/$',views.workout_update_cp_view), +# url(r'^workout/(?P\d+)/makepublic/$',views.workout_makepublic_view), +# url(r'^workout/(?P\d+)/geeky/$',views.workout_geeky_view), +# url(r'^workout/(?P\d+)/advanced/$',views.workout_advanced_view), + url(r'^workout/(?P\d+)/instroke/(?P\w+.*)/$',views.instroke_chart), + url(r'^workout/(?P\d+)/instroke/$',views.instroke_view), + url(r'^workout/(?P\d+)/stats/$',views.workout_stats_view,name='workout_stats_view'), + url(r'^workout/(?P\d+)/data/$',views.workout_data_view, name='workout_data_view'), - url(r'^workout/(?P\d+)/otwsetpower$',views.workout_otwsetpower_view), - url(r'^workout/(?P\d+)/interactiveotwplot$',views.workout_otwpowerplot_view), - url(r'^workout/(?P\d+)/wind$',views.workout_wind_view), - url(r'^workout/(?P\d+)/image$',views.workout_uploadimage_view), - url(r'^virtualevent/(?P\d+)/compare$',views.virtualevent_compare_view), - url(r'^virtualevent/(?P\d+)/image$', + url(r'^workout/(?P\d+)/otwsetpower/$',views.workout_otwsetpower_view), + url(r'^workout/(?P\d+)/interactiveotwplot/$',views.workout_otwpowerplot_view), + url(r'^workout/(?P\d+)/wind/$',views.workout_wind_view), + url(r'^workout/(?P\d+)/image/$',views.workout_uploadimage_view), + url(r'^virtualevent/(?P\d+)/compare/$',views.virtualevent_compare_view), + url(r'^virtualevent/(?P\d+)/image/$', views.virtualevent_uploadimage_view), url(r'^virtualevent/(?P\d+)/setimage/(?P\d+)/$', views.virtualevent_setlogo_view), url(r'^logo/(?P\d+)/delete/$', views.logo_delete_view), - url(r'^workout/(?P\d+)/darkskywind$',views.workout_downloadwind_view), - url(r'^workout/(?P\d+)/metar/(?P\w+)$',views.workout_downloadmetar_view), - url(r'^workout/(?P\d+)/stream$',views.workout_stream_view), -# url(r'^workout/(?P\d+)/crewnerdsummary$',views.workout_crewnerd_summary_view), - url(r'^workout/(?P\d+)/editintervals$',views.workout_summary_edit_view, + url(r'^workout/(?P\d+)/darkskywind/$',views.workout_downloadwind_view), + url(r'^workout/(?P\d+)/metar/(?P\w+)/$',views.workout_downloadmetar_view), + url(r'^workout/(?P\d+)/stream/$',views.workout_stream_view), +# url(r'^workout/(?P\d+)/crewnerdsummary/$',views.workout_crewnerd_summary_view), + url(r'^workout/(?P\d+)/editintervals/$',views.workout_summary_edit_view, name='workout_summary_edit_view'), - url(r'^workout/(?P\d+)/restore$',views.workout_summary_restore_view), - url(r'^workout/(?P\d+)/split$',views.workout_split_view), -# url(r'^workout/(?P\d+)/interactiveplot$',views.workout_biginteractive_view), - url(r'^workout/(?P\d+)/view$',views.workout_view), + url(r'^workout/(?P\d+)/restore/$',views.workout_summary_restore_view), + url(r'^workout/(?P\d+)/split/$',views.workout_split_view), +# url(r'^workout/(?P\d+)/interactiveplot/$',views.workout_biginteractive_view), + url(r'^workout/(?P\d+)/view/$',views.workout_view), url(r'^workout/(?P\d+)/$',views.workout_view), - url(r'^workout/fusion/(?P\d+)/(?P\d+)$',views.workout_fusion_view), + url(r'^workout/fusion/(?P\d+)/(?P\d+)/$',views.workout_fusion_view), url(r'^workout/fusion/(?P\d+)/$',views.workout_fusion_list), - url(r'^workout/fusion/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$',views.workout_fusion_list), - url(r'^help$',TemplateView.as_view( + url(r'^workout/fusion/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workout_fusion_list), + url(r'^help/$',TemplateView.as_view( template_name='help.html'),name='help' ), - url(r'^physics$',TemplateView.as_view(template_name='physics.html'),name='physics'), - url(r'^partners$',TemplateView.as_view(template_name='partners.html'),name='partners'), + url(r'^physics/$',TemplateView.as_view(template_name='physics.html'),name='physics'), + url(r'^partners/$',TemplateView.as_view(template_name='partners.html'),name='partners'), # keeping the old URLs for retrofit - url(r'^workout/(?P\d+)/addtimeplot$', + url(r'^workout/(?P\d+)/addtimeplot/$', views.workout_add_chart_view, {'plotnr':'1'}), - url(r'^workout/(?P\d+)/adddistanceplot$', + url(r'^workout/(?P\d+)/adddistanceplot/$', views.workout_add_chart_view, {'plotnr':'2'}), - url(r'^workout/(?P\d+)/addpiechart$', + url(r'^workout/(?P\d+)/addpiechart/$', views.workout_add_chart_view, {'plotnr':'3'}), - url(r'^workout/(?P\d+)/adddistanceplot2$', + url(r'^workout/(?P\d+)/adddistanceplot2/$', views.workout_add_chart_view, {'plotnr':'7'}), - url(r'^workout/(?P\d+)/addtimeplot2$', + url(r'^workout/(?P\d+)/addtimeplot2/$', views.workout_add_chart_view, {'plotnr':'8'}), - url(r'^workout/(?P\d+)/addotwpowerplot$', + url(r'^workout/(?P\d+)/addotwpowerplot/$', views.workout_add_chart_view, {'plotnr':'9'}), - url(r'^workout/(?P\d+)/addpowerpiechart$', + url(r'^workout/(?P\d+)/addpowerpiechart/$', views.workout_add_chart_view, {'plotnr':'13'}), # addstatic is the new URL -> need to update in templates - url(r'^workout/(?P\d+)/addstatic/(?P\d+)$', + url(r'^workout/(?P\d+)/addstatic/(?P\d+)/$', views.workout_add_chart_view), - url(r'^workout/(?P\d+)/addstatic$',views.workout_add_chart_view), - url(r'^workout/(?P\d+)/delete$',login_required( + url(r'^workout/(?P\d+)/addstatic/$',views.workout_add_chart_view), + url(r'^workout/(?P\d+)/delete/$',login_required( views.WorkoutDelete.as_view()), name='workout_delete'), - url(r'^workout/(?P\d+)/smoothenpace$',views.workout_smoothenpace_view), - url(r'^workout/(?P\d+)/undosmoothenpace$',views.workout_undo_smoothenpace_view), + url(r'^workout/(?P\d+)/smoothenpace/$',views.workout_smoothenpace_view), + url(r'^workout/(?P\d+)/undosmoothenpace/$',views.workout_undo_smoothenpace_view), url(r'^workout/c2import/$',views.workout_c2import_view), url(r'^workout/c2list/$',views.workout_c2import_view), - url(r'^workout/c2list/(?P\d+)$',views.workout_c2import_view), - url(r'^workout/c2list/user/(?P\d+)$',views.workout_c2import_view), - url(r'^workout/c2list/(?P\d+)/user/(?P\d+)$',views.workout_c2import_view), + url(r'^workout/c2list/(?P\d+)/$',views.workout_c2import_view), + url(r'^workout/c2list/user/(?P\d+)/$',views.workout_c2import_view), + url(r'^workout/c2list/(?P\d+)/user/(?P\d+)/$',views.workout_c2import_view), url(r'^workout/stravaimport/$',views.workout_stravaimport_view), - url(r'^workout/stravaimport/user/(?P\d+)$',views.workout_stravaimport_view), + url(r'^workout/stravaimport/user/(?P\d+)/$',views.workout_stravaimport_view), url(r'^workout/c2import/all/$',views.workout_getc2workout_all), - url(r'^workout/c2import/all/(?P\d+)$',views.workout_getc2workout_all), + url(r'^workout/c2import/all/(?P\d+)/$',views.workout_getc2workout_all), url(r'^workout/(?P\w+.*)import/(?P\d+)/$',views.workout_getimportview), url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all), url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next), url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view), - url(r'^workout/sporttracksimport/user/(?P\d+)$',views.workout_sporttracksimport_view), + url(r'^workout/sporttracksimport/user/(?P\d+)/$',views.workout_sporttracksimport_view), url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all), url(r'^workout/polarimport/$',views.workout_polarimport_view), url(r'^workout/polarimport/user/(?P\d+)/',views.workout_polarimport_view), url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view), - url(r'^workout/runkeeperimport/user/(?P\d+)$',views.workout_runkeeperimport_view), + url(r'^workout/runkeeperimport/user/(?P\d+)/$',views.workout_runkeeperimport_view), url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view), -# url(r'^workout/(?P\d+)/deleteconfirm$',views.workout_delete_confirm_view), +# url(r'^workout/(?P\d+)/deleteconfirm/$',views.workout_delete_confirm_view), url(r'^workout/(?P\d+)/c2uploadw/$',views.workout_c2_upload_view), url(r'^workout/(?P\d+)/stravauploadw/$',views.workout_strava_upload_view), url(r'^workout/(?P\d+)/recalcsummary/$',views.workout_recalcsummary_view), @@ -366,34 +366,34 @@ urlpatterns = [ url(r'^multi-compare/workout/(?P\d+)/user/(?P\d+)/$',views.multi_compare_view), url(r'^multi-compare/workout/(?P\d+)/$',views.multi_compare_view), url(r'^multi-compare/$',views.multi_compare_view), - url(r'^user-boxplot/user/(?P\d+)$',views.boxplot_view), - url(r'^user-boxplot$',views.boxplot_view), - url(r'^user-boxplot-data$',views.boxplot_view_data), - url(r'^user-multiflex/user/(?P\d+)$',views.multiflex_view), + url(r'^user-boxplot/user/(?P\d+)/$',views.boxplot_view), + url(r'^user-boxplot/$',views.boxplot_view), + url(r'^user-boxplot-data/$',views.boxplot_view_data), + url(r'^user-multiflex/user/(?P\d+)/$',views.multiflex_view), url(r'^user-multiflex/$',views.multiflex_view), - url(r'^user-multiflex-data$',views.multiflex_data), - url(r'^me/deactivate$',views.deactivate_user), - url(r'^me/delete$',views.remove_user), - url(r'^me/gdpr-optin-confirm/?$',views.user_gdpr_confirm), + url(r'^user-multiflex-data/$',views.multiflex_data), + url(r'^me/deactivate/$',views.deactivate_user), + url(r'^me/delete/$',views.remove_user), + url(r'^me/gdpr-optin-confirm/?/$',views.user_gdpr_confirm), url(r'^me/gdpr-optin-confirm/$',views.user_gdpr_confirm), - url(r'^me/gdpr-optin/?$',views.user_gdpr_optin), + url(r'^me/gdpr-optin/?/$',views.user_gdpr_optin), url(r'^me/gdpr-optin/$',views.user_gdpr_optin), url(r'^me/teams/$',views.rower_teams_view), url(r'^me/calcdps/$',views.rower_calcdps_view), url(r'^me/exportsettings/$',views.rower_exportsettings_view), - url(r'^me/exportsettings/user/(?P\d+)$',views.rower_exportsettings_view), + url(r'^me/exportsettings/user/(?P\d+)/$',views.rower_exportsettings_view), url(r'^team/(?P\d+)/$',views.team_view), url(r'^team/(?P\d+)/memberstats/$',views.team_members_stats_view), url(r'^team/(?P\d+)/edit/$',views.team_edit_view), url(r'^team/(?P\d+)/leaveconfirm/$',views.team_leaveconfirm_view), url(r'^team/(?P\d+)/leave/$',views.team_leave_view), url(r'^team/(?P\d+)/deleteconfirm/$',views.team_deleteconfirm_view), - url(r'^team/(?P\d+)/requestmembership/(?P\d+)$',views.team_requestmembership_view), + url(r'^team/(?P\d+)/requestmembership/(?P\d+)/$',views.team_requestmembership_view), url(r'^team/(?P\d+)/delete/$',views.team_delete_view), url(r'^team/create/$',views.team_create_view), - url(r'^me/team/(?P\d+)/drop/(?P\d+)$',views.manager_member_drop_view), - url(r'^me/invitation/(?P\d+)/reject$',views.invitation_reject_view), - url(r'^me/invitation/(?P\d+)/revoke$',views.invitation_revoke_view), + url(r'^me/team/(?P\d+)/drop/(?P\d+)/$',views.manager_member_drop_view), + url(r'^me/invitation/(?P\d+)/reject/$',views.invitation_reject_view), + url(r'^me/invitation/(?P\d+)/revoke/$',views.invitation_revoke_view), url(r'^me/invitation/$',views.rower_invitations_view), url(r'^me/raise500/$',views.raise_500), url(r'^me/invitation/(\w+.*)/$',views.rower_invitations_view), @@ -402,14 +402,14 @@ urlpatterns = [ url(r'^me/request/(\w+.*)/$',views.manager_requests_view), url(r'^me/request/$',views.manager_requests_view), url(r'^me/edit/$',views.rower_edit_view), - url(r'^me/edit/user/(?P\d+)$',views.rower_edit_view), + url(r'^me/edit/user/(?P\d+)/$',views.rower_edit_view), url(r'^me/preferences/$',views.rower_prefs_view), url(r'^me/transactions/$',views.transactions_view), - url(r'^me/preferences/user/(?P\d+)$',views.rower_prefs_view), + url(r'^me/preferences/user/(?P\d+)/$',views.rower_prefs_view), url(r'^me/edit/(.+.*)/$',views.rower_edit_view), url(r'^me/c2authorize/$',views.rower_c2_authorize), url(r'^me/polarauthorize/$',views.rower_polar_authorize), - url(r'^me/revokeapp/(?P\d+)$',views.rower_revokeapp_view), + url(r'^me/revokeapp/(?P\d+)/$',views.rower_revokeapp_view), url(r'^me/stravaauthorize/$',views.rower_strava_authorize), url(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize), url(r'^me/underarmourauthorize/$',views.rower_underarmour_authorize), @@ -420,59 +420,59 @@ urlpatterns = [ url(r'^me/tprefresh/$',views.rower_tp_token_refresh), url(r'^me/c2refresh/$',views.rower_c2_token_refresh), url(r'^me/favoritecharts/$',views.rower_favoritecharts_view), - url(r'^me/favoritecharts/user/(?P\d+)$',views.rower_favoritecharts_view), -# url(r'^me/workflowconfig$',views.workout_workflow_config_view), + url(r'^me/favoritecharts/user/(?P\d+)/$',views.rower_favoritecharts_view), +# url(r'^me/workflowconfig/$',views.workout_workflow_config_view), url(r'^me/workflowconfig2/$',views.workout_workflow_config2_view), - url(r'^me/workflowconfig2/user/(?P\d+)$',views.workout_workflow_config2_view), - url(r'^me/workflowdefault$',views.workflow_default_view), + url(r'^me/workflowconfig2/user/(?P\d+)/$',views.workout_workflow_config2_view), + url(r'^me/workflowdefault/$',views.workflow_default_view), url(r'^email/send/$', views.sendmail), url(r'^email/thankyou/$', TemplateView.as_view(template_name='thankyou.html'), name='thankyou'), url(r'^email/$', TemplateView.as_view(template_name='email.html'), name='email'), url(r'^about', TemplateView.as_view(template_name='about_us.html'),name='about'), - url(r'^brochure$',TemplateView.as_view(template_name='brochure.html'), + url(r'^brochure/$',TemplateView.as_view(template_name='brochure.html'), name='brochure'), url(r'^developers', TemplateView.as_view(template_name='developers.html'),name='about'), # url(r'^compatibility', TemplateView.as_view(template_name='compatibility.html'),name='about'), # url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'), - url(r'^analysis/user/(?P\d+)$', views.analysis_view,name='analysis'), - url(r'^laboratory/user/(?P\d+)$', views.laboratory_view,name='laboratory'), + url(r'^analysis/user/(?P\d+)/$', views.analysis_view,name='analysis'), + url(r'^laboratory/user/(?P\d+)/$', views.laboratory_view,name='laboratory'), url(r'^analysis/$', views.analysis_view,name='analysis'), url(r'^laboratory/$', views.laboratory_view,name='laboratory'), url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), - url(r'^checkout/(?P\d+)$',views.payment_confirm_view), - url(r'^upgradecheckout/(?P\d+)$',views.upgrade_confirm_view), - url(r'^downgradecheckout/(?P\d+)$',views.downgrade_confirm_view), - url(r'^billing$',views.billing_view,name='billing'), - url(r'^upgrade$',views.upgrade_view,name='upgrade'), - url(r'^downgrade$',views.downgrade_view,name='downgrade'), - url(r'^paymentcompleted$',views.payment_completed_view), - url(r'^downgradecompleted$',views.downgrade_completed_view), - url(r'^paidplans$',views.paidplans_view,name='paidplans'), - url(r'^me/cancelsubscriptions$',views.plan_stop_view), - url(r'^me/cancelsubscription/(?P[\w\ ]+.*)$',views.plan_tobasic_view), - url(r'^checkouts$',views.checkouts_view,name='checkouts'), - url(r'^upgradecheckouts$',views.upgrade_checkouts_view,name='upgrade_checkouts'), - url(r'^downgradecheckouts$',views.downgrade_checkouts_view,name='downgrade_checkouts'), + url(r'^checkout/(?P\d+)/$',views.payment_confirm_view), + url(r'^upgradecheckout/(?P\d+)/$',views.upgrade_confirm_view), + url(r'^downgradecheckout/(?P\d+)/$',views.downgrade_confirm_view), + url(r'^billing/$',views.billing_view,name='billing'), + url(r'^upgrade/$',views.upgrade_view,name='upgrade'), + url(r'^downgrade/$',views.downgrade_view,name='downgrade'), + url(r'^paymentcompleted/$',views.payment_completed_view), + url(r'^downgradecompleted/$',views.downgrade_completed_view), + url(r'^paidplans/$',views.paidplans_view,name='paidplans'), + url(r'^me/cancelsubscriptions/$',views.plan_stop_view), + url(r'^me/cancelsubscription/(?P[\w\ ]+.*)/$',views.plan_tobasic_view), + url(r'^checkouts/$',views.checkouts_view,name='checkouts'), + url(r'^upgradecheckouts/$',views.upgrade_checkouts_view,name='upgrade_checkouts'), + url(r'^downgradecheckouts/$',views.downgrade_checkouts_view,name='downgrade_checkouts'), url(r'^planrequired',views.planrequired_view), - url(r'^starttrial$',views.start_trial_view), - url(r'^startplantrial$',views.start_plantrial_view), + url(r'^starttrial/$',views.start_trial_view), + url(r'^startplantrial/$',views.start_plantrial_view), # url(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'), # url(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'), url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'), - url(r'^register$',views.rower_register_view), + url(r'^register/$',views.rower_register_view), url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'), - url(r'^workout/(?P\d+)/workflow$',views.workout_workflow_view, + url(r'^workout/(?P\d+)/workflow/$',views.workout_workflow_view, name='workout_workflow_view'), url(r'^workout/(?P\d+)/flexchart/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/(?P\w+)/$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/(?P\w+.*)$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart$',views.workout_flexchart3_view), -# url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)$',views.workout_comparison_view2), + url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/(?P\w+.*)/$',views.workout_flexchart3_view), + url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/$',views.workout_flexchart3_view), + url(r'^workout/(?P\d+)/flexchart/$',views.workout_flexchart3_view), +# url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), # url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), url(r'^test\_callback',views.rower_process_testcallback), url(r'^createplan/$',views.rower_create_trainingplan), url(r'^createplan/user/(?P\d+)/$',views.rower_create_trainingplan), - url(r'^deleteplan/(?P\d+)$',login_required( + url(r'^deleteplan/(?P\d+)/$',login_required( views.TrainingPlanDelete.as_view())), url(r'^deletemicrocycle/(?P\d+)/$',login_required( views.MicroCycleDelete.as_view())), @@ -480,7 +480,7 @@ urlpatterns = [ views.MesoCycleDelete.as_view())), url(r'^deletemacrocycle/(?P\d+)/$',login_required( views.MacroCycleDelete.as_view())), -# url(r'^deleteplan/(?P\d+)$',views.rower_delete_trainingplan), +# url(r'^deleteplan/(?P\d+)/$',views.rower_delete_trainingplan), url(r'^plan/(?P\d+)/$',views.rower_trainingplan_view), url(r'^plan/(?P\d+)/user/(?P\d+)/$',views.rower_trainingplan_view), url(r'^plan/(?P\d+)/micro/(?P\d+)/$',views.rower_trainingplan_view), @@ -504,13 +504,13 @@ urlpatterns = [ views.TrainingMicroCycleUpdate.as_view()), name='microcycle_update_view'), url(r'^deletetarget/(?P\d+)/$',views.rower_delete_trainingtarget), - url(r'^editplan/(?P\d+)$',login_required( + url(r'^editplan/(?P\d+)/$',login_required( views.TrainingPlanUpdate.as_view()), name='trainingplan_update_view'), url(r'^edittarget/(?P\d+)/$',login_required( views.TrainingTargetUpdate.as_view()), name='trainingtarget_update_view'), - url(r'^workout/(?P\d+)/test\_strokedata$',views.strokedataform), + url(r'^workout/(?P\d+)/test\_strokedata/$',views.strokedataform), url(r'^sessions/teamcreate/user/(?P\d+)/$',views.plannedsession_teamcreate_view), url(r'^sessions/teamcreate/team/(?P\d+)/user/(?P\d+)/$', views.plannedsession_teamcreate_view), @@ -520,11 +520,11 @@ urlpatterns = [ url(r'^sessions/teamedit/(?P\d+)/$',views.plannedsession_teamedit_view), url(r'^sessions/teamedit/(?P\d+)/user/(?P\d+)/$',views.plannedsession_teamedit_view), url(r'^sessions/create/$',views.plannedsession_create_view), - url(r'^sessions/create/user/(?P\d+)$', + url(r'^sessions/create/user/(?P\d+)/$', views.plannedsession_create_view), url(r'^sessions/create/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$', views.plannedsession_create_view), - url(r'^sessions/create/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)$', + url(r'^sessions/create/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$', views.plannedsession_create_view), url(r'^sessions/multiclone/$',views.plannedsession_multiclone_view), url(r'^sessions/multiclone/user/(?P\d+)/$', @@ -546,47 +546,47 @@ urlpatterns = [ name='plannedsession_view'), url(r'^sessions/(?P\d+)/user/(?P\d+)/$',views.plannedsession_view, name='plannedsession_view'), - url(r'^sessions/(?P\d+)/deleteconfirm$',login_required( + url(r'^sessions/(?P\d+)/deleteconfirm/$',login_required( views.PlannedSessionDelete.as_view())), - url(r'^sessions/(?P\d+)/delete$',login_required( + url(r'^sessions/(?P\d+)/delete/$',login_required( views.PlannedSessionDelete.as_view()), name='plannedsession_delete_view'), url(r'^sessions/manage/session/(?P\d+)/$', views.plannedsessions_manage_view), url(r'^sessions/manage/session/(?P\d+)/user/(?P\d+)/$', views.plannedsessions_manage_view), - url(r'^sessions/manage/?$', + url(r'^sessions/manage/?/$', views.plannedsessions_manage_view), url(r'^sessions/manage/user/(?P\d+)/$', views.plannedsessions_manage_view), url(r'^sessions/coach/$',views.plannedsessions_coach_view), url(r'^sessions/coach/user/\d+/$',views.plannedsessions_coach_view), - url(r'^sessions/print/?$',views.plannedsessions_print_view), + url(r'^sessions/print/?/$',views.plannedsessions_print_view), url(r'^sessions/print/user/(?P\d+)/$',views.plannedsessions_print_view), url(r'^sessions/sendcalendar/$',views.plannedsessions_icsemail_view), url(r'^sessions/sendcalendar/user/(?P\d+)/$',views.plannedsessions_icsemail_view), url(r'^sessions/$',views.plannedsessions_view), - url(r'^sessions/user/(?P\d+)$',views.plannedsessions_view), - url(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)$', + url(r'^sessions/user/(?P\d+)/$',views.plannedsessions_view), + url(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$', views.plannedsessions_view), - url(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)$', + url(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$', views.plannedsessions_view), - url(r'^courses/(?P\d+)/edit$',views.course_edit_view, + url(r'^courses/(?P\d+)/edit/$',views.course_edit_view, name='course_edit_view'), - url(r'^courses/(?P\d+)/delete$',views.course_delete_view), - url(r'^courses/(?P\d+)/emailkml$',views.course_kmlemail_view), - url(r'^courses/(?P\d+)/replace$',views.course_replace_view), - url(r'^courses/(?P\d+)$',views.course_view), - url(r'^courses/(?P\d+)/map$',views.course_map_view), + url(r'^courses/(?P\d+)/delete/$',views.course_delete_view), + url(r'^courses/(?P\d+)/emailkml/$',views.course_kmlemail_view), + url(r'^courses/(?P\d+)/replace/$',views.course_replace_view), + url(r'^courses/(?P\d+)/$',views.course_view), + url(r'^courses/(?P\d+)/map/$',views.course_map_view), # URLS to be created - url(r'^help$',TemplateView.as_view(template_name='help.html'), name='help'), + url(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), ] if settings.DEBUG: urlpatterns += [ url(r'^testreverse/$',views.test_reverse_view), - url(r'^c2listug/(?P\d+)$',views.c2listdebug_view), + url(r'^c2listug/(?P\d+)/$',views.c2listdebug_view), url(r'^c2listug/$',views.c2listdebug_view), ] diff --git a/rowers/views.py b/rowers/views.py index 55660d38..bf920f55 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -4009,6 +4009,10 @@ def fitness_metric_view(request,mode='rower',days=42): # test if not something already done ms = PowerTimeFitnessMetric.objects.filter(user=request.user) + if not ms: + url = reverse(workouts_view) + return HttpResponseRedirect(url) + max_workout_id = max([m.last_workout for m in ms]) last_update_date = max([m.date.strftime('%Y-%m-%d') for m in ms]) @@ -9961,16 +9965,14 @@ def workout_flexchart3_view(request,*args,**kwargs): workstrokesonly = not includereststrokes flexaxesform = FlexAxesForm(request,request.POST) - print request.POST if flexaxesform.is_valid(): - print 'form valid' cd = flexaxesform.cleaned_data xparam = cd['xaxis'] yparam1 = cd['yaxis1'] yparam2 = cd['yaxis2'] else: - print flexaxesform.errors + pass if not promember: From 0d4c6231a7d3cc2ced1a98c3027da5330b6b00e7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 4 Jan 2019 21:48:13 +0100 Subject: [PATCH 15/18] some more tests --- rowers/tests/mocks.py | 18 +++++++ rowers/tests/test_imports.py | 69 ++++++++++++++++++++++++-- rowers/tests/testdata/testdata.csv.gz | Bin 11511 -> 11426 bytes rowers/tests/testdata/testdata.tcx.gz | Bin 0 -> 4045 bytes rowers/views.py | 2 +- rowsandall_app/settings_dev.py | 1 + 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 rowers/tests/testdata/testdata.tcx.gz diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index e48495c8..6937e41c 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -125,6 +125,23 @@ def mocked_read_df_cols_sql(ids, columns, convertnewtons=True): return df, extracols +def mocked_stravaexport(f2,workoutname,stravatoken,description='', + activity_type='Rowing'): + print "this is mocked strava export" + return 1,'success' + +def StravaActivity(): + def wait(*args, **kwargs): + return 1 + +class MockStravalibClient(): + def upload_activity(*args, **kwargs): + return StravaActivity() + + def update_activity(*args, **kwargs): + return StravaActivity() + + class mocked_rowingdata(rowingdata): def __init__(self, *args, **kwargs): super(mocked_rowingdata).__init__(*args, **kwargs) @@ -271,6 +288,7 @@ def mocked_requests(*args, **kwargs): return MockResponse(json_data,200) + if not args: return MockSession() diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index fad25be5..115484f9 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -6,7 +6,7 @@ pytestmark = pytest.mark.django_db from bs4 import BeautifulSoup import re from nose_parameterized import parameterized -from django.test import TestCase, Client,override_settings +from django.test import TestCase, Client,override_settings, modify_settings from django.core.management import call_command from django.utils.six import StringIO from django.test.client import RequestFactory @@ -36,6 +36,8 @@ import rowers.c2stuff as c2stuff import json import numpy as np +import rowers + from rowers import urls from rowers.views import ( error500_view,error404_view,error400_view,error403_view @@ -278,9 +280,58 @@ class StravaObjects(DjangoTestCase): ) self.r.stravatoken = '12' + self.r.stravarefreshtoken = '123' self.r.save() self.c.login(username='john',password='koeinsloot') + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + +# @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) +# @patch('rowers.views.stravastuff.handle_stravaexport') + #@patch('rowers.dataprep.getsmallrowdata_db') + #def test_strava_upload(self, mock_post,MockStravalibClient, + # mocked_getsmallrowdata_db): + # def test_strava_upload(self,mock_post, mocked_stravaexport): + # response = self.c.get('/rowers/workout/1/stravauploadw/') + + # self.assertRedirects(response, + # expected_url = '/rowers/workout/1/edit/', + # status_code=302,target_status_code=200) + + # self.assertEqual(response.url, '/rowers/workout/1/edit/') + # self.assertEqual(response.status_code, 302) @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) def test_strava_list(self, mock_get): @@ -289,16 +340,28 @@ class StravaObjects(DjangoTestCase): self.assertEqual(response.status_code,200) @patch('rowers.utils.requests.get', side_effect=mocked_requests) - def test_strava_import(self, mock_get): + @patch('rowers.dataprep.getsmallrowdata_db') + def test_strava_import(self, mock_get, + mocked_getsmallrowdata_db): response = self.c.get('/rowers/workout/stravaimport/12',follow=True) self.assertRedirects(response, - expected_url='/rowers/workout/1/edit/', + expected_url='/rowers/workout/2/edit/', status_code=301,target_status_code=200) self.assertEqual(response.status_code, 200) + @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) + def test_strava_callback(self, mock_post): + response = self.c.get('/stravacall_back?code=absdef23',follow=True) + self.assertEqual(response.status_code, 200) + + @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) + def test_strava_token_refresh(self, mock_post): + result = rowers.stravastuff.rower_strava_token_refresh(self.u) + self.assertEqual(result,"987654321234567898765432123456789") + #@pytest.mark.django_db diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index c8e1107351aae1553cc73d50275a17f91d536e0d..7e09e8115c40386c386423838988752971ee1a54 100644 GIT binary patch literal 11426 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≧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 w5V5Hb^v`{TaTo-aedFP(4zu0+PoIY$HY#M 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 diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz new file mode 100644 index 0000000000000000000000000000000000000000..2d9b5194e7b187fdb84a4ea71098218cae3f2819 GIT binary patch literal 4045 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 literal 0 HcmV?d00001 diff --git a/rowers/views.py b/rowers/views.py index bf920f55..a2ab56d6 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -2252,7 +2252,7 @@ def workout_strava_upload_view(request,id=0): try: thetoken = strava_open(request.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/stravaauthorize") + return HttpResponseRedirect("/rowers/me/stravaauthorize/") if (r.stravatoken == '') or (r.stravatoken is None): s = "Token doesn't exist. Need to authorize" diff --git a/rowsandall_app/settings_dev.py b/rowsandall_app/settings_dev.py index 8443b40a..b4953f19 100644 --- a/rowsandall_app/settings_dev.py +++ b/rowsandall_app/settings_dev.py @@ -96,3 +96,4 @@ EMAIL_USE_TLS = CFG['email_use_tls'] DEFAULT_FROM_EMAIL = 'info@rowsandall.com' SETTINGS_NAME = 'rowsandall_app.settings_dev' + From e2cdb0af8e50bf96e3279b011a3e2eb4d15fb44e Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 5 Jan 2019 13:29:39 +0100 Subject: [PATCH 16/18] adding trailing slashes to post forms --- rowers/forms.py | 6 ++- rowers/models.py | 2 + rowers/payments.py | 42 ++++++++++---------- rowers/templates/billing.html | 3 +- rowers/templates/downgrade.html | 1 + rowers/templates/downgradeconfirm.html | 2 +- rowers/templates/fitnessmetric.html | 2 +- rowers/templates/gdpr_optin.html | 2 +- rowers/templates/list_workouts.html | 4 +- rowers/templates/multiflex.html | 2 +- rowers/templates/paidplans.html | 5 +++ rowers/templates/paymentconfirm.html | 2 +- rowers/templates/payments.html | 2 +- rowers/templates/plannedsessionedit.html | 2 +- rowers/templates/rankings.html | 2 +- rowers/templates/splitworkout.html | 2 +- rowers/templates/strokedata_form.html | 2 +- rowers/templates/summary_edit.html | 6 +-- rowers/templates/upgrade.html | 3 +- rowers/templates/upgradeconfirm.html | 2 +- rowers/templates/user_boxplot_select.html | 2 +- rowers/templates/user_multiflex_select.html | 2 +- rowers/templates/workout_comments.html | 2 +- rowers/templates/workout_join_select.html | 6 +-- rowers/tests/testdata/testdata.csv.gz | Bin 11426 -> 11426 bytes 25 files changed, 59 insertions(+), 47 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index 8599496b..ffef4328 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -746,7 +746,8 @@ class PlanSelectForm(forms.Form): self.fields['plan'].empty_label = None if paymentprocessor: self.fields['plan'].queryset = PaidPlan.objects.filter( - paymentprocessor=paymentprocessor + paymentprocessor=paymentprocessor, + active=True ).exclude( shortname="basic" ).order_by( @@ -758,7 +759,8 @@ class PlanSelectForm(forms.Form): except AttributeError: amount = 0 self.fields['plan'].queryset = PaidPlan.objects.filter( - paymentprocessor=rower.paymentprocessor + paymentprocessor=rower.paymentprocessor, + active=True ).exclude( price__lte=amount ).order_by( diff --git a/rowers/models.py b/rowers/models.py index ab8f822f..29322052 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -568,6 +568,8 @@ class PaidPlan(models.Model): choices=paymenttypes, ) + active = models.BooleanField(default=True) + clubsize = models.IntegerField(default=0) def __unicode__(self): diff --git a/rowers/payments.py b/rowers/payments.py index bbeb12f4..1e4304fa 100644 --- a/rowers/payments.py +++ b/rowers/payments.py @@ -10,30 +10,30 @@ def planstopaypal(): plan.external_id = None plan.save() -def initiaterowerplans(): - rowers = Rower.objects.filter(paymenttype = 'recurring',paidplan = None) - for r in rowers: - r.paymentprocessor = 'paypal' - r.save() +#def initiaterowerplans(): +# rowers = Rower.objects.filter(paymenttype = 'recurring',paidplan = None) +# for r in rowers: +# r.paymentprocessor = 'paypal' +# r.save() -def setrowerplans(): - rowers = Rower.objects.all() +#def setrowerplans(): +# rowers = Rower.objects.all() - for r in rowers: - paidplans = PaidPlan.objects.filter( - shortname = r.rowerplan, - paymenttype = r.paymenttype, - clubsize = r.clubsize, - paymentprocessor=r.paymentprocessor) +# for r in rowers: +# paidplans = PaidPlan.objects.filter( +# shortname = r.rowerplan, +# paymenttype = r.paymenttype, +# clubsize = r.clubsize, +# paymentprocessor=r.paymentprocessor) - if paidplans: - r.paidplan = paidplans[0] - r.save() - else: - try: - print 'Could not set plan for ',r.user.username - except: - pass +# if paidplans: +# r.paidplan = paidplans[0] +# r.save() +# else: +# try: +# print 'Could not set plan for ',r.user.username +# except: +# pass def is_existing_customer(rower): if rower.country is not None and rower.customer_id is not None and rower.country != '': diff --git a/rowers/templates/billing.html b/rowers/templates/billing.html index 1d16238a..0aacc77e 100644 --- a/rowers/templates/billing.html +++ b/rowers/templates/billing.html @@ -19,7 +19,8 @@

    Unless specified otherwise, the payments on the recurring payment plans are annual. The prices are specified - as a price per year. + as a price per year. You can downgrade or cancel your + plan at any time in your settings.

    diff --git a/rowers/templates/downgrade.html b/rowers/templates/downgrade.html index bf2e7bc7..7e5fe130 100644 --- a/rowers/templates/downgrade.html +++ b/rowers/templates/downgrade.html @@ -1,3 +1,4 @@ + {% extends "newbase.html" %} {% block title %}Rowsandall Paid Membership{% endblock title %} {% load rowerfilters %} diff --git a/rowers/templates/downgradeconfirm.html b/rowers/templates/downgradeconfirm.html index 9bb0aee0..1e027c34 100644 --- a/rowers/templates/downgradeconfirm.html +++ b/rowers/templates/downgradeconfirm.html @@ -56,7 +56,7 @@ Change Downgrade
  • -
  • - +
  • {{ form.as_table }}
    diff --git a/rowers/templates/gdpr_optin.html b/rowers/templates/gdpr_optin.html index 311816ac..e9a37507 100644 --- a/rowers/templates/gdpr_optin.html +++ b/rowers/templates/gdpr_optin.html @@ -42,7 +42,7 @@

    - + {% csrf_token %} diff --git a/rowers/templates/list_workouts.html b/rowers/templates/list_workouts.html index 2ccb8c53..adf48b3b 100644 --- a/rowers/templates/list_workouts.html +++ b/rowers/templates/list_workouts.html @@ -80,10 +80,10 @@

    {% if team %}

    - {% else %} - {% endif %} {{ searchform }} diff --git a/rowers/templates/multiflex.html b/rowers/templates/multiflex.html index 92d4f140..4af8901d 100644 --- a/rowers/templates/multiflex.html +++ b/rowers/templates/multiflex.html @@ -27,7 +27,7 @@

  • - + {% csrf_token %} {{ chartform.as_table }} diff --git a/rowers/templates/paidplans.html b/rowers/templates/paidplans.html index 4550c0d7..331792e9 100644 --- a/rowers/templates/paidplans.html +++ b/rowers/templates/paidplans.html @@ -12,6 +12,11 @@ hosting costs, we have created paid plans offering extended functionality.

    +

    + All plans are valid for a year. Recurring payment plans will automatically + bill you at the start of a new 12 month period. You can stop your plan + at any time in your settings. +

    diff --git a/rowers/templates/paymentconfirm.html b/rowers/templates/paymentconfirm.html index 10fba5ad..35b94715 100644 --- a/rowers/templates/paymentconfirm.html +++ b/rowers/templates/paymentconfirm.html @@ -65,7 +65,7 @@ Change Order
  • -
  • diff --git a/rowers/templates/rankings.html b/rowers/templates/rankings.html index 6291b8b5..ee1bc30b 100644 --- a/rowers/templates/rankings.html +++ b/rowers/templates/rankings.html @@ -114,7 +114,7 @@ {% csrf_token %} / diff --git a/rowers/templates/splitworkout.html b/rowers/templates/splitworkout.html index 86756bc8..5ab8a668 100644 --- a/rowers/templates/splitworkout.html +++ b/rowers/templates/splitworkout.html @@ -12,7 +12,7 @@
    • -
      +

    {{ form.as_table }}
    diff --git a/rowers/templates/strokedata_form.html b/rowers/templates/strokedata_form.html index 21e39da9..a34ee316 100644 --- a/rowers/templates/strokedata_form.html +++ b/rowers/templates/strokedata_form.html @@ -8,7 +8,7 @@ {% endif %}

    Stroke Data for workout

    - + {{ form.as_table }}
    diff --git a/rowers/templates/summary_edit.html b/rowers/templates/summary_edit.html index 5d61d6bf..32d7b067 100644 --- a/rowers/templates/summary_edit.html +++ b/rowers/templates/summary_edit.html @@ -38,7 +38,7 @@

    See the how-to at the bottom of this page for details on how to use this form.

    - + {{ form.as_table }}
    @@ -73,7 +73,7 @@
  • Updated Summary

    - + {% csrf_token %} @@ -101,7 +101,7 @@
  • Detailed Summary Edit

    This is still experimental and there are known bugs. Use at your own risk. Nothing is stored permanently until you hit Save in the Updated Summary section. You can use the restore original button to restore the original values.

    - + diff --git a/rowers/templates/upgrade.html b/rowers/templates/upgrade.html index 9f21c889..f224f7dd 100644 --- a/rowers/templates/upgrade.html +++ b/rowers/templates/upgrade.html @@ -20,7 +20,8 @@

    Unless specified otherwise, the payments on the recurring payment plans are annual. The prices are specified - as a price per year. + as a price per year. You can downgrade or cancel your + plan at any time in your settings.

    diff --git a/rowers/templates/upgradeconfirm.html b/rowers/templates/upgradeconfirm.html index 92c28ccd..b42c4459 100644 --- a/rowers/templates/upgradeconfirm.html +++ b/rowers/templates/upgradeconfirm.html @@ -65,7 +65,7 @@ Change Upgrade
  • -
  • - + {% if workouts %} diff --git a/rowers/templates/user_multiflex_select.html b/rowers/templates/user_multiflex_select.html index 0566ad12..9b4478fa 100644 --- a/rowers/templates/user_multiflex_select.html +++ b/rowers/templates/user_multiflex_select.html @@ -103,7 +103,7 @@
  • -
    + {% if workouts %} Toggle All
    diff --git a/rowers/templates/workout_comments.html b/rowers/templates/workout_comments.html index c858c8b7..4f593026 100644 --- a/rowers/templates/workout_comments.html +++ b/rowers/templates/workout_comments.html @@ -54,7 +54,7 @@ {% endfor %} - +
  • {{ form.as_table }}
    diff --git a/rowers/templates/workout_join_select.html b/rowers/templates/workout_join_select.html index a6f2649e..7267ee91 100644 --- a/rowers/templates/workout_join_select.html +++ b/rowers/templates/workout_join_select.html @@ -70,7 +70,7 @@
    • - + {% if workouts %} Toggle All
      @@ -127,10 +127,10 @@
    • {% if team %} - {% else %} - {% endif %} {{ searchform }} diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index 7e09e8115c40386c386423838988752971ee1a54..a9a1d241a655f2a7aa853a51ba5860915c299217 100644 GIT binary patch delta 16 XcmZ1!xhRrdzMF&N-dux??6Y+MGg1ZO delta 16 XcmZ1!xhRrdzMF$X?wI~Y_SrfBF9QWi From b66975e575dc14b29b0f5dd2d1a5ff16127d5914 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 5 Jan 2019 13:38:36 +0100 Subject: [PATCH 17/18] extra test file --- rowers/tests/testdata/testdata.csv.gz | Bin 11426 -> 11426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index a9a1d241a655f2a7aa853a51ba5860915c299217..ff12d9ea7a1e8c4d37754c07fa2781b453ae95f7 100644 GIT binary patch delta 15 WcmZ1!xhRrNzMF$XX30jjIXVC-x&-zB delta 15 WcmZ1!xhRrNzMF&N-rS9Bb94YMBL%Sl From 09c3d35e826a39d84217320910fb635e50fcb33d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 5 Jan 2019 14:01:12 +0100 Subject: [PATCH 18/18] releasing links to paid plans --- rowers/tests/testdata/testdata.csv.gz | Bin 11426 -> 11426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index ff12d9ea7a1e8c4d37754c07fa2781b453ae95f7..3838db526efcdf9d9f74a8a7d081fe6edadc06a0 100644 GIT binary patch delta 15 WcmZ1!xhRrNzMF$Xf7wR1IXVC;HU$d+ delta 15 WcmZ1!xhRrNzMF$XX30jjIXVC-x&-zB