created a gestion sports services class that handles the connection while the connector is dedicated to the requests
This commit is contained in:
parent
bcd8dc0733
commit
e6023e0687
12 changed files with 513 additions and 593 deletions
|
@ -2,17 +2,12 @@ import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from connectors import Connector, GestionSportsConnector
|
from gestion_sports_services import GestionSportsServices
|
||||||
from models import Action, BookingFilter, Club, Court, User
|
from models import Action, BookingFilter, Club, Court, User
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_connector(club: Club) -> Connector:
|
|
||||||
if club.booking_platform.id == "gestion-sports":
|
|
||||||
return GestionSportsConnector(club)
|
|
||||||
|
|
||||||
|
|
||||||
async def book_court(
|
async def book_court(
|
||||||
club: Club, users: list[User], booking_filter: BookingFilter
|
club: Club, users: list[User], booking_filter: BookingFilter
|
||||||
) -> tuple[Court, User]:
|
) -> tuple[Court, User]:
|
||||||
|
@ -26,10 +21,10 @@ async def book_court(
|
||||||
:return: a tuple containing the court that was booked and the user who made the
|
:return: a tuple containing the court that was booked and the user who made the
|
||||||
booking
|
booking
|
||||||
"""
|
"""
|
||||||
connector = get_connector(club)
|
service = GestionSportsServices()
|
||||||
for user in users:
|
for user in users:
|
||||||
if not await connector.has_user_ongoing_booking(user):
|
if not await service.has_user_available_slots(user, club):
|
||||||
return await connector.book(user, booking_filter), user
|
return await service.book(club, user, booking_filter), user
|
||||||
|
|
||||||
|
|
||||||
async def cancel_booking(club: Club, user: User, booking_filter: BookingFilter) -> None:
|
async def cancel_booking(club: Club, user: User, booking_filter: BookingFilter) -> None:
|
||||||
|
@ -40,8 +35,8 @@ async def cancel_booking(club: Club, user: User, booking_filter: BookingFilter)
|
||||||
:param user: the user who made the booking
|
:param user: the user who made the booking
|
||||||
:param booking_filter: the conditions to meet to cancel the booking
|
:param booking_filter: the conditions to meet to cancel the booking
|
||||||
"""
|
"""
|
||||||
connector = get_connector(club)
|
service = GestionSportsServices()
|
||||||
await connector.cancel_booking(user, booking_filter)
|
await service.cancel_booking(user, club, booking_filter)
|
||||||
|
|
||||||
|
|
||||||
async def cancel_booking_id(club: Club, user: User, booking_id: int) -> None:
|
async def cancel_booking_id(club: Club, user: User, booking_id: int) -> None:
|
||||||
|
@ -52,8 +47,8 @@ async def cancel_booking_id(club: Club, user: User, booking_id: int) -> None:
|
||||||
:param user: the user who made the booking
|
:param user: the user who made the booking
|
||||||
:param booking_id: the id of the booking to cancel
|
:param booking_id: the id of the booking to cancel
|
||||||
"""
|
"""
|
||||||
connector = get_connector(club)
|
service = GestionSportsServices()
|
||||||
await connector.cancel_booking_id(user, booking_id)
|
await service.cancel_booking_id(user, club, booking_id)
|
||||||
|
|
||||||
|
|
||||||
def main() -> tuple[Court, User] | None:
|
def main() -> tuple[Court, User] | None:
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
import config
|
import config
|
||||||
import pendulum
|
|
||||||
from aiohttp import ClientResponse, ClientSession
|
from aiohttp import ClientResponse, ClientSession
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from models import Booking, BookingFilter, Club, Court, Sport, User
|
from models import Booking, BookingFilter, Club, Court, Sport, User
|
||||||
|
@ -19,55 +16,7 @@ LOGGER = logging.getLogger(__name__)
|
||||||
POST_HEADERS = config.get_post_headers("gestion-sports")
|
POST_HEADERS = config.get_post_headers("gestion-sports")
|
||||||
|
|
||||||
|
|
||||||
class Connector(ABC):
|
class GestionSportsConnector:
|
||||||
"""
|
|
||||||
Abstract class that defines the method a connector
|
|
||||||
to a website for sport booking should have
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def book(self, user: User, booking_filter: BookingFilter) -> Court | None:
|
|
||||||
"""
|
|
||||||
Book a court matching the filter for a user
|
|
||||||
|
|
||||||
:param user: the user who will have the booking
|
|
||||||
:param booking_filter: the conditions to book (date, time, court)
|
|
||||||
:return: the court booked
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def has_user_ongoing_booking(self, user: User) -> bool:
|
|
||||||
"""
|
|
||||||
Test whether the user has ongoing bookings
|
|
||||||
|
|
||||||
:param user: the user who will have the booking
|
|
||||||
:return: true if the user has at least one ongoing booking, false otherwise
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def cancel_booking_id(self, user: User, booking_id: int) -> None:
|
|
||||||
"""
|
|
||||||
Cancel the booking for a given user
|
|
||||||
|
|
||||||
:param user: the user who has the booking
|
|
||||||
:param booking_id: the id of the booking
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def cancel_booking(self, user: User, booking_filter: BookingFilter) -> None:
|
|
||||||
"""
|
|
||||||
Cancel the booking that meet some conditions for a given user
|
|
||||||
|
|
||||||
:param user: the user who has the booking
|
|
||||||
:param booking_filter: the booking conditions to meet to cancel the booking
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class GestionSportsConnector(Connector):
|
|
||||||
"""
|
"""
|
||||||
The connector for the Gestion Sports platform.
|
The connector for the Gestion Sports platform.
|
||||||
It handles all the requests to the website.
|
It handles all the requests to the website.
|
||||||
|
@ -266,14 +215,16 @@ class GestionSportsConnector(Connector):
|
||||||
LOGGER.debug("Connexion request response:\n%s", resp_text)
|
LOGGER.debug("Connexion request response:\n%s", resp_text)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def book(self, user: User, booking_filter: BookingFilter) -> Court | None:
|
async def book_any_court(
|
||||||
|
self, session: ClientSession, booking_filter: BookingFilter
|
||||||
|
) -> list[tuple[int, dict]]:
|
||||||
"""
|
"""
|
||||||
Perform a request for each court at the same time to increase the chances to get
|
Perform a request for each court at the same time to increase the chances to get
|
||||||
a booking.
|
a booking.
|
||||||
The gestion-sports backend does not allow several bookings at the same time
|
The gestion-sports backend does not allow several bookings at the same time
|
||||||
so there is no need to make each request one after the other
|
so there is no need to make each request one after the other
|
||||||
|
|
||||||
:param user: the user that wants to book the court
|
:param session: the session to use
|
||||||
:param booking_filter: the booking conditions to meet
|
:param booking_filter: the booking conditions to meet
|
||||||
:return: the booked court, or None if no court was booked
|
:return: the booked court, or None if no court was booked
|
||||||
"""
|
"""
|
||||||
|
@ -283,24 +234,18 @@ class GestionSportsConnector(Connector):
|
||||||
|
|
||||||
sport = self.available_sports.get(booking_filter.sport_name)
|
sport = self.available_sports.get(booking_filter.sport_name)
|
||||||
|
|
||||||
async with ClientSession() as session:
|
bookings = await asyncio.gather(
|
||||||
# use asyncio to request a booking on every court
|
*[
|
||||||
# the gestion-sports backend is able to book only one court for a user
|
self.send_booking_request(
|
||||||
await self.land(session)
|
session, booking_filter.date, court.id, sport.id
|
||||||
await self.login(session, user)
|
)
|
||||||
self.wait_until_booking_time(booking_filter)
|
for court in sport.courts
|
||||||
bookings = await asyncio.gather(
|
],
|
||||||
*[
|
return_exceptions=True,
|
||||||
self.send_booking_request(
|
)
|
||||||
session, booking_filter.date, court.id, sport.id
|
|
||||||
)
|
|
||||||
for court in sport.courts
|
|
||||||
],
|
|
||||||
return_exceptions=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
LOGGER.debug("Booking results:\n'%s'", bookings)
|
LOGGER.debug("Booking results:\n'%s'", bookings)
|
||||||
return self.get_booked_court(bookings, sport.name)
|
return bookings
|
||||||
|
|
||||||
async def send_booking_request(
|
async def send_booking_request(
|
||||||
self,
|
self,
|
||||||
|
@ -308,7 +253,7 @@ class GestionSportsConnector(Connector):
|
||||||
date: DateTime,
|
date: DateTime,
|
||||||
court_id: int,
|
court_id: int,
|
||||||
sport_id: int,
|
sport_id: int,
|
||||||
) -> tuple[ClientResponse, int, bool]:
|
) -> tuple[int, dict]:
|
||||||
"""
|
"""
|
||||||
Book a single court that meets the conditions from the booking filter
|
Book a single court that meets the conditions from the booking filter
|
||||||
|
|
||||||
|
@ -316,7 +261,7 @@ class GestionSportsConnector(Connector):
|
||||||
:param date: the booking date
|
:param date: the booking date
|
||||||
:param court_id: the id of the court to book
|
:param court_id: the id of the court to book
|
||||||
:param sport_id: the id of the sport
|
:param sport_id: the id of the sport
|
||||||
:return: a tuple containing the court id and the booking status
|
:return: a tuple containing the court id and the response
|
||||||
"""
|
"""
|
||||||
LOGGER.debug("Booking court %s at %s", court_id, date.to_w3c_string())
|
LOGGER.debug("Booking court %s at %s", court_id, date.to_w3c_string())
|
||||||
payload = PayloadBuilder.build(
|
payload = PayloadBuilder.build(
|
||||||
|
@ -332,12 +277,12 @@ class GestionSportsConnector(Connector):
|
||||||
self.booking_url, data=payload, headers=POST_HEADERS
|
self.booking_url, data=payload, headers=POST_HEADERS
|
||||||
) as response:
|
) as response:
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
resp_json = await response.text()
|
resp_json = json.loads(await response.text())
|
||||||
LOGGER.debug("Response from booking request:\n'%s'", resp_json)
|
LOGGER.debug("Response from booking request:\n'%s'", resp_json)
|
||||||
return response, court_id, self.is_booking_response_status_ok(resp_json)
|
return court_id, resp_json
|
||||||
|
|
||||||
def get_booked_court(
|
def get_booked_court(
|
||||||
self, bookings: list[tuple[ClientSession, int, bool]], sport_name: str
|
self, bookings: list[tuple[int, dict]], sport_name: str
|
||||||
) -> Court | None:
|
) -> Court | None:
|
||||||
"""
|
"""
|
||||||
Parse the booking list and return the court that was booked
|
Parse the booking list and return the court that was booked
|
||||||
|
@ -346,8 +291,8 @@ class GestionSportsConnector(Connector):
|
||||||
:param sport_name: the sport name
|
:param sport_name: the sport name
|
||||||
:return: the id of the booked court if any, None otherwise
|
:return: the id of the booked court if any, None otherwise
|
||||||
"""
|
"""
|
||||||
for _, court_id, is_booked in bookings:
|
for court_id, response in bookings:
|
||||||
if is_booked:
|
if self.is_booking_response_status_ok(response):
|
||||||
LOGGER.debug("Court %d is booked", court_id)
|
LOGGER.debug("Court %d is booked", court_id)
|
||||||
court_booked = self.find_court(court_id, sport_name)
|
court_booked = self.find_court(court_id, sport_name)
|
||||||
LOGGER.info("Court '%s' is booked", court_booked.name)
|
LOGGER.info("Court '%s' is booked", court_booked.name)
|
||||||
|
@ -369,70 +314,14 @@ class GestionSportsConnector(Connector):
|
||||||
return court
|
return court
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_booking_response_status_ok(response: str) -> bool:
|
def is_booking_response_status_ok(response: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the booking response is OK
|
Check if the booking response is OK
|
||||||
|
|
||||||
:param response: the response as a string
|
:param response: the response as a string
|
||||||
:return: true if the status is ok, false otherwise
|
:return: true if the status is ok, false otherwise
|
||||||
"""
|
"""
|
||||||
formatted_result = response.removeprefix('"').removesuffix('"')
|
return response["status"] == "ok"
|
||||||
result_json = json.loads(formatted_result)
|
|
||||||
return result_json["status"] == "ok"
|
|
||||||
|
|
||||||
def build_booking_datetime(self, booking_filter: BookingFilter) -> DateTime:
|
|
||||||
"""
|
|
||||||
Build the date and time when the booking is open for a given match date.
|
|
||||||
The booking filter contains the date and time of the booking.
|
|
||||||
The club has the information about when the booking is open for that date.
|
|
||||||
|
|
||||||
:param booking_filter: the booking information
|
|
||||||
:return: the date and time when the booking is open
|
|
||||||
"""
|
|
||||||
date_to_book = booking_filter.date
|
|
||||||
booking_opening = self.club.booking_platform.booking_opening
|
|
||||||
booking_date = date_to_book.subtract(days=booking_opening.days_before)
|
|
||||||
|
|
||||||
opening_time = pendulum.parse(booking_opening.opening_time)
|
|
||||||
booking_hour = opening_time.hour
|
|
||||||
booking_minute = opening_time.minute
|
|
||||||
|
|
||||||
return booking_date.at(booking_hour, booking_minute)
|
|
||||||
|
|
||||||
def wait_until_booking_time(self, booking_filter: BookingFilter) -> None:
|
|
||||||
"""
|
|
||||||
Wait until the booking is open.
|
|
||||||
The booking filter contains the date and time of the booking.
|
|
||||||
The club has the information about when the booking is open for that date.
|
|
||||||
|
|
||||||
:param booking_filter: the booking information
|
|
||||||
"""
|
|
||||||
LOGGER.info("Waiting for booking time")
|
|
||||||
booking_datetime = self.build_booking_datetime(booking_filter)
|
|
||||||
now = pendulum.now()
|
|
||||||
duration_until_booking = booking_datetime - now
|
|
||||||
LOGGER.debug(f"Current time: {now}, Datetime to book: {booking_datetime}")
|
|
||||||
LOGGER.debug(
|
|
||||||
f"Time to wait before booking: {duration_until_booking.hours:0>2}"
|
|
||||||
f":{duration_until_booking.minutes:0>2}"
|
|
||||||
f":{duration_until_booking.seconds:0>2}"
|
|
||||||
)
|
|
||||||
|
|
||||||
while now < booking_datetime:
|
|
||||||
time.sleep(1)
|
|
||||||
now = pendulum.now()
|
|
||||||
LOGGER.info("It's booking time!")
|
|
||||||
|
|
||||||
async def has_user_ongoing_booking(self, user: User) -> bool:
|
|
||||||
"""
|
|
||||||
Check if the user currently has bookings in the future
|
|
||||||
:param user: the user to check the bookings
|
|
||||||
:return: true if the user has some bookings, false otherwise
|
|
||||||
"""
|
|
||||||
async with ClientSession() as session:
|
|
||||||
await self.land(session)
|
|
||||||
await self.login(session, user)
|
|
||||||
return bool(await self.get_ongoing_bookings(session))
|
|
||||||
|
|
||||||
async def get_ongoing_bookings(self, session: ClientSession) -> list[Booking]:
|
async def get_ongoing_bookings(self, session: ClientSession) -> list[Booking]:
|
||||||
"""
|
"""
|
||||||
|
@ -494,21 +383,7 @@ class GestionSportsConnector(Connector):
|
||||||
LOGGER.debug("ongoing bookings response: %s\n", resp)
|
LOGGER.debug("ongoing bookings response: %s\n", resp)
|
||||||
return [Booking(**booking) for booking in json.loads(resp)]
|
return [Booking(**booking) for booking in json.loads(resp)]
|
||||||
|
|
||||||
async def cancel_booking_id(self, user: User, booking_id: int) -> ClientResponse:
|
async def cancel_booking_id(
|
||||||
"""
|
|
||||||
Cancel a booking based on its id for a given user
|
|
||||||
|
|
||||||
:param user: the user that has the booking
|
|
||||||
:param booking_id: the id of the booking to cancel
|
|
||||||
:return: the response from the client
|
|
||||||
"""
|
|
||||||
async with ClientSession() as session:
|
|
||||||
await self.land(session)
|
|
||||||
await self.login(session, user)
|
|
||||||
|
|
||||||
return await self.send_cancellation_request(session, booking_id)
|
|
||||||
|
|
||||||
async def send_cancellation_request(
|
|
||||||
self, session: ClientSession, booking_id: int
|
self, session: ClientSession, booking_id: int
|
||||||
) -> ClientResponse:
|
) -> ClientResponse:
|
||||||
"""
|
"""
|
||||||
|
@ -533,20 +408,16 @@ class GestionSportsConnector(Connector):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def cancel_booking(
|
async def cancel_booking(
|
||||||
self, user: User, booking_filter: BookingFilter
|
self, session: ClientSession, booking_filter: BookingFilter
|
||||||
) -> ClientResponse | None:
|
) -> ClientResponse | None:
|
||||||
"""
|
"""
|
||||||
Cancel the booking that meets some conditions
|
Cancel the booking that meets some conditions
|
||||||
|
|
||||||
:param user: the user who owns the booking
|
:param session: the session
|
||||||
:param booking_filter: the conditions the booking to cancel should meet
|
:param booking_filter: the conditions the booking to cancel should meet
|
||||||
"""
|
"""
|
||||||
async with ClientSession() as session:
|
bookings = await self.get_ongoing_bookings(session)
|
||||||
await self.land(session)
|
|
||||||
await self.login(session, user)
|
|
||||||
|
|
||||||
bookings = await self.get_ongoing_bookings(session)
|
for booking in bookings:
|
||||||
|
if booking.matches(booking_filter):
|
||||||
for booking in bookings:
|
return await self.cancel_booking_id(session, booking.id)
|
||||||
if booking.matches(booking_filter):
|
|
||||||
return await self.send_cancellation_request(session, booking.id)
|
|
||||||
|
|
127
resa_padel/gestion_sports_services.py
Normal file
127
resa_padel/gestion_sports_services.py
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
import pendulum
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
from connectors import GestionSportsConnector
|
||||||
|
from models import BookingFilter, BookingOpening, Club, Court, User
|
||||||
|
from pendulum import DateTime
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GestionSportsServices:
|
||||||
|
@staticmethod
|
||||||
|
async def book(
|
||||||
|
club: Club, user: User, booking_filter: BookingFilter
|
||||||
|
) -> Court | None:
|
||||||
|
"""
|
||||||
|
Perform a request for each court at the same time to increase the chances to get
|
||||||
|
a booking.
|
||||||
|
The gestion-sports backend does not allow several bookings at the same time
|
||||||
|
so there is no need to make each request one after the other
|
||||||
|
|
||||||
|
:param club: the club in which the booking will be made
|
||||||
|
:param user: the user that wants to book the court
|
||||||
|
:param booking_filter: the booking conditions to meet
|
||||||
|
:return: the booked court, or None if no court was booked
|
||||||
|
"""
|
||||||
|
connector = GestionSportsConnector(club)
|
||||||
|
LOGGER.info(
|
||||||
|
"Booking any available court from GestionSports API at %s",
|
||||||
|
connector.booking_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
async with ClientSession() as session:
|
||||||
|
# use asyncio to request a booking on every court
|
||||||
|
# the gestion-sports backend is able to book only one court for a user
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
|
||||||
|
booking_opening = club.booking_platform.booking_opening
|
||||||
|
GestionSportsServices.wait_until_booking_time(
|
||||||
|
booking_filter, booking_opening
|
||||||
|
)
|
||||||
|
|
||||||
|
bookings = await connector.book_any_court(session, booking_filter)
|
||||||
|
|
||||||
|
LOGGER.debug("Booking results:\n'%s'", bookings)
|
||||||
|
return connector.get_booked_court(bookings, booking_filter.sport_name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def has_user_available_slots(user: User, club: Club) -> bool:
|
||||||
|
connector = GestionSportsConnector(club)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
bookings = await connector.get_ongoing_bookings(session)
|
||||||
|
|
||||||
|
return bool(bookings)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def cancel_booking(user: User, club: Club, booking_filter: BookingFilter):
|
||||||
|
connector = GestionSportsConnector(club)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
await connector.cancel_booking(session, booking_filter)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def cancel_booking_id(user: User, club: Club, booking_id: int):
|
||||||
|
connector = GestionSportsConnector(club)
|
||||||
|
async with ClientSession() as session:
|
||||||
|
await connector.land(session)
|
||||||
|
await connector.login(session, user)
|
||||||
|
await connector.cancel_booking_id(session, booking_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def wait_until_booking_time(
|
||||||
|
booking_filter: BookingFilter, booking_opening: BookingOpening
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Wait until the booking is open.
|
||||||
|
The booking filter contains the date and time of the booking.
|
||||||
|
The club has the information about when the booking is open for that date.
|
||||||
|
|
||||||
|
:param booking_opening:
|
||||||
|
:param booking_filter: the booking information
|
||||||
|
"""
|
||||||
|
LOGGER.info("Waiting for booking time")
|
||||||
|
booking_datetime = GestionSportsServices.build_booking_datetime(
|
||||||
|
booking_filter, booking_opening
|
||||||
|
)
|
||||||
|
now = pendulum.now()
|
||||||
|
duration_until_booking = booking_datetime - now
|
||||||
|
LOGGER.debug(f"Current time: {now}, Datetime to book: {booking_datetime}")
|
||||||
|
LOGGER.debug(
|
||||||
|
f"Time to wait before booking: {duration_until_booking.hours:0>2}"
|
||||||
|
f":{duration_until_booking.minutes:0>2}"
|
||||||
|
f":{duration_until_booking.seconds:0>2}"
|
||||||
|
)
|
||||||
|
|
||||||
|
while now < booking_datetime:
|
||||||
|
time.sleep(1)
|
||||||
|
now = pendulum.now()
|
||||||
|
LOGGER.info("It's booking time!")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_booking_datetime(
|
||||||
|
booking_filter: BookingFilter, booking_opening: BookingOpening
|
||||||
|
) -> DateTime:
|
||||||
|
"""
|
||||||
|
Build the date and time when the booking is open for a given match date.
|
||||||
|
The booking filter contains the date and time of the booking.
|
||||||
|
The club has the information about when the booking is open for that date.
|
||||||
|
|
||||||
|
:param booking_opening:the booking opening conditions
|
||||||
|
:param booking_filter: the booking information
|
||||||
|
:return: the date and time when the booking is open
|
||||||
|
"""
|
||||||
|
date_to_book = booking_filter.date
|
||||||
|
booking_date = date_to_book.subtract(days=booking_opening.days_before)
|
||||||
|
|
||||||
|
opening_time = pendulum.parse(booking_opening.opening_time)
|
||||||
|
booking_hour = opening_time.hour
|
||||||
|
booking_minute = opening_time.minute
|
||||||
|
|
||||||
|
return booking_date.at(booking_hour, booking_minute)
|
46
tests/integration_tests/conftest.py
Normal file
46
tests/integration_tests/conftest.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import config
|
||||||
|
import pendulum
|
||||||
|
import pytest
|
||||||
|
from connectors import GestionSportsConnector
|
||||||
|
from models import BookingFilter, Club, User
|
||||||
|
|
||||||
|
TEST_FOLDER = Path(__file__).parent.parent
|
||||||
|
DATA_FOLDER = TEST_FOLDER / "data"
|
||||||
|
RESPONSES_FOLDER = DATA_FOLDER / "responses"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def club() -> Club:
|
||||||
|
return config.get_clubs()["tpc"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def connector(club) -> GestionSportsConnector:
|
||||||
|
return GestionSportsConnector(club)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def user() -> User:
|
||||||
|
return User(login="padel.testing@jouf.fr", password="ridicule")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def booking_filter() -> BookingFilter:
|
||||||
|
return BookingFilter(
|
||||||
|
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00+01:00")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def booking_success_response() -> dict:
|
||||||
|
booking_success_file = RESPONSES_FOLDER / "booking_success.json"
|
||||||
|
return json.loads(booking_success_file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def booking_failure_response() -> dict:
|
||||||
|
booking_failure_file = RESPONSES_FOLDER / "booking_failure.json"
|
||||||
|
return json.loads(booking_failure_file.read_text(encoding="utf-8"))
|
|
@ -2,10 +2,6 @@ import asyncio
|
||||||
import os
|
import os
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import config
|
|
||||||
import pendulum
|
|
||||||
from models import BookingFilter, User
|
|
||||||
|
|
||||||
from resa_padel import booking
|
from resa_padel import booking
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,12 +10,7 @@ from resa_padel import booking
|
||||||
{"CLUB_ID": "tpc"},
|
{"CLUB_ID": "tpc"},
|
||||||
clear=True,
|
clear=True,
|
||||||
)
|
)
|
||||||
def test_booking():
|
def test_booking(club, user, booking_filter):
|
||||||
club = config.get_club()
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
booking_filter = BookingFilter(
|
|
||||||
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00+01:00")
|
|
||||||
)
|
|
||||||
booked_court, user_that_booked = asyncio.run(
|
booked_court, user_that_booked = asyncio.run(
|
||||||
booking.book_court(club, [user], booking_filter)
|
booking.book_court(club, [user], booking_filter)
|
||||||
)
|
)
|
||||||
|
@ -32,10 +23,8 @@ def test_booking():
|
||||||
{"CLUB_ID": "tpc"},
|
{"CLUB_ID": "tpc"},
|
||||||
clear=True,
|
clear=True,
|
||||||
)
|
)
|
||||||
def test_cancellation():
|
def test_cancellation(club, user, booking_filter):
|
||||||
club = config.get_club()
|
asyncio.run(booking.cancel_booking(club, user, booking_filter))
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
asyncio.run(booking.cancel_booking_id(club, user, 3605033))
|
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
@patch.dict(
|
||||||
|
@ -49,9 +38,9 @@ def test_cancellation():
|
||||||
clear=True,
|
clear=True,
|
||||||
)
|
)
|
||||||
def test_main_booking():
|
def test_main_booking():
|
||||||
court, user = booking.main()
|
court, player = booking.main()
|
||||||
assert court is not None
|
assert court is not None
|
||||||
assert user.username == "padel.testing@jouf"
|
assert player.login == "padel.testing@jouf.fr"
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
@patch.dict(
|
||||||
|
|
|
@ -3,12 +3,10 @@ from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import config
|
|
||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from aiohttp import ClientSession
|
|
||||||
from connectors import GestionSportsConnector
|
from connectors import GestionSportsConnector
|
||||||
from models import Booking, BookingFilter, Club, User
|
from models import BookingFilter, Club
|
||||||
from pendulum import DateTime
|
from pendulum import DateTime
|
||||||
from yarl import URL
|
from yarl import URL
|
||||||
|
|
||||||
|
@ -38,9 +36,7 @@ def retrieve_booking_datetime(
|
||||||
{"CLUB_ID": "tpc"},
|
{"CLUB_ID": "tpc"},
|
||||||
clear=True,
|
clear=True,
|
||||||
)
|
)
|
||||||
def test_urls():
|
def test_urls(connector):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
assert (
|
assert (
|
||||||
connector.landing_url
|
connector.landing_url
|
||||||
== "https://toulousepadelclub.gestion-sports.com/connexion.php"
|
== "https://toulousepadelclub.gestion-sports.com/connexion.php"
|
||||||
|
@ -65,12 +61,10 @@ def test_urls():
|
||||||
|
|
||||||
@patch.dict(
|
@patch.dict(
|
||||||
os.environ,
|
os.environ,
|
||||||
{"CLUB_ID": "tpc", "RESOURCES_FOLDER": "/some/path"},
|
{"RESOURCES_FOLDER": "/some/path"},
|
||||||
clear=True,
|
clear=True,
|
||||||
)
|
)
|
||||||
def test_urls_payload_templates():
|
def test_urls_payload_templates(connector):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
resources_folder = Path("/some", "path", "gestion-sports")
|
resources_folder = Path("/some", "path", "gestion-sports")
|
||||||
assert connector.login_template == resources_folder / "login-payload.txt"
|
assert connector.login_template == resources_folder / "login-payload.txt"
|
||||||
assert connector.booking_template == resources_folder / "booking-payload.txt"
|
assert connector.booking_template == resources_folder / "booking-payload.txt"
|
||||||
|
@ -84,15 +78,8 @@ def test_urls_payload_templates():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_landing_page():
|
async def test_landing_page(connector):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
response = await connector.land(session)
|
response = await connector.land(session)
|
||||||
|
|
||||||
|
@ -104,17 +91,8 @@ async def test_landing_page():
|
||||||
assert response.cookies.get("PHPSESSID") is not None
|
assert response.cookies.get("PHPSESSID") is not None
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_login():
|
async def test_login(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
|
|
||||||
|
@ -130,90 +108,46 @@ async def test_login():
|
||||||
assert response.cookies.get("COOK_ID_USER").value == "232382"
|
assert response.cookies.get("COOK_ID_USER").value == "232382"
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
def test_get_booked_court(
|
||||||
os.environ,
|
connector, booking_success_response, booking_failure_response
|
||||||
{"CLUB_ID": "tpc"},
|
):
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
def test_get_booked_court():
|
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
|
|
||||||
session = ClientSession()
|
|
||||||
bookings = [
|
bookings = [
|
||||||
(session, 601, False),
|
(601, booking_failure_response),
|
||||||
(session, 602, False),
|
(602, booking_failure_response),
|
||||||
(session, 603, False),
|
(603, booking_failure_response),
|
||||||
(session, 614, False),
|
(614, booking_failure_response),
|
||||||
(session, 605, False),
|
(605, booking_failure_response),
|
||||||
(session, 606, True),
|
(606, booking_success_response),
|
||||||
(session, 607, False),
|
(607, booking_failure_response),
|
||||||
(session, 608, False),
|
(608, booking_failure_response),
|
||||||
]
|
]
|
||||||
|
|
||||||
court = connector.get_booked_court(bookings, "padel")
|
court = connector.get_booked_court(bookings, "padel")
|
||||||
assert court.number == 9
|
assert court.number == 9
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_book_one_court():
|
async def test_book_one_court(connector, user, booking_filter):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
response, court_id, ok = await connector.send_booking_request(
|
|
||||||
session, pendulum.parse("2024-03-21T13:30:00Z"), 610, 217
|
court_id, response = await connector.send_booking_request(
|
||||||
|
session, pendulum.parse("2024-03-21T13:30:00+01:00"), 610, 217
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status == 200
|
assert court_id == 610
|
||||||
assert response.request_info.method == "POST"
|
assert response.get("status") == "ok"
|
||||||
assert response.content_type == "text/html"
|
|
||||||
assert response.request_info.url == URL(connector.booking_url)
|
|
||||||
assert response.charset == "UTF-8"
|
|
||||||
assert response.text is not None
|
|
||||||
assert court_id == 610
|
|
||||||
assert ok is True
|
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_book():
|
async def test_book(connector, user, booking_filter):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
booking_filter = BookingFilter(
|
|
||||||
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00Z")
|
|
||||||
)
|
|
||||||
|
|
||||||
booked_court = await connector.book(user, booking_filter)
|
booked_court = await connector.book(user, booking_filter)
|
||||||
|
|
||||||
assert booked_court is not None
|
assert booked_court is not None
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
def test_build_booking_datetime(connector, booking_filter):
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
def test_build_booking_datetime():
|
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
booking_filter = BookingFilter(
|
|
||||||
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00Z")
|
|
||||||
)
|
|
||||||
|
|
||||||
opening_datetime = connector.build_booking_datetime(booking_filter)
|
opening_datetime = connector.build_booking_datetime(booking_filter)
|
||||||
assert opening_datetime.year == 2024
|
assert opening_datetime.year == 2024
|
||||||
assert opening_datetime.month == 3
|
assert opening_datetime.month == 3
|
||||||
|
@ -222,19 +156,8 @@ def test_build_booking_datetime():
|
||||||
assert opening_datetime.minute == 0
|
assert opening_datetime.minute == 0
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@patch("pendulum.now")
|
@patch("pendulum.now")
|
||||||
def test_wait_until_booking_time(mock_now):
|
def test_wait_until_booking_time(mock_now, connector, booking_filter, club):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
booking_filter = BookingFilter(
|
|
||||||
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00Z")
|
|
||||||
)
|
|
||||||
|
|
||||||
booking_datetime = retrieve_booking_datetime(booking_filter, club)
|
booking_datetime = retrieve_booking_datetime(booking_filter, club)
|
||||||
|
|
||||||
seconds = [
|
seconds = [
|
||||||
|
@ -252,17 +175,8 @@ def test_wait_until_booking_time(mock_now):
|
||||||
assert pendulum.now() == booking_datetime.add(microseconds=1)
|
assert pendulum.now() == booking_datetime.add(microseconds=1)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_hash():
|
async def test_get_hash(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
@ -281,17 +195,8 @@ def test_get_hash_input():
|
||||||
assert hash_value == "63470fa38e300fd503de1ee21a71b3bdb6fb206b"
|
assert hash_value == "63470fa38e300fd503de1ee21a71b3bdb6fb206b"
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_bookings():
|
async def test_get_bookings(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
@ -303,17 +208,8 @@ async def test_get_bookings():
|
||||||
print(bookings)
|
print(bookings)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_ongoing_bookings():
|
async def test_get_ongoing_bookings(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
@ -322,31 +218,13 @@ async def test_get_ongoing_bookings():
|
||||||
print(bookings)
|
print(bookings)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_has_user_ongoing_bookings():
|
async def test_has_user_ongoing_bookings(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
assert await connector.has_user_ongoing_booking(user)
|
assert await connector.has_user_ongoing_booking(user)
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking_id():
|
async def test_cancel_booking_id(connector, user):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
await connector.land(session)
|
await connector.land(session)
|
||||||
await connector.login(session, user)
|
await connector.login(session, user)
|
||||||
|
@ -358,73 +236,16 @@ async def test_cancel_booking_id():
|
||||||
assert len(await connector.get_ongoing_bookings(session)) == 0
|
assert len(await connector.get_ongoing_bookings(session)) == 0
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
def test_is_booking_matching_filter():
|
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
filter_date = pendulum.parse("2024-03-02T15:00:00+01:00")
|
|
||||||
booking = Booking(
|
|
||||||
id=1,
|
|
||||||
dateResa="02/03/2024",
|
|
||||||
startTime="15:00",
|
|
||||||
sport="Padel",
|
|
||||||
court="10",
|
|
||||||
)
|
|
||||||
booking_filter = BookingFilter(date=filter_date, sport_name="Padel")
|
|
||||||
|
|
||||||
assert connector.is_booking_matching_filter(booking, booking_filter)
|
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
def test_is_booking_not_matching_filter():
|
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
filter_date = pendulum.parse("2024-03-02T15:00:00+01:00")
|
|
||||||
booking = Booking(
|
|
||||||
id=1,
|
|
||||||
dateResa="02/03/2024",
|
|
||||||
startTime="16:00",
|
|
||||||
sport="Padel",
|
|
||||||
court="10",
|
|
||||||
)
|
|
||||||
booking_filter = BookingFilter(date=filter_date, sport_name="Padel")
|
|
||||||
|
|
||||||
assert not connector.is_booking_matching_filter(booking, booking_filter)
|
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
def test_find_court():
|
def test_find_court(connector):
|
||||||
club = config.get_club()
|
|
||||||
connector = GestionSportsConnector(club)
|
|
||||||
|
|
||||||
court = connector.find_court(603, "Padel")
|
court = connector.find_court(603, "Padel")
|
||||||
|
|
||||||
assert court.number == 6
|
assert court.number == 6
|
||||||
|
|
||||||
|
|
||||||
@patch.dict(
|
|
||||||
os.environ,
|
|
||||||
{"CLUB_ID": "tpc"},
|
|
||||||
clear=True,
|
|
||||||
)
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking():
|
async def test_cancel_booking(connector, user, booking_filter):
|
||||||
club = config.get_club()
|
async with aiohttp.ClientSession() as session:
|
||||||
connector = GestionSportsConnector(club)
|
await connector.land(session)
|
||||||
user = User(login="padel.testing@jouf.fr", password="ridicule")
|
await connector.login(session, user)
|
||||||
filter_date = pendulum.parse("2024-03-21T13:30:00+01:00")
|
await connector.cancel_booking(session, booking_filter)
|
||||||
booking_filter = BookingFilter(date=filter_date, sport_name="Padel")
|
|
||||||
await connector.cancel_booking(user, booking_filter)
|
|
||||||
|
|
20
tests/integration_tests/test_gestion_sports_services.py
Normal file
20
tests/integration_tests/test_gestion_sports_services.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import pytest
|
||||||
|
from gestion_sports_services import GestionSportsServices
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_booking_success(club, user, booking_filter):
|
||||||
|
court_booked = await GestionSportsServices.book(club, user, booking_filter)
|
||||||
|
|
||||||
|
assert court_booked.id is not None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_user_has_available_slots(club, user):
|
||||||
|
has_slots = await GestionSportsServices.has_user_available_slots(user, club)
|
||||||
|
assert has_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_cancel_booking(club, user, booking_filter):
|
||||||
|
await GestionSportsServices.cancel_booking(user, club, booking_filter)
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from connectors import GestionSportsConnector
|
from connectors import GestionSportsConnector
|
||||||
|
from gestion_sports_services import GestionSportsServices
|
||||||
from models import (
|
from models import (
|
||||||
BookingFilter,
|
BookingFilter,
|
||||||
BookingOpening,
|
BookingOpening,
|
||||||
|
@ -184,6 +185,11 @@ def connector(club) -> GestionSportsConnector:
|
||||||
return GestionSportsConnector(club)
|
return GestionSportsConnector(club)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gs_services() -> GestionSportsServices:
|
||||||
|
return GestionSportsServices()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user() -> User:
|
def user() -> User:
|
||||||
return User(login="padel.testing@jouf.fr", password="ridicule")
|
return User(login="padel.testing@jouf.fr", password="ridicule")
|
||||||
|
@ -226,6 +232,22 @@ def booking_failure_response() -> dict:
|
||||||
return json.loads(booking_failure_file.read_text(encoding="utf-8"))
|
return json.loads(booking_failure_file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def booked_courts_response(
|
||||||
|
court11,
|
||||||
|
court12,
|
||||||
|
court13,
|
||||||
|
court14,
|
||||||
|
booking_success_response,
|
||||||
|
booking_failure_response,
|
||||||
|
) -> list[tuple[int, dict]]:
|
||||||
|
court1_resp = court11.id, booking_failure_response
|
||||||
|
court2_resp = court12.id, booking_failure_response
|
||||||
|
court3_resp = court13.id, booking_success_response
|
||||||
|
court4_resp = court14.id, booking_failure_response
|
||||||
|
return [court1_resp, court2_resp, court3_resp, court4_resp]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def booking_success_from_start(
|
def booking_success_from_start(
|
||||||
landing_response,
|
landing_response,
|
||||||
|
@ -350,3 +372,8 @@ def cancellation_success_booking_filter() -> BookingFilter:
|
||||||
return BookingFilter(
|
return BookingFilter(
|
||||||
sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00Z")
|
sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00Z")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def service() -> GestionSportsServices:
|
||||||
|
return GestionSportsServices()
|
||||||
|
|
83
tests/unit_tests/responses.py
Normal file
83
tests/unit_tests/responses.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
def make_landing_request_success(aioresponses, connector, landing_response):
|
||||||
|
aioresponses.get(
|
||||||
|
connector.landing_url,
|
||||||
|
status=200,
|
||||||
|
headers={"Set-Cookie": "PHPSESSID=987512"},
|
||||||
|
body=landing_response,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_login_request_fail(aioresponses, connector, login_failure_response):
|
||||||
|
aioresponses.post(
|
||||||
|
connector.login_url,
|
||||||
|
status=200,
|
||||||
|
payload=login_failure_response,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_login_request_success(aioresponses, connector, login_success_response):
|
||||||
|
aioresponses.post(
|
||||||
|
connector.login_url,
|
||||||
|
status=200,
|
||||||
|
headers={"Set-Cookie": "COOK_COMPTE=e2be1;" "COOK_ID_CLUB=22;COOK_ID_USER=666"},
|
||||||
|
payload=login_success_response,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_booking_request(aioresponses, connector, booking_response):
|
||||||
|
aioresponses.post(connector.booking_url, status=200, payload=booking_response)
|
||||||
|
|
||||||
|
|
||||||
|
def set_full_booking_requests_responses(aioresponses, connector, responses_list):
|
||||||
|
make_landing_request_success(aioresponses, connector, responses_list[0])
|
||||||
|
make_login_request_success(aioresponses, connector, responses_list[1])
|
||||||
|
for response in responses_list[2:]:
|
||||||
|
set_booking_request(aioresponses, connector, response)
|
||||||
|
|
||||||
|
|
||||||
|
def set_ongoing_bookings_response(
|
||||||
|
aioresponses, connector, user_bookings_get_response, user_bookings_post_response
|
||||||
|
):
|
||||||
|
set_hash_response(aioresponses, connector, user_bookings_get_response)
|
||||||
|
set_bookings_response(aioresponses, connector, user_bookings_post_response)
|
||||||
|
|
||||||
|
|
||||||
|
def set_hash_response(aioresponses, connector, user_bookings_get_response):
|
||||||
|
aioresponses.get(
|
||||||
|
connector.user_bookings_url, status=200, body=user_bookings_get_response
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_bookings_response(aioresponses, connector, user_bookings_post_response):
|
||||||
|
aioresponses.post(
|
||||||
|
connector.user_bookings_url, status=200, payload=user_bookings_post_response
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_full_user_bookings_responses(aioresponses, connector, responses):
|
||||||
|
make_landing_request_success(aioresponses, connector, responses[0])
|
||||||
|
make_login_request_success(aioresponses, connector, responses[1])
|
||||||
|
set_ongoing_bookings_response(aioresponses, connector, *responses[2:])
|
||||||
|
|
||||||
|
|
||||||
|
def set_cancellation_response(aioresponses, connector, response):
|
||||||
|
aioresponses.post(connector.booking_cancellation_url, status=200, payload=response)
|
||||||
|
|
||||||
|
|
||||||
|
def set_full_cancellation_by_id_responses(aioresponses, connector, responses):
|
||||||
|
make_landing_request_success(aioresponses, connector, responses[0])
|
||||||
|
make_login_request_success(aioresponses, connector, responses[1])
|
||||||
|
set_hash_response(aioresponses, connector, responses[2])
|
||||||
|
set_cancellation_response(aioresponses, connector, responses[3])
|
||||||
|
|
||||||
|
|
||||||
|
def set_full_cancellation_responses(aioresponses, connector, responses):
|
||||||
|
make_landing_request_success(aioresponses, connector, responses[0])
|
||||||
|
make_login_request_success(aioresponses, connector, responses[1])
|
||||||
|
|
||||||
|
# the request to get the hash is made twice
|
||||||
|
set_hash_response(aioresponses, connector, responses[2])
|
||||||
|
set_hash_response(aioresponses, connector, responses[2])
|
||||||
|
|
||||||
|
set_bookings_response(aioresponses, connector, responses[3])
|
||||||
|
set_cancellation_response(aioresponses, connector, responses[4])
|
|
@ -15,7 +15,7 @@ from pendulum import DateTime, Timezone
|
||||||
)
|
)
|
||||||
def test_get_booking_filter():
|
def test_get_booking_filter():
|
||||||
booking_filter = config.get_booking_filter()
|
booking_filter = config.get_booking_filter()
|
||||||
assert booking_filter.sport_id == "padel"
|
assert booking_filter.sport_name == "padel"
|
||||||
assert booking_filter.date == DateTime(
|
assert booking_filter.date == DateTime(
|
||||||
year=2024,
|
year=2024,
|
||||||
month=2,
|
month=2,
|
||||||
|
|
|
@ -5,90 +5,7 @@ import pytest
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
from connectors import GestionSportsConnector
|
from connectors import GestionSportsConnector
|
||||||
|
|
||||||
|
from tests.unit_tests import responses
|
||||||
def make_landing_request_success(aioresponses, connector, landing_response):
|
|
||||||
aioresponses.get(
|
|
||||||
connector.landing_url,
|
|
||||||
status=200,
|
|
||||||
headers={"Set-Cookie": "PHPSESSID=987512"},
|
|
||||||
body=landing_response,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def make_login_request_fail(aioresponses, connector, login_failure_response):
|
|
||||||
aioresponses.post(
|
|
||||||
connector.login_url,
|
|
||||||
status=200,
|
|
||||||
payload=login_failure_response,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def make_login_request_success(aioresponses, connector, login_success_response):
|
|
||||||
aioresponses.post(
|
|
||||||
connector.login_url,
|
|
||||||
status=200,
|
|
||||||
headers={"Set-Cookie": "COOK_COMPTE=e2be1;" "COOK_ID_CLUB=22;COOK_ID_USER=666"},
|
|
||||||
payload=login_success_response,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def set_booking_request(aioresponses, connector, booking_response):
|
|
||||||
aioresponses.post(connector.booking_url, status=200, payload=booking_response)
|
|
||||||
|
|
||||||
|
|
||||||
def set_full_booking_requests_responses(aioresponses, connector, responses_list):
|
|
||||||
make_landing_request_success(aioresponses, connector, responses_list[0])
|
|
||||||
make_login_request_success(aioresponses, connector, responses_list[1])
|
|
||||||
for response in responses_list[2:]:
|
|
||||||
set_booking_request(aioresponses, connector, response)
|
|
||||||
|
|
||||||
|
|
||||||
def set_ongoing_bookings_response(
|
|
||||||
aioresponses, connector, user_bookings_get_response, user_bookings_post_response
|
|
||||||
):
|
|
||||||
set_hash_response(aioresponses, connector, user_bookings_get_response)
|
|
||||||
set_bookings_response(aioresponses, connector, user_bookings_post_response)
|
|
||||||
|
|
||||||
|
|
||||||
def set_hash_response(aioresponses, connector, user_bookings_get_response):
|
|
||||||
aioresponses.get(
|
|
||||||
connector.user_bookings_url, status=200, body=user_bookings_get_response
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def set_bookings_response(aioresponses, connector, user_bookings_post_response):
|
|
||||||
aioresponses.post(
|
|
||||||
connector.user_bookings_url, status=200, payload=user_bookings_post_response
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def set_full_user_bookings_responses(aioresponses, connector, responses):
|
|
||||||
make_landing_request_success(aioresponses, connector, responses[0])
|
|
||||||
make_login_request_success(aioresponses, connector, responses[1])
|
|
||||||
set_ongoing_bookings_response(aioresponses, connector, *responses[2:])
|
|
||||||
|
|
||||||
|
|
||||||
def set_cancellation_response(aioresponses, connector, response):
|
|
||||||
aioresponses.post(connector.booking_cancellation_url, status=200, payload=response)
|
|
||||||
|
|
||||||
|
|
||||||
def set_full_cancellation_by_id_responses(aioresponses, connector, responses):
|
|
||||||
make_landing_request_success(aioresponses, connector, responses[0])
|
|
||||||
make_login_request_success(aioresponses, connector, responses[1])
|
|
||||||
set_hash_response(aioresponses, connector, responses[2])
|
|
||||||
set_cancellation_response(aioresponses, connector, responses[3])
|
|
||||||
|
|
||||||
|
|
||||||
def set_full_cancellation_responses(aioresponses, connector, responses):
|
|
||||||
make_landing_request_success(aioresponses, connector, responses[0])
|
|
||||||
make_login_request_success(aioresponses, connector, responses[1])
|
|
||||||
|
|
||||||
# the request to get the hash is made twice
|
|
||||||
set_hash_response(aioresponses, connector, responses[2])
|
|
||||||
set_hash_response(aioresponses, connector, responses[2])
|
|
||||||
|
|
||||||
set_bookings_response(aioresponses, connector, responses[3])
|
|
||||||
set_cancellation_response(aioresponses, connector, responses[4])
|
|
||||||
|
|
||||||
|
|
||||||
def test_urls(connector, club):
|
def test_urls(connector, club):
|
||||||
|
@ -134,7 +51,7 @@ def test_urls_payload_templates(mock_resources, club):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_landing_page(aioresponses, connector, landing_response):
|
async def test_landing_page(aioresponses, connector, landing_response):
|
||||||
make_landing_request_success(aioresponses, connector, landing_response)
|
responses.make_landing_request_success(aioresponses, connector, landing_response)
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
response = await connector.land(session)
|
response = await connector.land(session)
|
||||||
|
@ -146,7 +63,9 @@ async def test_landing_page(aioresponses, connector, landing_response):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_login_success(aioresponses, connector, user, login_success_response):
|
async def test_login_success(aioresponses, connector, user, login_success_response):
|
||||||
make_login_request_success(aioresponses, connector, login_success_response)
|
responses.make_login_request_success(
|
||||||
|
aioresponses, connector, login_success_response
|
||||||
|
)
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
response = await connector.login(session, user)
|
response = await connector.login(session, user)
|
||||||
|
@ -160,7 +79,7 @@ async def test_login_success(aioresponses, connector, user, login_success_respon
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_login_failure(aioresponses, connector, user, login_failure_response):
|
async def test_login_failure(aioresponses, connector, user, login_failure_response):
|
||||||
make_login_request_fail(aioresponses, connector, login_failure_response)
|
responses.make_login_request_fail(aioresponses, connector, login_failure_response)
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
response = await connector.login(session, user)
|
response = await connector.login(session, user)
|
||||||
|
@ -170,38 +89,9 @@ async def test_login_failure(aioresponses, connector, user, login_failure_respon
|
||||||
assert await response.json() == login_failure_response
|
assert await response.json() == login_failure_response
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
def test_get_booked_court(connector, booked_courts_response):
|
||||||
async def test_booking_success(
|
booked_court = connector.get_booked_court(booked_courts_response, "Sport1")
|
||||||
aioresponses,
|
assert booked_court.number == 3
|
||||||
connector,
|
|
||||||
user,
|
|
||||||
booking_filter,
|
|
||||||
booking_success_from_start,
|
|
||||||
):
|
|
||||||
set_full_booking_requests_responses(
|
|
||||||
aioresponses, connector, booking_success_from_start
|
|
||||||
)
|
|
||||||
|
|
||||||
court_booked = await connector.book(user, booking_filter)
|
|
||||||
|
|
||||||
assert court_booked.id == 2
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_booking_failure(
|
|
||||||
aioresponses,
|
|
||||||
connector,
|
|
||||||
user,
|
|
||||||
booking_filter,
|
|
||||||
booking_failure_from_start,
|
|
||||||
):
|
|
||||||
set_full_booking_requests_responses(
|
|
||||||
aioresponses, connector, booking_failure_from_start
|
|
||||||
)
|
|
||||||
|
|
||||||
court_booked = await connector.book(user, booking_filter)
|
|
||||||
|
|
||||||
assert court_booked is None
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
@ -212,7 +102,7 @@ async def test_get_ongoing_bookings(
|
||||||
user_bookings_get_response,
|
user_bookings_get_response,
|
||||||
user_bookings_list,
|
user_bookings_list,
|
||||||
):
|
):
|
||||||
set_ongoing_bookings_response(
|
responses.set_ongoing_bookings_response(
|
||||||
aioresponses, connector, user_bookings_get_response, user_bookings_list
|
aioresponses, connector, user_bookings_get_response, user_bookings_list
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -222,81 +112,19 @@ async def test_get_ongoing_bookings(
|
||||||
assert len(bookings) == 2
|
assert len(bookings) == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_get_ongoing_bookings(
|
|
||||||
aioresponses,
|
|
||||||
connector,
|
|
||||||
user,
|
|
||||||
user_bookings_get_response,
|
|
||||||
user_bookings_list,
|
|
||||||
):
|
|
||||||
set_ongoing_bookings_response(
|
|
||||||
aioresponses, connector, user_bookings_get_response, user_bookings_list
|
|
||||||
)
|
|
||||||
|
|
||||||
async with ClientSession() as session:
|
|
||||||
bookings = await connector.get_ongoing_bookings(session)
|
|
||||||
|
|
||||||
assert len(bookings) == 2
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_has_user_ongoing_bookings(
|
|
||||||
aioresponses,
|
|
||||||
connector,
|
|
||||||
user,
|
|
||||||
user_has_ongoing_bookings_from_start,
|
|
||||||
):
|
|
||||||
set_full_user_bookings_responses(
|
|
||||||
aioresponses, connector, user_has_ongoing_bookings_from_start
|
|
||||||
)
|
|
||||||
|
|
||||||
has_bookings = await connector.has_user_ongoing_booking(user)
|
|
||||||
|
|
||||||
assert has_bookings
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_has_user_ongoing_bookings(
|
|
||||||
aioresponses,
|
|
||||||
connector,
|
|
||||||
user,
|
|
||||||
user_has_no_ongoing_bookings_from_start,
|
|
||||||
):
|
|
||||||
set_full_user_bookings_responses(
|
|
||||||
aioresponses, connector, user_has_no_ongoing_bookings_from_start
|
|
||||||
)
|
|
||||||
has_bookings = await connector.has_user_ongoing_booking(user)
|
|
||||||
|
|
||||||
assert not has_bookings
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancellation_request(
|
async def test_cancellation_request(
|
||||||
aioresponses, connector, user_bookings_get_response, cancellation_response
|
aioresponses, connector, user_bookings_get_response, cancellation_response
|
||||||
):
|
):
|
||||||
set_hash_response(aioresponses, connector, user_bookings_get_response)
|
responses.set_hash_response(aioresponses, connector, user_bookings_get_response)
|
||||||
set_cancellation_response(aioresponses, connector, cancellation_response)
|
responses.set_cancellation_response(aioresponses, connector, cancellation_response)
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
response = await connector.send_cancellation_request(session, 123)
|
response = await connector.cancel_booking_id(session, 123)
|
||||||
|
|
||||||
assert await response.json() == cancellation_response
|
assert await response.json() == cancellation_response
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_cancel_booking_id(
|
|
||||||
aioresponses, connector, user, cancellation_by_id_from_start
|
|
||||||
):
|
|
||||||
set_full_cancellation_by_id_responses(
|
|
||||||
aioresponses, connector, cancellation_by_id_from_start
|
|
||||||
)
|
|
||||||
|
|
||||||
response = await connector.cancel_booking_id(user, 132)
|
|
||||||
|
|
||||||
assert await response.json() == cancellation_by_id_from_start[3]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cancel_booking_success(
|
async def test_cancel_booking_success(
|
||||||
aioresponses,
|
aioresponses,
|
||||||
|
@ -305,10 +133,13 @@ async def test_cancel_booking_success(
|
||||||
cancellation_success_booking_filter,
|
cancellation_success_booking_filter,
|
||||||
cancellation_success_from_start,
|
cancellation_success_from_start,
|
||||||
):
|
):
|
||||||
set_full_cancellation_responses(
|
responses.set_full_cancellation_responses(
|
||||||
aioresponses, connector, cancellation_success_from_start
|
aioresponses, connector, cancellation_success_from_start
|
||||||
)
|
)
|
||||||
|
|
||||||
response = await connector.cancel_booking(user, cancellation_success_booking_filter)
|
async with ClientSession() as session:
|
||||||
|
response = await connector.cancel_booking(
|
||||||
|
session, cancellation_success_booking_filter
|
||||||
|
)
|
||||||
|
|
||||||
assert await response.json() == cancellation_success_from_start[4]
|
assert await response.json() == cancellation_success_from_start[4]
|
||||||
|
|
110
tests/unit_tests/test_gestion_sports_services.py
Normal file
110
tests/unit_tests/test_gestion_sports_services.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import pytest
|
||||||
|
from gestion_sports_services import GestionSportsServices
|
||||||
|
|
||||||
|
from tests.unit_tests import responses
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_booking_success(
|
||||||
|
aioresponses,
|
||||||
|
connector,
|
||||||
|
club,
|
||||||
|
user,
|
||||||
|
booking_filter,
|
||||||
|
booking_success_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_booking_requests_responses(
|
||||||
|
aioresponses, connector, booking_success_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
court_booked = await GestionSportsServices.book(club, user, booking_filter)
|
||||||
|
|
||||||
|
assert court_booked.id == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_booking_failure(
|
||||||
|
aioresponses,
|
||||||
|
gs_services,
|
||||||
|
connector,
|
||||||
|
club,
|
||||||
|
user,
|
||||||
|
booking_filter,
|
||||||
|
booking_failure_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_booking_requests_responses(
|
||||||
|
aioresponses, connector, booking_failure_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
court_booked = await gs_services.book(club, user, booking_filter)
|
||||||
|
|
||||||
|
assert court_booked is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_user_has_available_booking_slots(
|
||||||
|
aioresponses,
|
||||||
|
gs_services,
|
||||||
|
connector,
|
||||||
|
user,
|
||||||
|
club,
|
||||||
|
user_has_ongoing_bookings_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_user_bookings_responses(
|
||||||
|
aioresponses, connector, user_has_ongoing_bookings_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
has_user_available_slots = await gs_services.has_user_available_slots(user, club)
|
||||||
|
|
||||||
|
assert has_user_available_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_user_has_no_available_booking_slots(
|
||||||
|
aioresponses,
|
||||||
|
gs_services,
|
||||||
|
connector,
|
||||||
|
user,
|
||||||
|
club,
|
||||||
|
user_has_no_ongoing_bookings_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_user_bookings_responses(
|
||||||
|
aioresponses, connector, user_has_no_ongoing_bookings_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
has_user_available_slots = await gs_services.has_user_available_slots(user, club)
|
||||||
|
|
||||||
|
assert not has_user_available_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_cancel_booking(
|
||||||
|
aioresponses,
|
||||||
|
gs_services,
|
||||||
|
connector,
|
||||||
|
user,
|
||||||
|
club,
|
||||||
|
booking_filter,
|
||||||
|
cancellation_success_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_cancellation_responses(
|
||||||
|
aioresponses, connector, cancellation_success_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
await gs_services.cancel_booking(user, club, booking_filter)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_cancel_booking_id(
|
||||||
|
aioresponses,
|
||||||
|
gs_services,
|
||||||
|
connector,
|
||||||
|
user,
|
||||||
|
club,
|
||||||
|
cancellation_success_from_start,
|
||||||
|
):
|
||||||
|
responses.set_full_cancellation_responses(
|
||||||
|
aioresponses, connector, cancellation_success_from_start
|
||||||
|
)
|
||||||
|
|
||||||
|
await gs_services.cancel_booking_id(user, club, 65464)
|
Loading…
Add table
Add a link
Reference in a new issue