Merge branch 'dev' into oauth2
This commit is contained in:
2
fittrackee/tests/fixtures/fixtures_app.py
vendored
2
fittrackee/tests/fixtures/fixtures_app.py
vendored
@ -81,6 +81,8 @@ def app(monkeypatch: pytest.MonkeyPatch) -> Generator:
|
||||
monkeypatch.setenv('WEATHER_API_KEY', '')
|
||||
if os.getenv('TILE_SERVER_URL'):
|
||||
monkeypatch.delenv('TILE_SERVER_URL')
|
||||
if os.getenv('STATICMAP_SUBDOMAINS'):
|
||||
monkeypatch.delenv('STATICMAP_SUBDOMAINS')
|
||||
if os.getenv('MAP_ATTRIBUTION'):
|
||||
monkeypatch.delenv('MAP_ATTRIBUTION')
|
||||
if os.getenv('DEFAULT_STATICMAP'):
|
||||
|
56
fittrackee/tests/fixtures/fixtures_workouts.py
vendored
56
fittrackee/tests/fixtures/fixtures_workouts.py
vendored
@ -702,6 +702,62 @@ def gpx_file_with_segments() -> str:
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def gpx_file_with_3_segments() -> str:
|
||||
"""60 seconds between each segment"""
|
||||
return (
|
||||
'<?xml version=\'1.0\' encoding=\'UTF-8\'?>'
|
||||
'<gpx xmlns:gpxdata="http://www.cluetrust.com/XML/GPXDATA/1/0" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxext="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns="http://www.topografix.com/GPX/1/1">' # noqa
|
||||
' <metadata/>'
|
||||
' <trk>'
|
||||
' <name>just a workout</name>'
|
||||
' <trkseg>'
|
||||
' <trkpt lat="44.68095" lon="6.07367">'
|
||||
' <ele>998</ele>'
|
||||
' <time>2018-03-13T12:44:50Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.68091" lon="6.07367">'
|
||||
' <ele>998</ele>'
|
||||
' <time>2018-03-13T12:44:55Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.6808" lon="6.07364">'
|
||||
' <ele>994</ele>'
|
||||
' <time>2018-03-13T12:45:00Z</time>'
|
||||
' </trkpt>'
|
||||
' </trkseg>'
|
||||
' <trkseg>'
|
||||
' <trkpt lat="44.67972" lon="6.07367">'
|
||||
' <ele>987</ele>'
|
||||
' <time>2018-03-13T12:46:00Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.67966" lon="6.07368">'
|
||||
' <ele>987</ele>'
|
||||
' <time>2018-03-13T12:46:05Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.67961" lon="6.0737">'
|
||||
' <ele>986</ele>'
|
||||
' <time>2018-03-13T12:46:10Z</time>'
|
||||
' </trkpt>'
|
||||
' </trkseg>'
|
||||
' <trkseg>'
|
||||
' <trkpt lat="44.67858" lon="6.07425">'
|
||||
' <ele>980</ele>'
|
||||
' <time>2018-03-13T12:47:10Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.67842" lon="6.07434">'
|
||||
' <ele>979</ele>'
|
||||
' <time>2018-03-13T12:47:15Z</time>'
|
||||
' </trkpt>'
|
||||
' <trkpt lat="44.67837" lon="6.07435">'
|
||||
' <ele>979</ele>'
|
||||
' <time>2018-03-13T12:47:20Z</time>'
|
||||
' </trkpt>'
|
||||
' </trkseg>'
|
||||
' </trk>'
|
||||
'</gpx>'
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def gpx_file_storage(gpx_file: str) -> FileStorage:
|
||||
return FileStorage(
|
||||
|
@ -1,7 +1,7 @@
|
||||
import json
|
||||
import time
|
||||
from random import randint
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
from flask import Flask
|
||||
@ -286,10 +286,20 @@ class ApiTestCaseMixin(OAuth2Mixin, RandomMixin):
|
||||
|
||||
|
||||
class CallArgsMixin:
|
||||
"""call args are returned differently between Python 3.7 and 3.7+"""
|
||||
|
||||
@staticmethod
|
||||
def get_args(call_args: Any) -> Any:
|
||||
def get_args(call_args: Tuple) -> Tuple:
|
||||
if len(call_args) == 2:
|
||||
args, _ = call_args
|
||||
else:
|
||||
_, args, _ = call_args
|
||||
return args
|
||||
|
||||
@staticmethod
|
||||
def get_kwargs(call_args: Tuple) -> Dict:
|
||||
if len(call_args) == 2:
|
||||
_, kwargs = call_args
|
||||
else:
|
||||
_, _, kwargs = call_args
|
||||
return kwargs
|
||||
|
@ -1,3 +1,4 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import call, patch
|
||||
|
||||
import pytest
|
||||
@ -5,9 +6,10 @@ from flask import Flask
|
||||
from gpxpy.gpx import IGNORE_TOP_SPEED_PERCENTILES, MovingData
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
from fittrackee.tests.utils import random_string
|
||||
from fittrackee.users.models import User, UserSportPreference
|
||||
from fittrackee.workouts.models import Sport
|
||||
from fittrackee.workouts.utils.workouts import process_files
|
||||
from fittrackee.workouts.utils.workouts import get_gpx_info, process_files
|
||||
|
||||
folders = {
|
||||
'extract_dir': '/tmp/fitTrackee/uploads',
|
||||
@ -96,3 +98,35 @@ class TestStoppedSpeedThreshold:
|
||||
IGNORE_TOP_SPEED_PERCENTILES, # speed_extreemes_percentiles
|
||||
True, # ignore_nonstandard_distances
|
||||
)
|
||||
|
||||
|
||||
class TestGetGpxInfoStopTime:
|
||||
def test_stop_time_equals_to_0_when_gpx_file_contains_one_segment(
|
||||
self, gpx_file: str
|
||||
) -> None:
|
||||
"""
|
||||
stopped_speed_threshold to 0 to avoid calculated stopped time
|
||||
in segments
|
||||
"""
|
||||
with patch('builtins.open', return_value=gpx_file):
|
||||
|
||||
gpx_data, _, _ = get_gpx_info(
|
||||
gpx_file=random_string(), stopped_speed_threshold=0.0
|
||||
)
|
||||
|
||||
assert gpx_data['stop_time'] == timedelta(seconds=0)
|
||||
|
||||
def test_stop_time_equals_to_stopped_time_sum_between_all_segments(
|
||||
self, gpx_file_with_3_segments: str
|
||||
) -> None:
|
||||
"""
|
||||
stopped_speed_threshold to 0 to avoid calculated stopped time
|
||||
in segments
|
||||
"""
|
||||
with patch('builtins.open', return_value=gpx_file_with_3_segments):
|
||||
|
||||
gpx_data, _, _ = get_gpx_info(
|
||||
gpx_file=random_string(), stopped_speed_threshold=0.0
|
||||
)
|
||||
|
||||
assert gpx_data['stop_time'] == timedelta(seconds=120)
|
||||
|
63
fittrackee/tests/workouts/test_utils/test_maps.py
Normal file
63
fittrackee/tests/workouts/test_utils/test_maps.py
Normal file
@ -0,0 +1,63 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from fittrackee.workouts.utils.maps import get_static_map_tile_server_url
|
||||
|
||||
|
||||
class TestGetStaticMapTileServerUrl:
|
||||
@pytest.mark.parametrize(
|
||||
'input_tile_server_url,'
|
||||
'input_tile_server_subdomains,'
|
||||
'expected_tile_server_url',
|
||||
[
|
||||
(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'',
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
),
|
||||
(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'a',
|
||||
'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
),
|
||||
(
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'',
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
),
|
||||
(
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'a',
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_it_returns_tile_server_url(
|
||||
self,
|
||||
input_tile_server_url: str,
|
||||
input_tile_server_subdomains: str,
|
||||
expected_tile_server_url: str,
|
||||
) -> None:
|
||||
tile_config = {
|
||||
'URL': input_tile_server_url,
|
||||
'STATICMAP_SUBDOMAINS': input_tile_server_subdomains,
|
||||
}
|
||||
|
||||
assert (
|
||||
get_static_map_tile_server_url(tile_config)
|
||||
== expected_tile_server_url
|
||||
)
|
||||
|
||||
def test_it_returns_tile_server_url_with_random_subdomain(self) -> None:
|
||||
"""in case multiple subdomains are provided"""
|
||||
tile_config = {
|
||||
'URL': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'STATICMAP_SUBDOMAINS': 'a,b,c',
|
||||
}
|
||||
|
||||
with patch('random.choice', return_value='b'):
|
||||
assert (
|
||||
get_static_map_tile_server_url(tile_config)
|
||||
== 'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png'
|
||||
)
|
@ -9,6 +9,7 @@ from unittest.mock import Mock
|
||||
import pytest
|
||||
from flask import Flask
|
||||
|
||||
from fittrackee import VERSION
|
||||
from fittrackee.users.models import User
|
||||
from fittrackee.workouts.models import Sport, Workout
|
||||
|
||||
@ -442,7 +443,7 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
assert len(data['data']['workouts']) == 1
|
||||
assert data['data']['workouts'][0]['notes'] == input_notes
|
||||
|
||||
def test_it_calls_configured_tile_server_for_static_map(
|
||||
def test_it_calls_configured_tile_server_for_static_map_when_default_static_map_to_false( # noqa
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
@ -473,7 +474,36 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
in call_args[0]
|
||||
)
|
||||
|
||||
def test_it_calls_default_tile_server_for_static_map(
|
||||
def test_it_calls_static_map_with_fittrackee_user_agent_when_default_static_map_to_false( # noqa
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
gpx_file: str,
|
||||
static_map_get_mock: Mock,
|
||||
) -> None:
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app, user_1.email
|
||||
)
|
||||
client.post(
|
||||
'/api/workouts',
|
||||
data=dict(
|
||||
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
|
||||
data='{"sport_id": 1}',
|
||||
),
|
||||
headers=dict(
|
||||
content_type='multipart/form-data',
|
||||
Authorization=f'Bearer {auth_token}',
|
||||
),
|
||||
)
|
||||
|
||||
call_kwargs = self.get_kwargs(static_map_get_mock.call_args)
|
||||
|
||||
assert call_kwargs['headers'] == {
|
||||
'User-Agent': f'FitTrackee v{VERSION}'
|
||||
}
|
||||
|
||||
def test_it_calls_default_tile_server_for_static_map_when_default_static_map_to_true( # noqa
|
||||
self,
|
||||
app_default_static_map: Flask,
|
||||
user_1: User,
|
||||
@ -504,6 +534,35 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
not in call_args[0]
|
||||
)
|
||||
|
||||
def test_it_calls_static_map_with_fittrackee_user_agent_when_default_static_map_to_true( # noqa
|
||||
self,
|
||||
app_default_static_map: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
gpx_file: str,
|
||||
static_map_get_mock: Mock,
|
||||
) -> None:
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app_default_static_map, user_1.email
|
||||
)
|
||||
client.post(
|
||||
'/api/workouts',
|
||||
data=dict(
|
||||
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
|
||||
data='{"sport_id": 1}',
|
||||
),
|
||||
headers=dict(
|
||||
content_type='multipart/form-data',
|
||||
Authorization=f'Bearer {auth_token}',
|
||||
),
|
||||
)
|
||||
|
||||
call_kwargs = self.get_kwargs(static_map_get_mock.call_args)
|
||||
|
||||
assert call_kwargs['headers'] == {
|
||||
'User-Agent': f'FitTrackee v{VERSION}'
|
||||
}
|
||||
|
||||
def test_it_returns_500_if_gpx_file_has_not_tracks(
|
||||
self,
|
||||
app: Flask,
|
||||
@ -527,7 +586,7 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
),
|
||||
)
|
||||
|
||||
data = self.assert_500(response, 'Error during gpx processing.')
|
||||
data = self.assert_500(response, 'error during gpx processing')
|
||||
assert 'data' not in data
|
||||
|
||||
def test_it_returns_500_if_gpx_has_invalid_xml(
|
||||
@ -556,7 +615,7 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
),
|
||||
)
|
||||
|
||||
data = self.assert_500(response, 'Error during gpx file parsing.')
|
||||
data = self.assert_500(response, 'error during gpx file parsing')
|
||||
assert 'data' not in data
|
||||
|
||||
def test_it_returns_400_if_workout_gpx_has_invalid_extension(
|
||||
@ -973,7 +1032,7 @@ class TestPostWorkoutWithZipArchive(ApiTestCaseMixin):
|
||||
),
|
||||
)
|
||||
|
||||
data = self.assert_500(response, 'Error during gpx processing.')
|
||||
data = self.assert_500(response, 'error during gpx processing')
|
||||
assert 'data' not in data
|
||||
|
||||
def test_it_imports_only_max_number_of_files(
|
||||
|
Reference in New Issue
Block a user