236 lines
7.9 KiB
Python
236 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Comprehensive unit tests for the CrossFitBooker class in crossfit_booker.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from unittest.mock import Mock, patch
|
|
from datetime import date
|
|
import requests
|
|
|
|
# Add the parent directory to the path to import crossfit_booker
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from crossfit_booker import CrossFitBooker
|
|
|
|
|
|
class TestCrossFitBookerInit:
|
|
"""Test cases for CrossFitBooker initialization"""
|
|
|
|
def test_init_success(self):
|
|
"""Test successful initialization with all required env vars"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass',
|
|
'EMAIL_FROM': 'from@test.com',
|
|
'EMAIL_TO': 'to@test.com',
|
|
'EMAIL_PASSWORD': 'email_pass',
|
|
'TELEGRAM_TOKEN': 'telegram_token',
|
|
'TELEGRAM_CHAT_ID': '12345'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
assert booker.auth_token is None
|
|
assert booker.user_id is None
|
|
assert booker.session is not None
|
|
assert booker.notifier is not None
|
|
|
|
def test_init_missing_credentials(self):
|
|
"""Test initialization fails with missing credentials"""
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
try:
|
|
CrossFitBooker()
|
|
except ValueError as e:
|
|
assert str(e) == "Missing environment variables"
|
|
|
|
def test_init_partial_credentials(self):
|
|
"""Test initialization fails with partial credentials"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user'
|
|
# Missing PASSWORD
|
|
}, clear=True):
|
|
try:
|
|
CrossFitBooker()
|
|
except ValueError as e:
|
|
assert str(e) == "Missing environment variables"
|
|
|
|
|
|
class TestCrossFitBookerAuthHeaders:
|
|
"""Test cases for get_auth_headers method"""
|
|
|
|
def test_get_auth_headers_without_token(self):
|
|
"""Test headers without auth token"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
headers = booker.get_auth_headers()
|
|
assert "Authorization" not in headers
|
|
assert headers["User-Agent"] == "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0"
|
|
|
|
def test_get_auth_headers_with_token(self):
|
|
"""Test headers with auth token"""
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
booker.auth_token = "test_token_123"
|
|
headers = booker.get_auth_headers()
|
|
assert headers["Authorization"] == "Bearer test_token_123"
|
|
|
|
|
|
class TestCrossFitBookerLogin:
|
|
"""Test cases for login method"""
|
|
|
|
@patch('requests.Session.post')
|
|
def test_login_success(self, mock_post):
|
|
"""Test successful login flow"""
|
|
# Mock first login response
|
|
mock_response1 = Mock()
|
|
mock_response1.ok = True
|
|
mock_response1.json.return_value = {
|
|
"data": {
|
|
"user": {
|
|
"id_user": "12345"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Mock second login response
|
|
mock_response2 = Mock()
|
|
mock_response2.ok = True
|
|
mock_response2.json.return_value = {
|
|
"token": "test_bearer_token"
|
|
}
|
|
|
|
mock_post.side_effect = [mock_response1, mock_response2]
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
result = booker.login()
|
|
|
|
assert result is True
|
|
assert booker.user_id == "12345"
|
|
assert booker.auth_token == "test_bearer_token"
|
|
|
|
@patch('requests.Session.post')
|
|
def test_login_first_step_failure(self, mock_post):
|
|
"""Test login failure on first step"""
|
|
mock_response = Mock()
|
|
mock_response.ok = False
|
|
mock_response.status_code = 400
|
|
mock_response.text = "Bad Request"
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
result = booker.login()
|
|
|
|
assert result is False
|
|
assert booker.user_id is None
|
|
assert booker.auth_token is None
|
|
|
|
@patch('requests.Session.post')
|
|
def test_login_json_parsing_error(self, mock_post):
|
|
"""Test login with JSON parsing error"""
|
|
mock_response = Mock()
|
|
mock_response.ok = True
|
|
mock_response.json.side_effect = ValueError("Invalid JSON")
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
result = booker.login()
|
|
|
|
assert result is False
|
|
|
|
@patch('requests.Session.post')
|
|
def test_login_request_exception(self, mock_post):
|
|
"""Test login with request exception"""
|
|
mock_post.side_effect = requests.exceptions.ConnectionError("Network error")
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
result = booker.login()
|
|
|
|
assert result is False
|
|
|
|
|
|
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'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
result = booker.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'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
booker.auth_token = "test_token"
|
|
booker.user_id = "12345"
|
|
|
|
result = booker.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_failure(self, mock_post):
|
|
"""Test get_available_sessions with API failure"""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 400
|
|
mock_response.text = "Bad Request"
|
|
|
|
mock_post.return_value = mock_response
|
|
|
|
with patch.dict(os.environ, {
|
|
'CROSSFIT_USERNAME': 'test_user',
|
|
'CROSSFIT_PASSWORD': 'test_pass'
|
|
}):
|
|
booker = CrossFitBooker()
|
|
booker.auth_token = "test_token"
|
|
booker.user_id = "12345"
|
|
|
|
result = booker.get_available_sessions(date(2025, 7, 24), date(2025, 7, 25))
|
|
|
|
assert result is None |