262 lines
9.9 KiB
Python
262 lines
9.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Unit tests for CrossFitBooker session-related methods
|
|
"""
|
|
|
|
import pytest
|
|
import os
|
|
import sys
|
|
from unittest.mock import patch, Mock
|
|
from datetime import datetime, timedelta, date
|
|
import pytz
|
|
|
|
# Add the parent directory to the path
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from src.auth import AuthHandler
|
|
from src.booker import Booker
|
|
from src.session_notifier import SessionNotifier
|
|
from src.session_manager import SessionManager
|
|
|
|
|
|
|
|
class TestCrossFitBookerGetAvailableSessions:
|
|
"""Test cases for get_available_sessions method"""
|
|
|
|
def test_get_available_sessions_no_auth(self):
|
|
"""Test get_available_sessions without authentication"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25))
|
|
assert result is None
|
|
|
|
@patch('requests.Session.post')
|
|
def test_get_available_sessions_success(self, mock_post):
|
|
"""Test successful get_available_sessions"""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
"success": True,
|
|
"data": {
|
|
"activities_calendar": [
|
|
{"id": "1", "name": "Test Session"}
|
|
]
|
|
}
|
|
}
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
auth_handler.auth_token = "test_token"
|
|
auth_handler.user_id = "12345"
|
|
session_manager = SessionManager(auth_handler)
|
|
|
|
result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25))
|
|
|
|
assert result is not None
|
|
assert result["success"] is True
|
|
|
|
@patch('requests.Session.post')
|
|
def test_get_available_sessions_401_error(self, mock_post):
|
|
"""Test get_available_sessions with 401 error"""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 401
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
auth_handler.auth_token = "test_token"
|
|
auth_handler.user_id = "12345"
|
|
|
|
result = session_manager.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25))
|
|
|
|
assert result is None
|
|
|
|
class TestCrossFitBookerBookSession:
|
|
"""Test cases for book_session method"""
|
|
|
|
def test_book_session_no_auth(self):
|
|
"""Test book_session without authentication"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
result = session_manager.book_session("session_123")
|
|
assert result is False
|
|
|
|
@patch('requests.Session.post')
|
|
def test_book_session_success(self, mock_post):
|
|
"""Test successful book_session"""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {"success": True}
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
auth_handler.auth_token = "test_token"
|
|
auth_handler.user_id = "12345"
|
|
session_manager = SessionManager(auth_handler)
|
|
|
|
result = session_manager.book_session("session_123")
|
|
|
|
assert result is True
|
|
|
|
@patch('requests.Session.post')
|
|
def test_book_session_api_failure(self, mock_post):
|
|
"""Test book_session with API failure"""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {"success": False, "error": "Session full"}
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
auth_handler.auth_token = "test_token"
|
|
auth_handler.user_id = "12345"
|
|
session_manager = SessionManager(auth_handler)
|
|
|
|
result = session_manager.book_session("session_123")
|
|
|
|
assert result is False
|
|
|
|
class TestCrossFitBookerIsSessionBookable:
|
|
"""Test cases for is_session_bookable method"""
|
|
|
|
def test_is_session_bookable_can_join_true(self):
|
|
"""Test session bookable with can_join=True"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {"user_info": {"can_join": True}}
|
|
current_time = datetime.now(pytz.timezone("Europe/Paris"))
|
|
|
|
result = session_manager.is_session_bookable(session, current_time)
|
|
assert result is True
|
|
|
|
def test_is_session_bookable_booking_window_past(self):
|
|
"""Test session bookable with booking window in past"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {
|
|
"user_info": {
|
|
"can_join": False,
|
|
"unableToBookUntilDate": "01-01-2020",
|
|
"unableToBookUntilTime": "10:00"
|
|
}
|
|
}
|
|
current_time = datetime.now(pytz.timezone("Europe/Paris"))
|
|
|
|
result = session_manager.is_session_bookable(session, current_time)
|
|
assert result is True
|
|
|
|
def test_is_session_bookable_booking_window_future(self):
|
|
"""Test session not bookable with booking window in future"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {
|
|
"user_info": {
|
|
"can_join": False,
|
|
"unableToBookUntilDate": "01-01-2030",
|
|
"unableToBookUntilTime": "10:00"
|
|
}
|
|
}
|
|
current_time = datetime.now(pytz.timezone("Europe/Paris"))
|
|
|
|
result = session_manager.is_session_bookable(session, current_time)
|
|
assert result is False
|
|
|
|
|
|
class TestCrossFitBookerMatchesPreferredSession:
|
|
"""Test cases for matches_preferred_session method"""
|
|
|
|
def test_matches_preferred_session_exact_match(self):
|
|
"""Test exact match with preferred session"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {
|
|
"start_timestamp": "2025-07-30 18:30:00",
|
|
"name_activity": "CONDITIONING"
|
|
}
|
|
current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris"))
|
|
|
|
# Mock PREFERRED_SESSIONS
|
|
with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]):
|
|
result = session_manager.matches_preferred_session(session, current_time)
|
|
assert result is True
|
|
|
|
def test_matches_preferred_session_fuzzy_match(self):
|
|
"""Test fuzzy match with preferred session"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {
|
|
"start_timestamp": "2025-07-30 18:30:00",
|
|
"name_activity": "CONDITIONING WORKOUT"
|
|
}
|
|
current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris"))
|
|
|
|
# Mock PREFERRED_SESSIONS
|
|
with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]):
|
|
result = session_manager.matches_preferred_session(session, current_time)
|
|
assert result is True
|
|
|
|
def test_matches_preferred_session_no_match(self):
|
|
"""Test no match with preferred session"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
auth_handler = AuthHandler('test_user', 'test_pass')
|
|
session_manager = SessionManager(auth_handler)
|
|
session = {
|
|
"start_timestamp": "2025-07-30 18:30:00",
|
|
"name_activity": "YOGA"
|
|
}
|
|
current_time = datetime(2025, 7, 30, 12, 0, 0, tzinfo=pytz.timezone("Europe/Paris"))
|
|
|
|
# Mock PREFERRED_SESSIONS
|
|
with patch('src.session_manager.PREFERRED_SESSIONS', [(2, "18:30", "CONDITIONING")]):
|
|
result = session_manager.matches_preferred_session(session, current_time)
|
|
assert result is False |