Merge pull request 'refactor-data-model' (#17) from refactor-data-model into main
Reviewed-on: https://jouf.fr/gitea/stanislas/resa-padel/pulls/17
This commit is contained in:
commit
0d541e82a5
29 changed files with 4357 additions and 207 deletions
|
@ -3,7 +3,7 @@ import logging
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from gestion_sports_services import GestionSportsServices
|
from gestion_sports_services import GestionSportsServices
|
||||||
from models import Action, BookingFilter, Club, Court, User
|
from models import Action, BookingFilter, Club, Court, Tournament, User
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -51,7 +51,18 @@ async def cancel_booking_id(club: Club, user: User, booking_id: int) -> None:
|
||||||
await service.cancel_booking_id(user, club, booking_id)
|
await service.cancel_booking_id(user, club, booking_id)
|
||||||
|
|
||||||
|
|
||||||
def main() -> tuple[Court, User] | None:
|
async def get_tournaments(club: Club, user: User) -> list[Tournament]:
|
||||||
|
"""
|
||||||
|
Cancel a booking that matches the booking id
|
||||||
|
|
||||||
|
:param club: the club in which the booking was made
|
||||||
|
:param user: the user who made the booking
|
||||||
|
"""
|
||||||
|
service = GestionSportsServices()
|
||||||
|
return await service.get_all_tournaments(user, club)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> tuple[Court, User] | list[Tournament] | None:
|
||||||
"""
|
"""
|
||||||
Main function used to book a court
|
Main function used to book a court
|
||||||
|
|
||||||
|
@ -80,3 +91,8 @@ def main() -> tuple[Court, User] | None:
|
||||||
club = config.get_club()
|
club = config.get_club()
|
||||||
booking_filter = config.get_booking_filter()
|
booking_filter = config.get_booking_filter()
|
||||||
asyncio.run(cancel_booking(club, user, booking_filter))
|
asyncio.run(cancel_booking(club, user, booking_filter))
|
||||||
|
|
||||||
|
elif action == Action.TOURNAMENTS:
|
||||||
|
user = config.get_user()
|
||||||
|
club = config.get_club()
|
||||||
|
return asyncio.run(get_tournaments(club, user))
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
import logging
|
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
|
||||||
from connectors import Connector
|
|
||||||
from models import BookingFilter, Club, User
|
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class BookingService:
|
|
||||||
def __init__(self, club: Club, connector: Connector):
|
|
||||||
LOGGER.info("Initializing booking service at for club", club.name)
|
|
||||||
self.club = club
|
|
||||||
self.connector = connector
|
|
||||||
self.session: ClientSession | None = None
|
|
||||||
|
|
||||||
async def __aenter__(self):
|
|
||||||
self.session = ClientSession()
|
|
||||||
return self
|
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
||||||
await self.session.close()
|
|
||||||
|
|
||||||
async def book(self, user: User, booking_filter: BookingFilter) -> int | None:
|
|
||||||
"""
|
|
||||||
Book a court matching the booking filters for a user.
|
|
||||||
The steps to perform a booking are to go to the landing page, to log in, wait
|
|
||||||
and for the time when booking is open and then actually book the court
|
|
||||||
|
|
||||||
:param user: the user that wants to book a court
|
|
||||||
:param booking_filter: the booking criteria
|
|
||||||
:return: the court number if the booking is successful, None otherwise
|
|
||||||
"""
|
|
||||||
if self.connector is None:
|
|
||||||
LOGGER.error("No connection to Gestion Sports is available")
|
|
||||||
return None
|
|
||||||
|
|
||||||
if user is None or booking_filter is None:
|
|
||||||
LOGGER.error("Not enough information available to book a court")
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.connector.book(user, booking_filter)
|
|
|
@ -143,4 +143,4 @@ def get_action() -> Action:
|
||||||
Get the action to perform from an environment variable
|
Get the action to perform from an environment variable
|
||||||
:return: the action to perform
|
:return: the action to perform
|
||||||
"""
|
"""
|
||||||
return Action(os.environ.get("ACTION"))
|
return Action(os.environ.get("ACTION").lower())
|
||||||
|
|
|
@ -49,6 +49,11 @@ class GestionSportsConnector:
|
||||||
self.club.booking_platform.urls.get(name).path,
|
self.club.booking_platform.urls.get(name).path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _get_url_parameter(self, name: str) -> str:
|
||||||
|
self._check_url_path_exists(name)
|
||||||
|
|
||||||
|
return self.club.booking_platform.urls.get(name).parameter
|
||||||
|
|
||||||
def _get_payload_template(self, name: str) -> Path:
|
def _get_payload_template(self, name: str) -> Path:
|
||||||
"""
|
"""
|
||||||
Get the path to the template file for the service with the given name
|
Get the path to the template file for the service with the given name
|
||||||
|
@ -178,6 +183,18 @@ class GestionSportsConnector:
|
||||||
"""
|
"""
|
||||||
return self._get_payload_template("cancellation")
|
return self._get_payload_template("cancellation")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tournaments_sessions_url(self) -> str:
|
||||||
|
return self._get_url_path("tournament-sessions")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tournaments_sessions_template(self) -> Path:
|
||||||
|
return self._get_payload_template("tournament-sessions")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tournaments_list_url(self) -> str:
|
||||||
|
return self._get_url_path("tournaments-list")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available_sports(self) -> dict[str, Sport]:
|
def available_sports(self) -> dict[str, Sport]:
|
||||||
"""
|
"""
|
||||||
|
@ -209,7 +226,7 @@ class GestionSportsConnector:
|
||||||
payload = PayloadBuilder.build(self.login_template, user=user, club=self.club)
|
payload = PayloadBuilder.build(self.login_template, user=user, club=self.club)
|
||||||
|
|
||||||
async with session.post(
|
async with session.post(
|
||||||
self.login_url, data=payload, headers=POST_HEADERS
|
self.login_url, data=payload, headers=POST_HEADERS, allow_redirects=False
|
||||||
) as response:
|
) as response:
|
||||||
resp_text = await response.text()
|
resp_text = await response.text()
|
||||||
LOGGER.debug("Connexion request response:\n%s", resp_text)
|
LOGGER.debug("Connexion request response:\n%s", resp_text)
|
||||||
|
@ -421,3 +438,23 @@ class GestionSportsConnector:
|
||||||
for booking in bookings:
|
for booking in bookings:
|
||||||
if booking.matches(booking_filter):
|
if booking.matches(booking_filter):
|
||||||
return await self.cancel_booking_id(session, booking.id)
|
return await self.cancel_booking_id(session, booking.id)
|
||||||
|
|
||||||
|
async def send_tournaments_sessions_request(
|
||||||
|
self, session: ClientSession
|
||||||
|
) -> ClientResponse:
|
||||||
|
payload = self.tournaments_sessions_template.read_text()
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
self.tournaments_sessions_url, data=payload, headers=POST_HEADERS
|
||||||
|
) as response:
|
||||||
|
LOGGER.debug("tournament sessions: \n%s", await response.text())
|
||||||
|
return response
|
||||||
|
|
||||||
|
async def send_tournaments_request(
|
||||||
|
self, session: ClientSession, tournement_session_id: str
|
||||||
|
) -> ClientResponse:
|
||||||
|
final_url = self.tournaments_list_url + tournement_session_id
|
||||||
|
LOGGER.debug("Getting tournaments list at %s", final_url)
|
||||||
|
async with session.get(final_url) as response:
|
||||||
|
LOGGER.debug("tournaments: %s\n", await response.text())
|
||||||
|
return response
|
|
@ -1,10 +1,12 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import pendulum
|
import pendulum
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
from connectors import GestionSportsConnector
|
from bs4 import BeautifulSoup
|
||||||
from models import BookingFilter, BookingOpening, Club, Court, User
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
|
from models import BookingFilter, BookingOpening, Club, Court, Tournament, User
|
||||||
from pendulum import DateTime
|
from pendulum import DateTime
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -125,3 +127,62 @@ class GestionSportsServices:
|
||||||
booking_minute = opening_time.minute
|
booking_minute = opening_time.minute
|
||||||
|
|
||||||
return booking_date.at(booking_hour, booking_minute)
|
return booking_date.at(booking_hour, booking_minute)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_all_tournaments(user: User, club: Club) -> list[Tournament]:
|
||||||
|
connector = GestionSportsConnector(club)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
session_html = await connector.send_tournaments_sessions_request(session)
|
||||||
|
tournaments_id = GestionSportsServices.retrieve_tournament_session(
|
||||||
|
await session_html.text()
|
||||||
|
)
|
||||||
|
|
||||||
|
tournaments = await connector.send_tournaments_request(
|
||||||
|
session, tournaments_id
|
||||||
|
)
|
||||||
|
return GestionSportsServices.retrieve_tournaments(await tournaments.text())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def retrieve_tournament_session(sessions: str) -> str:
|
||||||
|
session_object = json.loads(sessions).get("Inscription tournois:school-outline")
|
||||||
|
return list(session_object.keys())[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def retrieve_tournaments(html: str) -> list[Tournament]:
|
||||||
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
|
tournaments = []
|
||||||
|
|
||||||
|
cards = soup.find_all("div", {"class": "card-body"})
|
||||||
|
for card in cards:
|
||||||
|
title = card.find("h5")
|
||||||
|
price = title.find("span").get_text().strip()
|
||||||
|
name = title.get_text().strip().removesuffix(price).strip()
|
||||||
|
elements = card.find("div", {"class": "row"}).find_all("li")
|
||||||
|
date = elements[0].get_text().strip()
|
||||||
|
start_time, end_time = (
|
||||||
|
elements[2].get_text().strip().replace("h", ":").split(" - ")
|
||||||
|
)
|
||||||
|
start_datetime = pendulum.from_format(
|
||||||
|
f"{date} {start_time}", "DD/MM/YYYY HH:mm"
|
||||||
|
)
|
||||||
|
end_datetime = pendulum.from_format(
|
||||||
|
f"{date} {end_time}", "DD/MM/YYYY HH:mm"
|
||||||
|
)
|
||||||
|
gender = elements[1].get_text().strip()
|
||||||
|
places_left = (
|
||||||
|
card.find("span", {"class": "nb_place_libre"}).get_text().strip()
|
||||||
|
)
|
||||||
|
tournament = Tournament(
|
||||||
|
name=name,
|
||||||
|
price=price,
|
||||||
|
start_date=start_datetime,
|
||||||
|
end_date=end_datetime,
|
||||||
|
gender=gender,
|
||||||
|
places_left=places_left,
|
||||||
|
)
|
||||||
|
tournaments.append(tournament)
|
||||||
|
|
||||||
|
return tournaments
|
||||||
|
|
|
@ -70,6 +70,7 @@ class Sport(BaseModel):
|
||||||
class Url(BaseModel):
|
class Url(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
path: str
|
path: str
|
||||||
|
parameter: Optional[str] = Field(default=None)
|
||||||
payload_template: Optional[str] = Field(default=None, alias="payloadTemplate")
|
payload_template: Optional[str] = Field(default=None, alias="payloadTemplate")
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,3 +211,13 @@ class Booking(BaseModel):
|
||||||
class Action(Enum):
|
class Action(Enum):
|
||||||
BOOK = "book"
|
BOOK = "book"
|
||||||
CANCEL = "cancel"
|
CANCEL = "cancel"
|
||||||
|
TOURNAMENTS = "tournaments"
|
||||||
|
|
||||||
|
|
||||||
|
class Tournament(BaseModel):
|
||||||
|
name: str
|
||||||
|
price: str
|
||||||
|
start_date: DateTime
|
||||||
|
end_date: DateTime
|
||||||
|
gender: str
|
||||||
|
places_left: str | int
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
{
|
{
|
||||||
"Connection": "keep-alive",
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||||
"Accept-Language": "en-US,en;q=0.5",
|
"Accept-Language": "en-US,en;q=0.5",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"DNT": "1",
|
"Cache-Control": "no-cache",
|
||||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
"Connection": "keep-alive",
|
||||||
"X-Requested-With": "XMLHttpRequest",
|
"DNT": "1",
|
||||||
|
"Origin": "https://toulousepadelclub.gestion-sports.com",
|
||||||
|
"Pragma": "no-cache",
|
||||||
"Sec-Fetch-Dest": "empty",
|
"Sec-Fetch-Dest": "empty",
|
||||||
"Sec-Fetch-Mode": "cors",
|
"Sec-Fetch-Mode": "cors",
|
||||||
"Sec-Fetch-Site": "same-origin"
|
"Sec-Fetch-Site": "same-origin",
|
||||||
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0",
|
||||||
|
"X-Requested-With": "XMLHttpRequest"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ajax=loadSessionForSpecDay&date=all
|
|
@ -17,3 +17,8 @@ platforms:
|
||||||
- name: cancellation
|
- name: cancellation
|
||||||
path: /membre/mesresas.html
|
path: /membre/mesresas.html
|
||||||
payloadTemplate: gestion-sports/booking-cancellation-payload.txt
|
payloadTemplate: gestion-sports/booking-cancellation-payload.txt
|
||||||
|
- name: tournament-sessions
|
||||||
|
path: /membre/index.php
|
||||||
|
payloadTemplate: gestion-sports/tournament-sessions-payload.txt
|
||||||
|
- name: tournaments-list
|
||||||
|
path: /membre/events/event.html?event=
|
||||||
|
|
|
@ -16,4 +16,9 @@ platforms:
|
||||||
payloadTemplate: gestion-sports/user-bookings-payload.txt
|
payloadTemplate: gestion-sports/user-bookings-payload.txt
|
||||||
- name: cancellation
|
- name: cancellation
|
||||||
path: /cancel.html
|
path: /cancel.html
|
||||||
payloadTemplate: gestion-sports/booking-cancellation-payload.txt
|
payloadTemplate: sports/booking-cancellation-payload.txt
|
||||||
|
- name: tournament-sessions
|
||||||
|
path: /membre/index.php
|
||||||
|
payloadTemplate: sports/tournament-sessions-payload.txt
|
||||||
|
- name: tournament-list
|
||||||
|
path: /membre/events/event.html?event=
|
||||||
|
|
1380
tests/data/responses/tournament-sessions.html
Normal file
1380
tests/data/responses/tournament-sessions.html
Normal file
File diff suppressed because it is too large
Load diff
21
tests/data/responses/tournament-sessions.json
Normal file
21
tests/data/responses/tournament-sessions.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"Inscription tournois:school-outline": {
|
||||||
|
"1174": {
|
||||||
|
"id": 1174,
|
||||||
|
"sport": "padel",
|
||||||
|
"clubName": "toulouse padel club",
|
||||||
|
"nom": "Tournoi",
|
||||||
|
"dateNextSession": "25\/03\/2024",
|
||||||
|
"dateDebut": "01\/08\/2022",
|
||||||
|
"dateFin": "01\/10\/2024",
|
||||||
|
"logo": "TCP_Ligue_Arcanthe2-01-min.png",
|
||||||
|
"nbSession": 14,
|
||||||
|
"icon": "school-outline",
|
||||||
|
"playerCanSeeThisEvent": null,
|
||||||
|
"type": "tournoi",
|
||||||
|
"isJp": false,
|
||||||
|
"isCiup": false,
|
||||||
|
"sqlDate": "2024-03-25 13:30:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2459
tests/data/responses/tournaments.html
Normal file
2459
tests/data/responses/tournaments.html
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||||
import config
|
import config
|
||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from connectors import GestionSportsConnector
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
from models import BookingFilter, Club, User
|
from models import BookingFilter, Club, User
|
||||||
|
|
||||||
TEST_FOLDER = Path(__file__).parent.parent
|
TEST_FOLDER = Path(__file__).parent.parent
|
||||||
|
@ -36,11 +36,17 @@ def booking_filter() -> BookingFilter:
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_success_response() -> dict:
|
def booking_success_response() -> dict:
|
||||||
booking_success_file = RESPONSES_FOLDER / "booking_success.json"
|
booking_success_file = RESPONSES_FOLDER / "booking-success.json"
|
||||||
return json.loads(booking_success_file.read_text(encoding="utf-8"))
|
return json.loads(booking_success_file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_failure_response() -> dict:
|
def booking_failure_response() -> dict:
|
||||||
booking_failure_file = RESPONSES_FOLDER / "booking_failure.json"
|
file = RESPONSES_FOLDER / "booking-failure.json"
|
||||||
return json.loads(booking_failure_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tournament_sessions_json() -> str:
|
||||||
|
file = RESPONSES_FOLDER / "tournament-sessions.json"
|
||||||
|
return file.read_text(encoding="utf-8")
|
||||||
|
|
|
@ -57,3 +57,18 @@ def test_main_booking():
|
||||||
)
|
)
|
||||||
def test_main_cancellation():
|
def test_main_cancellation():
|
||||||
booking.main()
|
booking.main()
|
||||||
|
|
||||||
|
|
||||||
|
@patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"CLUB_ID": "tpc",
|
||||||
|
"ACTION": "tournaments",
|
||||||
|
"LOGIN": "padel.testing@jouf.fr",
|
||||||
|
"PASSWORD": "ridicule",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
)
|
||||||
|
def test_main_tournaments():
|
||||||
|
tournaments = booking.main()
|
||||||
|
assert len(tournaments) != 0
|
||||||
|
|
|
@ -1,36 +1,15 @@
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from connectors import GestionSportsConnector
|
from aiohttp import ClientSession
|
||||||
from models import BookingFilter, Club
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
from pendulum import DateTime
|
|
||||||
from yarl import URL
|
from yarl import URL
|
||||||
|
|
||||||
|
|
||||||
def retrieve_booking_datetime(
|
|
||||||
a_booking_filter: BookingFilter, a_club: Club
|
|
||||||
) -> DateTime:
|
|
||||||
"""
|
|
||||||
Utility to retrieve the booking datetime from the booking filter and the club
|
|
||||||
|
|
||||||
:param a_booking_filter: the booking filter that contains the date to book
|
|
||||||
:param a_club: the club which has the number of days before the date and the booking time
|
|
||||||
"""
|
|
||||||
booking_opening = a_club.booking_platform.booking_opening
|
|
||||||
opening_time = pendulum.parse(booking_opening.opening_time)
|
|
||||||
booking_hour = opening_time.hour
|
|
||||||
booking_minute = opening_time.minute
|
|
||||||
|
|
||||||
date_to_book = a_booking_filter.date
|
|
||||||
return date_to_book.subtract(days=booking_opening.days_before).at(
|
|
||||||
booking_hour, booking_minute
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
@patch.dict(
|
||||||
os.environ,
|
os.environ,
|
||||||
{"CLUB_ID": "tpc"},
|
{"CLUB_ID": "tpc"},
|
||||||
|
@ -57,6 +36,10 @@ def test_urls(connector):
|
||||||
connector.booking_cancellation_url
|
connector.booking_cancellation_url
|
||||||
== "https://toulousepadelclub.gestion-sports.com/membre/mesresas.html"
|
== "https://toulousepadelclub.gestion-sports.com/membre/mesresas.html"
|
||||||
)
|
)
|
||||||
|
assert (
|
||||||
|
connector.tournaments_sessions_url
|
||||||
|
== "https://toulousepadelclub.gestion-sports.com/membre/index.php"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
@patch.dict(
|
||||||
|
@ -76,11 +59,15 @@ def test_urls_payload_templates(connector):
|
||||||
connector.booking_cancel_template
|
connector.booking_cancel_template
|
||||||
== resources_folder / "booking-cancellation-payload.txt"
|
== resources_folder / "booking-cancellation-payload.txt"
|
||||||
)
|
)
|
||||||
|
assert (
|
||||||
|
connector.tournaments_sessions_template
|
||||||
|
== resources_folder / "tournament-sessions-payload.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_landing_page(connector):
|
async def test_landing_page(connector):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
response = await connector.land(session)
|
response = await connector.land(session)
|
||||||
|
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
@ -93,7 +80,7 @@ async def test_landing_page(connector):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_login(connector, user):
|
async def test_login(connector, user):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
|
|
||||||
response = await connector.login(session, user)
|
response = await connector.login(session, user)
|
||||||
|
@ -128,7 +115,7 @@ def test_get_booked_court(
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_book_one_court(connector, user, booking_filter):
|
async def test_book_one_court(connector, user, booking_filter):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
@ -156,28 +143,9 @@ def test_build_booking_datetime(connector, booking_filter):
|
||||||
assert opening_datetime.minute == 0
|
assert opening_datetime.minute == 0
|
||||||
|
|
||||||
|
|
||||||
@patch("pendulum.now")
|
|
||||||
def test_wait_until_booking_time(mock_now, connector, booking_filter, club):
|
|
||||||
booking_datetime = retrieve_booking_datetime(booking_filter, club)
|
|
||||||
|
|
||||||
seconds = [
|
|
||||||
booking_datetime.subtract(seconds=3),
|
|
||||||
booking_datetime.subtract(seconds=2),
|
|
||||||
booking_datetime.subtract(seconds=1),
|
|
||||||
booking_datetime,
|
|
||||||
booking_datetime.add(microseconds=1),
|
|
||||||
booking_datetime.add(microseconds=2),
|
|
||||||
]
|
|
||||||
mock_now.side_effect = seconds
|
|
||||||
|
|
||||||
connector.wait_until_booking_time(booking_filter)
|
|
||||||
|
|
||||||
assert pendulum.now() == booking_datetime.add(microseconds=1)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_hash(connector, user):
|
async def test_get_hash(connector, user):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
@ -197,7 +165,7 @@ def test_get_hash_input():
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_bookings(connector, user):
|
async def test_get_bookings(connector, user):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
@ -210,7 +178,7 @@ async def test_get_bookings(connector, user):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_ongoing_bookings(connector, user):
|
async def test_get_ongoing_bookings(connector, user):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
@ -218,20 +186,13 @@ async def test_get_ongoing_bookings(connector, user):
|
||||||
print(bookings)
|
print(bookings)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_has_user_ongoing_bookings(connector, user):
|
|
||||||
assert await connector.has_user_ongoing_booking(user)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking_id(connector, user):
|
async def test_cancel_booking_id(connector, user):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
ongoing_bookings = await connector.get_ongoing_bookings(session)
|
|
||||||
booking_id = ongoing_bookings[0].id
|
|
||||||
|
|
||||||
response = await connector.cancel_booking_id(user, booking_id)
|
await connector.cancel_booking_id(session, 666)
|
||||||
|
|
||||||
assert len(await connector.get_ongoing_bookings(session)) == 0
|
assert len(await connector.get_ongoing_bookings(session)) == 0
|
||||||
|
|
||||||
|
@ -245,7 +206,33 @@ def test_find_court(connector):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking(connector, user, booking_filter):
|
async def test_cancel_booking(connector, user, booking_filter):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
await connector.cancel_booking(session, booking_filter)
|
await connector.cancel_booking(session, booking_filter)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tournament_sessions(connector, user):
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
response = await connector.send_tournaments_sessions_request(session)
|
||||||
|
|
||||||
|
assert response.status == 200
|
||||||
|
|
||||||
|
all_sessions = json.loads(await response.text())
|
||||||
|
sessions = all_sessions.get("Inscription tournois:school-outline")
|
||||||
|
assert len(sessions) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_tournaments_request(connector, user):
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
tournament_session_id = "1174"
|
||||||
|
response = await connector.send_tournaments_request(
|
||||||
|
session, tournament_session_id
|
||||||
|
)
|
||||||
|
assert "<span class='nb_place_libre'>Complet</span>" in await response.text()
|
|
@ -18,3 +18,9 @@ async def test_user_has_available_slots(club, user):
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking(club, user, booking_filter):
|
async def test_cancel_booking(club, user, booking_filter):
|
||||||
await GestionSportsServices.cancel_booking(user, club, booking_filter)
|
await GestionSportsServices.cancel_booking(user, club, booking_filter)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_all_tournaments(user, club):
|
||||||
|
tournaments = await GestionSportsServices.get_all_tournaments(user, club)
|
||||||
|
assert len(tournaments) == 14
|
||||||
|
|
|
@ -3,7 +3,7 @@ from pathlib import Path
|
||||||
|
|
||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from connectors import GestionSportsConnector
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
from gestion_sports_services import GestionSportsServices
|
from gestion_sports_services import GestionSportsServices
|
||||||
from models import (
|
from models import (
|
||||||
BookingFilter,
|
BookingFilter,
|
||||||
|
@ -43,7 +43,7 @@ def court14() -> Court:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def sport1(court11, court12, court13, court14) -> Sport:
|
def sport1(court11: Court, court12: Court, court13: Court, court14: Court) -> Sport:
|
||||||
return Sport(
|
return Sport(
|
||||||
name="Sport1",
|
name="Sport1",
|
||||||
id=8,
|
id=8,
|
||||||
|
@ -75,7 +75,7 @@ def court24() -> Court:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def sport2(court21, court22, court23, court24) -> Sport:
|
def sport2(court21: Court, court22: Court, court23: Court, court24: Court) -> Sport:
|
||||||
return Sport(
|
return Sport(
|
||||||
name="Sport 2",
|
name="Sport 2",
|
||||||
id=10,
|
id=10,
|
||||||
|
@ -130,9 +130,26 @@ def cancellation_url() -> Url:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tournament_sessions_url() -> Url:
|
||||||
|
return Url(
|
||||||
|
name="tournament-sessions",
|
||||||
|
path="/tournaments_sessions.php",
|
||||||
|
payloadTemplate="gestion-sports/tournament-sessions-payload.txt",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tournaments_list_url() -> Url:
|
||||||
|
return Url(
|
||||||
|
name="tournaments-list",
|
||||||
|
path="/tournaments_list.html?event=",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_opening() -> BookingOpening:
|
def booking_opening() -> BookingOpening:
|
||||||
return BookingOpening(daysBefore=10, time="03:27")
|
return BookingOpening(daysBefore=7, time="00:00")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -142,15 +159,17 @@ def total_bookings() -> TotalBookings:
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_platform(
|
def booking_platform(
|
||||||
booking_opening,
|
booking_opening: BookingOpening,
|
||||||
total_bookings,
|
total_bookings: TotalBookings,
|
||||||
sport1,
|
sport1: Sport,
|
||||||
sport2,
|
sport2: Sport,
|
||||||
landing_url,
|
landing_url: str,
|
||||||
login_url,
|
login_url: str,
|
||||||
booking_url,
|
booking_url: str,
|
||||||
user_bookings_url,
|
user_bookings_url: str,
|
||||||
cancellation_url,
|
cancellation_url: str,
|
||||||
|
tournament_sessions_url: str,
|
||||||
|
tournaments_list_url: str,
|
||||||
) -> BookingPlatform:
|
) -> BookingPlatform:
|
||||||
return BookingPlatform(
|
return BookingPlatform(
|
||||||
id="gestion-sports",
|
id="gestion-sports",
|
||||||
|
@ -166,12 +185,14 @@ def booking_platform(
|
||||||
"booking": booking_url,
|
"booking": booking_url,
|
||||||
"user-bookings": user_bookings_url,
|
"user-bookings": user_bookings_url,
|
||||||
"cancellation": cancellation_url,
|
"cancellation": cancellation_url,
|
||||||
|
"tournament-sessions": tournament_sessions_url,
|
||||||
|
"tournaments-list": tournaments_list_url,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def club(booking_platform) -> Club:
|
def club(booking_platform: BookingPlatform) -> Club:
|
||||||
return Club(
|
return Club(
|
||||||
id="super_club",
|
id="super_club",
|
||||||
name="Super Club",
|
name="Super Club",
|
||||||
|
@ -204,42 +225,42 @@ def booking_filter() -> BookingFilter:
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def landing_response() -> str:
|
def landing_response() -> str:
|
||||||
landing_response_file = RESPONSES_FOLDER / "landing_response.html"
|
file = RESPONSES_FOLDER / "landing-response.html"
|
||||||
return landing_response_file.read_text(encoding="utf-8")
|
return file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def login_success_response() -> dict:
|
def login_success_response() -> dict:
|
||||||
login_success_file = RESPONSES_FOLDER / "login_success.json"
|
login_success_file = RESPONSES_FOLDER / "login-success.json"
|
||||||
return json.loads(login_success_file.read_text(encoding="utf-8"))
|
return json.loads(login_success_file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def login_failure_response() -> dict:
|
def login_failure_response() -> dict:
|
||||||
login_failure_file = RESPONSES_FOLDER / "login_failure.json"
|
file = RESPONSES_FOLDER / "login-failure.json"
|
||||||
return json.loads(login_failure_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_success_response() -> dict:
|
def booking_success_response() -> dict:
|
||||||
booking_success_file = RESPONSES_FOLDER / "booking_success.json"
|
file = RESPONSES_FOLDER / "booking-success.json"
|
||||||
return json.loads(booking_success_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_failure_response() -> dict:
|
def booking_failure_response() -> dict:
|
||||||
booking_failure_file = RESPONSES_FOLDER / "booking_failure.json"
|
file = RESPONSES_FOLDER / "booking-failure.json"
|
||||||
return json.loads(booking_failure_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booked_courts_response(
|
def booked_courts_response(
|
||||||
court11,
|
court11: int,
|
||||||
court12,
|
court12: int,
|
||||||
court13,
|
court13: int,
|
||||||
court14,
|
court14: int,
|
||||||
booking_success_response,
|
booking_success_response: dict,
|
||||||
booking_failure_response,
|
booking_failure_response: dict,
|
||||||
) -> list[tuple[int, dict]]:
|
) -> list[tuple[int, dict]]:
|
||||||
court1_resp = court11.id, booking_failure_response
|
court1_resp = court11.id, booking_failure_response
|
||||||
court2_resp = court12.id, booking_failure_response
|
court2_resp = court12.id, booking_failure_response
|
||||||
|
@ -250,10 +271,10 @@ def booked_courts_response(
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_success_from_start(
|
def booking_success_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
booking_success_response,
|
booking_success_response: str,
|
||||||
booking_failure_response,
|
booking_failure_response: str,
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -267,10 +288,10 @@ def booking_success_from_start(
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_failure_from_start(
|
def booking_failure_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
booking_success_response,
|
booking_success_response: str,
|
||||||
booking_failure_response,
|
booking_failure_response: str,
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -284,22 +305,22 @@ def booking_failure_from_start(
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user_bookings_get_response() -> str:
|
def user_bookings_get_response() -> str:
|
||||||
user_bookings_file = RESPONSES_FOLDER / "user_bookings_get.html"
|
file = RESPONSES_FOLDER / "user-bookings-get.html"
|
||||||
return user_bookings_file.read_text(encoding="utf-8")
|
return file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user_bookings_list() -> list:
|
def user_bookings_list() -> str:
|
||||||
user_bookings_file = RESPONSES_FOLDER / "user_bookings_post.json"
|
file = RESPONSES_FOLDER / "user-bookings-post.json"
|
||||||
return json.loads(user_bookings_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user_has_ongoing_bookings_from_start(
|
def user_has_ongoing_bookings_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
user_bookings_get_response,
|
user_bookings_get_response: str,
|
||||||
user_bookings_list,
|
user_bookings_list: str,
|
||||||
) -> list:
|
) -> list:
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -316,10 +337,10 @@ def user_bookings_empty_list() -> list:
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user_has_no_ongoing_bookings_from_start(
|
def user_has_no_ongoing_bookings_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
user_bookings_get_response,
|
user_bookings_get_response: str,
|
||||||
user_bookings_empty_list,
|
user_bookings_empty_list: str,
|
||||||
) -> list:
|
) -> list:
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -331,16 +352,16 @@ def user_has_no_ongoing_bookings_from_start(
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def cancellation_response() -> list:
|
def cancellation_response() -> list:
|
||||||
cancellation_response_file = RESPONSES_FOLDER / "cancellation_response.json"
|
file = RESPONSES_FOLDER / "cancellation-response.json"
|
||||||
return json.loads(cancellation_response_file.read_text(encoding="utf-8"))
|
return json.loads(file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def cancellation_by_id_from_start(
|
def cancellation_by_id_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
user_bookings_get_response,
|
user_bookings_get_response: str,
|
||||||
cancellation_response,
|
cancellation_response: str,
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -352,11 +373,11 @@ def cancellation_by_id_from_start(
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def cancellation_success_from_start(
|
def cancellation_success_from_start(
|
||||||
landing_response,
|
landing_response: str,
|
||||||
login_success_response,
|
login_success_response: str,
|
||||||
user_bookings_get_response,
|
user_bookings_get_response: str,
|
||||||
user_bookings_list,
|
user_bookings_list: str,
|
||||||
cancellation_response,
|
cancellation_response: str,
|
||||||
):
|
):
|
||||||
return [
|
return [
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -377,3 +398,30 @@ def cancellation_success_booking_filter() -> BookingFilter:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def service() -> GestionSportsServices:
|
def service() -> GestionSportsServices:
|
||||||
return GestionSportsServices()
|
return GestionSportsServices()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tournament_sessions_json() -> str:
|
||||||
|
file = RESPONSES_FOLDER / "tournament-sessions.json"
|
||||||
|
return file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tournaments_html() -> str:
|
||||||
|
file = RESPONSES_FOLDER / "tournaments.html"
|
||||||
|
return file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def full_tournaments_responses(
|
||||||
|
landing_response: str,
|
||||||
|
login_success_response: str,
|
||||||
|
tournament_sessions_json: str,
|
||||||
|
tournaments_html: str,
|
||||||
|
) -> list[str]:
|
||||||
|
return [
|
||||||
|
landing_response,
|
||||||
|
login_success_response,
|
||||||
|
tournament_sessions_json,
|
||||||
|
tournaments_html,
|
||||||
|
]
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
|
|
||||||
|
|
||||||
def make_landing_request_success(aioresponses, connector, landing_response):
|
def make_landing_request_success(aioresponses, connector, landing_response):
|
||||||
aioresponses.get(
|
aioresponses.get(
|
||||||
connector.landing_url,
|
connector.landing_url,
|
||||||
|
@ -54,6 +57,26 @@ def set_bookings_response(aioresponses, connector, user_bookings_post_response):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_tournaments_sessions_response(
|
||||||
|
aioresponses, connector: GestionSportsConnector, tournaments_sessions_response
|
||||||
|
):
|
||||||
|
aioresponses.post(
|
||||||
|
connector.tournaments_sessions_url,
|
||||||
|
status=200,
|
||||||
|
body=tournaments_sessions_response,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_tournaments_list_response(
|
||||||
|
aioresponses,
|
||||||
|
connector: GestionSportsConnector,
|
||||||
|
tournament_id,
|
||||||
|
tournaments_list_response,
|
||||||
|
):
|
||||||
|
url = f"{connector.tournaments_list_url}{tournament_id}"
|
||||||
|
aioresponses.get(url, status=200, body=tournaments_list_response)
|
||||||
|
|
||||||
|
|
||||||
def set_full_user_bookings_responses(aioresponses, connector, responses):
|
def set_full_user_bookings_responses(aioresponses, connector, responses):
|
||||||
make_landing_request_success(aioresponses, connector, responses[0])
|
make_landing_request_success(aioresponses, connector, responses[0])
|
||||||
make_login_request_success(aioresponses, connector, responses[1])
|
make_login_request_success(aioresponses, connector, responses[1])
|
||||||
|
@ -81,3 +104,11 @@ def set_full_cancellation_responses(aioresponses, connector, responses):
|
||||||
|
|
||||||
set_bookings_response(aioresponses, connector, responses[3])
|
set_bookings_response(aioresponses, connector, responses[3])
|
||||||
set_cancellation_response(aioresponses, connector, responses[4])
|
set_cancellation_response(aioresponses, connector, responses[4])
|
||||||
|
|
||||||
|
|
||||||
|
def set_full_tournaments_requests(aioresponses, connector, responses, tournament_id):
|
||||||
|
make_landing_request_success(aioresponses, connector, responses[0])
|
||||||
|
make_login_request_success(aioresponses, connector, responses[1])
|
||||||
|
|
||||||
|
set_tournaments_sessions_response(aioresponses, connector, responses[2])
|
||||||
|
set_tournaments_list_response(aioresponses, connector, tournament_id, responses[3])
|
||||||
|
|
|
@ -1,31 +1,24 @@
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
from connectors import GestionSportsConnector
|
from gestion_sport_connector import GestionSportsConnector
|
||||||
|
|
||||||
from tests.unit_tests import responses
|
from tests.unit_tests import responses
|
||||||
|
|
||||||
|
|
||||||
def test_urls(connector, club):
|
def test_urls(connector, club):
|
||||||
base_url = club.booking_platform.url
|
base_url = "https://ptf1.com"
|
||||||
relative_urls = club.booking_platform.urls
|
|
||||||
|
|
||||||
relative_landing_url = relative_urls.get("landing-page").path
|
assert connector.landing_url == f"{base_url}/landing.html"
|
||||||
assert connector.landing_url == f"{base_url}/{relative_landing_url}"
|
assert connector.login_url == f"{base_url}/login.html"
|
||||||
|
assert connector.booking_url == f"{base_url}/booking.html"
|
||||||
relative_login_url = relative_urls.get("login").path
|
assert connector.user_bookings_url == f"{base_url}/user_bookings.html"
|
||||||
assert connector.login_url == f"{base_url}/{relative_login_url}"
|
assert connector.booking_cancellation_url == f"{base_url}/cancel.html"
|
||||||
|
assert connector.tournaments_sessions_url == f"{base_url}/tournaments_sessions.php"
|
||||||
relative_booking_url = relative_urls.get("booking").path
|
assert connector.tournaments_list_url == f"{base_url}/tournaments_list.html?event="
|
||||||
assert connector.booking_url == f"{base_url}/{relative_booking_url}"
|
|
||||||
|
|
||||||
relative_user_bookings_url = relative_urls.get("user-bookings").path
|
|
||||||
assert connector.user_bookings_url == f"{base_url}/{relative_user_bookings_url}"
|
|
||||||
|
|
||||||
relative_cancel_url = relative_urls.get("cancellation").path
|
|
||||||
assert connector.booking_cancellation_url == f"{base_url}/{relative_cancel_url}"
|
|
||||||
|
|
||||||
|
|
||||||
@patch("config.get_resources_folder")
|
@patch("config.get_resources_folder")
|
||||||
|
@ -34,19 +27,27 @@ def test_urls_payload_templates(mock_resources, club):
|
||||||
mock_resources.return_value = path_to_resources
|
mock_resources.return_value = path_to_resources
|
||||||
|
|
||||||
connector = GestionSportsConnector(club)
|
connector = GestionSportsConnector(club)
|
||||||
relative_urls = club.booking_platform.urls
|
|
||||||
|
|
||||||
login_payload = relative_urls.get("login").payload_template
|
assert (
|
||||||
assert connector.login_template == path_to_resources / login_payload
|
connector.login_template
|
||||||
|
== path_to_resources / "gestion-sports/login-payload.txt"
|
||||||
booking_payload = relative_urls.get("booking").payload_template
|
)
|
||||||
assert connector.booking_template == path_to_resources / booking_payload
|
assert (
|
||||||
|
connector.booking_template
|
||||||
user_bookings_payload = relative_urls.get("user-bookings").payload_template
|
== path_to_resources / "gestion-sports/booking-payload.txt"
|
||||||
assert connector.user_bookings_template == path_to_resources / user_bookings_payload
|
)
|
||||||
|
assert (
|
||||||
cancel_payload = relative_urls.get("cancellation").payload_template
|
connector.user_bookings_template
|
||||||
assert connector.booking_cancel_template == path_to_resources / cancel_payload
|
== path_to_resources / "gestion-sports/user-bookings-payload.txt"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
connector.booking_cancel_template
|
||||||
|
== path_to_resources / "gestion-sports/booking-cancellation-payload.txt"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
connector.tournaments_sessions_template
|
||||||
|
== path_to_resources / "gestion-sports/tournament-sessions-payload.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
@ -143,3 +144,35 @@ async def test_cancel_booking_success(
|
||||||
)
|
)
|
||||||
|
|
||||||
assert await response.json() == cancellation_success_from_start[4]
|
assert await response.json() == cancellation_success_from_start[4]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tournament_sessions(
|
||||||
|
aioresponses, connector, user, tournament_sessions_json
|
||||||
|
):
|
||||||
|
responses.set_tournaments_sessions_response(
|
||||||
|
aioresponses, connector, tournament_sessions_json
|
||||||
|
)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
response = await connector.send_tournaments_sessions_request(session)
|
||||||
|
|
||||||
|
assert response.status == 200
|
||||||
|
|
||||||
|
all_sessions = json.loads(await response.text())
|
||||||
|
sessions = all_sessions.get("Inscription tournois:school-outline")
|
||||||
|
assert len(sessions) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_tournaments_request(
|
||||||
|
aioresponses, connector, user, tournaments_html
|
||||||
|
):
|
||||||
|
tournament_session_id = "255"
|
||||||
|
responses.set_tournaments_list_response(
|
||||||
|
aioresponses, connector, tournament_session_id, tournaments_html
|
||||||
|
)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
response = await connector.send_tournaments_request(
|
||||||
|
session, tournament_session_id
|
||||||
|
)
|
||||||
|
assert "<span class='nb_place_libre'>Complet</span>" in await response.text()
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from gestion_sports_services import GestionSportsServices
|
from gestion_sports_services import GestionSportsServices
|
||||||
|
from models import BookingFilter, BookingOpening
|
||||||
|
|
||||||
from tests.unit_tests import responses
|
from tests.unit_tests import responses
|
||||||
|
|
||||||
|
@ -108,3 +112,65 @@ async def test_cancel_booking_id(
|
||||||
)
|
)
|
||||||
|
|
||||||
await gs_services.cancel_booking_id(user, club, 65464)
|
await gs_services.cancel_booking_id(user, club, 65464)
|
||||||
|
|
||||||
|
|
||||||
|
@patch("pendulum.now")
|
||||||
|
def test_wait_until_booking_time(mock_now, club, user):
|
||||||
|
booking_filter = BookingFilter(
|
||||||
|
sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00+01:00")
|
||||||
|
)
|
||||||
|
|
||||||
|
booking_datetime = pendulum.parse("2024-03-14T00:00:00+01:00")
|
||||||
|
|
||||||
|
seconds = [
|
||||||
|
booking_datetime.subtract(seconds=3),
|
||||||
|
booking_datetime.subtract(seconds=2),
|
||||||
|
booking_datetime.subtract(seconds=1),
|
||||||
|
booking_datetime,
|
||||||
|
booking_datetime.add(microseconds=1),
|
||||||
|
booking_datetime.add(microseconds=2),
|
||||||
|
]
|
||||||
|
mock_now.side_effect = seconds
|
||||||
|
|
||||||
|
booking_opening = club.booking_platform.booking_opening
|
||||||
|
|
||||||
|
GestionSportsServices.wait_until_booking_time(booking_filter, booking_opening)
|
||||||
|
|
||||||
|
assert pendulum.now() == booking_datetime.add(microseconds=1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_booking_time():
|
||||||
|
booking_filter = BookingFilter(
|
||||||
|
sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00+01:00")
|
||||||
|
)
|
||||||
|
booking_opening = BookingOpening(daysBefore=7, time="00:00")
|
||||||
|
|
||||||
|
booking_time = GestionSportsServices.build_booking_datetime(
|
||||||
|
booking_filter, booking_opening
|
||||||
|
)
|
||||||
|
|
||||||
|
assert booking_time == pendulum.parse("2024-03-13T23:00:00Z")
|
||||||
|
|
||||||
|
|
||||||
|
def test_retrieve_tournament_id(tournament_sessions_json):
|
||||||
|
session_id = GestionSportsServices.retrieve_tournament_session(
|
||||||
|
tournament_sessions_json
|
||||||
|
)
|
||||||
|
|
||||||
|
assert session_id == "1174"
|
||||||
|
|
||||||
|
|
||||||
|
def test_retrieve_tournaments(tournaments_html):
|
||||||
|
tournaments = GestionSportsServices.retrieve_tournaments(tournaments_html)
|
||||||
|
assert len(tournaments) == 14
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_all_tournaments(
|
||||||
|
aioresponses, user, connector, club, full_tournaments_responses
|
||||||
|
):
|
||||||
|
responses.set_full_tournaments_requests(
|
||||||
|
aioresponses, connector, full_tournaments_responses, 1174
|
||||||
|
)
|
||||||
|
tournaments = await GestionSportsServices.get_all_tournaments(user, club)
|
||||||
|
assert len(tournaments) == 14
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue