import datetime from io import BytesIO from typing import Generator, List from unittest.mock import Mock, patch from uuid import uuid4 import pytest from PIL import Image from werkzeug.datastructures import FileStorage from fittrackee import db from fittrackee.workouts.models import Sport, Workout, WorkoutSegment from fittrackee.workouts.utils.maps import StaticMap byte_io = BytesIO() Image.new('RGB', (256, 256)).save(byte_io, 'PNG') byte_image = byte_io.getvalue() @pytest.fixture(scope='session', autouse=True) def static_map_get_mock() -> Generator: # to avoid unnecessary requests calls through staticmap m = Mock(return_value=(200, byte_image)) with patch.object(StaticMap, 'get', m) as _fixture: yield _fixture @pytest.fixture() def sport_1_cycling() -> Sport: sport = Sport(label='Cycling') db.session.add(sport) db.session.commit() return sport @pytest.fixture() def sport_1_cycling_inactive() -> Sport: sport = Sport(label='Cycling') sport.is_active = False db.session.add(sport) db.session.commit() return sport @pytest.fixture() def sport_2_running() -> Sport: sport = Sport(label='Running') sport.stopped_speed_threshold = 0.1 db.session.add(sport) db.session.commit() return sport def update_workout(workout: Workout) -> None: workout.ave_speed = float(workout.distance) / ( workout.duration.seconds / 3600 ) workout.max_speed = workout.ave_speed workout.moving = workout.duration @pytest.fixture() def workout_cycling_user_1() -> Workout: workout = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=3600), ) update_workout(workout) db.session.add(workout) db.session.commit() return workout @pytest.fixture() def workout_cycling_user_1_segment( workout_cycling_user_1: Workout, ) -> WorkoutSegment: workout_segment = WorkoutSegment( workout_id=workout_cycling_user_1.id, workout_uuid=workout_cycling_user_1.uuid, segment_id=0, ) workout_segment.duration = datetime.timedelta(seconds=6000) workout_segment.moving = workout_segment.duration workout_segment.distance = 5 db.session.add(workout_segment) db.session.commit() return workout_segment @pytest.fixture() def workout_running_user_1() -> Workout: workout = Workout( user_id=1, sport_id=2, workout_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'), distance=12, duration=datetime.timedelta(seconds=6000), ) update_workout(workout) db.session.add(workout) db.session.commit() return workout @pytest.fixture() def seven_workouts_user_1() -> List[Workout]: workouts = [] workout_1 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'), distance=5, duration=datetime.timedelta(seconds=1024), ) update_workout(workout_1) workout_1.ascent = 120 workout_1.descent = 200 db.session.add(workout_1) db.session.flush() workouts.append(workout_1) workout_2 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=3456), ) update_workout(workout_2) workout_2.ascent = 100 workout_2.descent = 80 db.session.add(workout_2) db.session.flush() workouts.append(workout_2) workout_3 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=1024), ) update_workout(workout_3) workout_3.ascent = 80 workout_3.descent = 100 db.session.add(workout_3) db.session.flush() workouts.append(workout_3) workout_4 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), distance=1, duration=datetime.timedelta(seconds=600), ) update_workout(workout_4) workout_4.ascent = 120 workout_4.descent = 180 db.session.add(workout_4) db.session.flush() workouts.append(workout_4) workout_5 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=1000), ) update_workout(workout_5) workout_5.ascent = 100 workout_5.descent = 200 db.session.add(workout_5) db.session.flush() workouts.append(workout_5) workout_6 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'), distance=8, duration=datetime.timedelta(seconds=6000), ) update_workout(workout_6) workout_6.ascent = 40 workout_6.descent = 20 db.session.add(workout_6) db.session.flush() workouts.append(workout_6) workout_7 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=3000), ) update_workout(workout_7) db.session.add(workout_7) db.session.commit() workouts.append(workout_7) return workouts @pytest.fixture() def workout_cycling_user_2() -> Workout: workout = Workout( user_id=2, sport_id=1, workout_date=datetime.datetime.strptime('23/01/2018', '%d/%m/%Y'), distance=15, duration=datetime.timedelta(seconds=3600), ) update_workout(workout) db.session.add(workout) db.session.commit() return workout @pytest.fixture() def gpx_file() -> str: return ( '' '' # noqa ' ' ' ' ' just a workout' ' ' ' ' ' 998' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 993' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 985' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 981' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 975' ' ' ' ' ' ' ' ' '' ) @pytest.fixture() def gpx_file_wo_name() -> str: return ( '' '' # noqa ' ' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 993' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 985' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 981' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 975' ' ' ' ' ' ' ' ' '' ) @pytest.fixture() def gpx_file_with_offset() -> str: return ( '' '' # noqa ' ' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 993' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 985' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 981' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 975' ' ' ' ' ' ' ' ' '' ) @pytest.fixture() def gpx_file_wo_track() -> str: return ( '' '' # noqa ' ' '' ) @pytest.fixture() def gpx_file_invalid_xml() -> str: return ( '' '' # noqa ' ' ) @pytest.fixture() def gpx_file_with_segments() -> str: return ( '' '' # noqa ' ' ' ' ' just a workout' ' ' ' ' ' 998' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' 993' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 992' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' 985' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 981' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 975' ' ' ' ' ' ' ' ' '' ) @pytest.fixture() def gpx_file_with_3_segments() -> str: """60 seconds between each segment""" return ( '' '' # noqa ' ' ' ' ' just a workout' ' ' ' ' ' 998' ' ' ' ' ' ' ' 998' ' ' ' ' ' ' ' 994' ' ' ' ' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 987' ' ' ' ' ' ' ' 986' ' ' ' ' ' ' ' ' ' ' ' 980' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' 979' ' ' ' ' ' ' ' ' '' ) @pytest.fixture() def gpx_file_storage(gpx_file: str) -> FileStorage: return FileStorage( filename=f'{uuid4().hex}.gpx', stream=BytesIO(str.encode(gpx_file)) )