Big refactoring.

- clubs, booking platforms and user are now defined in customization files -> there are less environment variables
- the responsibility of the session moved
- booking cancellation is available
This commit is contained in:
Stanislas Jouffroy 2024-03-17 23:57:50 +01:00 committed by stanislas
parent dbda5a158e
commit 0938fb98b7
27 changed files with 3050 additions and 696 deletions

411
tests/test_connectors.py Normal file
View file

@ -0,0 +1,411 @@
import os
from pathlib import Path
from unittest.mock import patch
import aiohttp
import config
import pendulum
import pytest
from aiohttp import ClientSession
from connectors import GestionSportsConnector
from models import Booking, BookingFilter, User
from yarl import URL
from tests import utils
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
def test_urls():
club = config.get_club()
connector = GestionSportsConnector(club)
assert (
connector.landing_url
== "https://toulousepadelclub.gestion-sports.com/connexion.php"
)
assert (
connector.login_url
== "https://toulousepadelclub.gestion-sports.com/connexion.php"
)
assert (
connector.booking_url
== "https://toulousepadelclub.gestion-sports.com/membre/reservation.html"
)
assert (
connector.user_bookings_url
== "https://toulousepadelclub.gestion-sports.com/membre/mesresas.html"
)
assert (
connector.booking_cancellation_url
== "https://toulousepadelclub.gestion-sports.com/membre/mesresas.html"
)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc", "RESOURCES_FOLDER": "/some/path"},
clear=True,
)
def test_urls_payload_templates():
club = config.get_club()
connector = GestionSportsConnector(club)
resources_folder = Path("/some", "path", "gestion-sports")
assert connector.login_template == resources_folder / "login-payload.txt"
assert connector.booking_template == resources_folder / "booking-payload.txt"
assert (
connector.user_bookings_template
== resources_folder / "user-bookings-payload.txt"
)
assert (
connector.booking_cancellation_template
== resources_folder / "booking-cancellation-payload.txt"
)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_landing_page():
club = config.get_club()
connector = GestionSportsConnector(club)
async with aiohttp.ClientSession() as session:
response = await connector.land(session)
assert response.status == 200
assert response.request_info.method == "GET"
assert response.content_type == "text/html"
assert response.request_info.url == URL(connector.landing_url)
assert response.charset == "UTF-8"
assert response.cookies.get("PHPSESSID") is not None
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_login():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
response = await connector.login(session, user)
assert response.status == 200
assert response.request_info.method == "POST"
assert response.content_type == "text/html"
assert response.request_info.url == URL(connector.landing_url)
assert response.charset == "UTF-8"
assert response.cookies.get("COOK_COMPTE") is not None
assert response.cookies.get("COOK_ID_CLUB").value == "88"
assert response.cookies.get("COOK_ID_USER").value == "232382"
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
def test_get_booked_court():
club = config.get_club()
connector = GestionSportsConnector(club)
session = ClientSession()
bookings = [
(session, 601, False),
(session, 602, False),
(session, 603, False),
(session, 614, False),
(session, 605, False),
(session, 606, True),
(session, 607, False),
(session, 608, False),
]
court = connector.get_booked_court(bookings, "padel")
assert court.number == 9
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_book_one_court():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
await connector.login(session, user)
response, court_id, ok = await connector.send_booking_request(
session, pendulum.parse("2024-03-21T13:30:00Z"), 610, 217
)
assert response.status == 200
assert response.request_info.method == "POST"
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
async def test_book():
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)
assert booked_court is not None
@patch.dict(
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)
assert opening_datetime.year == 2024
assert opening_datetime.month == 3
assert opening_datetime.day == 14
assert opening_datetime.hour == 0
assert opening_datetime.minute == 0
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@patch("pendulum.now")
def test_wait_until_booking_time(mock_now):
club = config.get_club()
connector = GestionSportsConnector(club)
booking_filter = BookingFilter(
sport_name="Padel", date=pendulum.parse("2024-03-21T13:30:00Z")
)
booking_datetime = utils.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)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_get_hash():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
await connector.login(session, user)
hash_value = await connector.send_hash_request(session)
assert hash_value is not None
def test_get_hash_input():
resources_folder = Path(__file__).parent / "data"
html_file = resources_folder / "user_bookings_html_response.html"
html = html_file.read_text(encoding="utf-8")
hash_value = GestionSportsConnector.get_hash_input(html)
assert hash_value == "63470fa38e300fd503de1ee21a71b3bdb6fb206b"
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_get_bookings():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
await connector.login(session, user)
hash_value = await connector.send_hash_request(session)
payload = f"ajax=loadResa&hash={hash_value}"
bookings = await connector.send_user_bookings_request(session, payload)
print(bookings)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_get_ongoing_bookings():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
await connector.login(session, user)
bookings = await connector.get_ongoing_bookings(session)
print(bookings)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_has_user_ongoing_bookings():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
assert await connector.has_user_ongoing_booking(user)
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_cancel_booking_id():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
async with aiohttp.ClientSession() as session:
await connector.land(session)
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)
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
def test_find_court():
club = config.get_club()
connector = GestionSportsConnector(club)
court = connector.find_court(603, "Padel")
assert court.number == 6
@patch.dict(
os.environ,
{"CLUB_ID": "tpc"},
clear=True,
)
@pytest.mark.asyncio
async def test_cancel_booking():
club = config.get_club()
connector = GestionSportsConnector(club)
user = User(login="padel.testing@jouf.fr", password="ridicule")
filter_date = pendulum.parse("2024-03-21T13:30:00+01:00")
booking_filter = BookingFilter(date=filter_date, sport_name="Padel")
await connector.cancel_booking(user, booking_filter)