Initial working version

This commit is contained in:
Joey Yakimowich-Payne 2025-05-14 17:45:07 -06:00
commit ec1c5958ce
33 changed files with 4547 additions and 0 deletions

8
tests/__init__.py Normal file
View file

@ -0,0 +1,8 @@
"""
Tests package initialization - adds the project root to the Python path
"""
import os
import sys
# Add the parent directory to Python's path so 'src' module can be found
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

88
tests/test_auth.py Normal file
View file

@ -0,0 +1,88 @@
"""
Test script to verify the new Twitch API authentication
"""
import os
import sys
import logging
from dotenv import load_dotenv
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger('auth-test')
def test_twitch_auth():
"""Test the Twitch authentication with client credentials flow"""
# Check for required libraries
try:
import requests
except ImportError:
logger.error("The 'requests' library is required. Install it with: pip install requests")
return False
try:
from src.core.auth import TwitchAuth
except ImportError:
logger.error("Failed to import TwitchAuth from src.core.auth")
return False
# Get credentials from environment variables
client_id = os.environ.get("TWITCH_CLIENT_ID")
client_secret = os.environ.get("TWITCH_CLIENT_SECRET")
if not client_id or not client_secret:
logger.error("TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET environment variables must be set")
logger.info("You can get these from https://dev.twitch.tv/console/apps")
return False
# Try to get a token using the TwitchAuth class
logger.info("Attempting to get Twitch OAuth token...")
try:
auth = TwitchAuth(client_id, client_secret)
oauth_token = auth.get_oauth_token()
if not oauth_token or not auth.access_token:
logger.error("Failed to get token using TwitchAuth")
return False
logger.info("Successfully obtained access token!")
if auth.token_expiry:
expiry_hours = (auth.token_expiry - time.time()) / 3600
logger.info(f"Token expires in: {expiry_hours:.1f} hours")
# Validate the token by making a simple API call
logger.info("Validating token with a simple API call...")
headers = {
'Client-ID': client_id,
'Authorization': f"Bearer {auth.access_token}"
}
# Get top games as a test
response = requests.get('https://api.twitch.tv/helix/games/top', headers=headers)
if response.status_code == 200:
games = response.json().get('data', [])
logger.info(f"API call successful! Retrieved {len(games)} top games.")
if games:
logger.info(f"Top game: {games[0]['name']}")
return True
else:
logger.error(f"API call failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"Error during authentication: {e}")
return False
if __name__ == "__main__":
import time
print("Testing Twitch API authentication...")
if test_twitch_auth():
print("Authentication test PASSED!")
sys.exit(0)
else:
print("Authentication test FAILED!")
sys.exit(1)

34
tests/test_controller.py Normal file
View file

@ -0,0 +1,34 @@
import traceback
import sys
import os
print("Starting controller test...")
try:
import sdl2
print("SDL2 imported successfully")
except ImportError as e:
print(f"Failed to import SDL2: {e}")
sys.exit(1)
try:
from src.game.input.gamepad import VirtualController
print("Controller support module imported successfully")
except Exception as e:
print(f"Failed to import controller support module: {e}")
traceback.print_exc()
sys.exit(1)
try:
print("Creating VirtualController...")
controller = VirtualController()
print("VirtualController created successfully")
print(f"Controller available: {controller.is_available()}")
print(f"Physical controller available: {controller.is_physical_controller_available()}")
print("Test completed successfully!")
except Exception as e:
print(f"Error during testing: {e}")
traceback.print_exc()
sys.exit(1)

View file

@ -0,0 +1,37 @@
import time
import traceback
import sys
print("Starting controller redirection test...")
try:
from src.game.input.gamepad import VirtualController
print("Controller support module imported successfully")
controller = VirtualController()
print(f"Controller available: {controller.is_available()}")
print(f"Physical controller available: {controller.is_physical_controller_available()}")
if controller.is_physical_controller_available():
print("Testing controller redirection...")
# Start redirection
success = controller.start_controller_redirection()
print(f"Redirection started: {success}")
if success:
# Let it run for a few seconds
print("Redirection active for 5 seconds. Try using your physical controller...")
for i in range(5, 0, -1):
print(f"{i}...")
time.sleep(1)
# Stop redirection
controller.stop_controller_redirection()
print("Redirection stopped")
print("Test completed successfully!")
except Exception as e:
print(f"Error during testing: {e}")
traceback.print_exc()
sys.exit(1)

View file

@ -0,0 +1,50 @@
import time
import traceback
import sys
print("Starting game control test...")
try:
from src.game.input.gamepad import VirtualController
print("Controller support module imported successfully")
controller = VirtualController()
print(f"Controller available: {controller.is_available()}")
if controller.is_available():
print("Testing basic controller actions...")
# Test some basic controller actions
print("Pressing A button")
controller.press_a()
time.sleep(0.5)
print("Pressing B button")
controller.press_b()
time.sleep(0.5)
print("Moving left stick up")
controller.move_left_stick_up()
time.sleep(0.5)
print("Moving right stick right")
controller.move_right_stick_right()
time.sleep(0.5)
print("Pressing left trigger")
controller.press_left_trigger()
time.sleep(0.5)
print("Pressing D-pad up")
controller.press_dpad_up()
time.sleep(0.5)
# Reset controller at the end
controller.reset()
print("Controller reset")
print("Test completed successfully!")
except Exception as e:
print(f"Error during testing: {e}")
traceback.print_exc()
sys.exit(1)

162
tests/test_token_cache.py Normal file
View file

@ -0,0 +1,162 @@
"""
Test script to verify token caching functionality
"""
import os
import sys
import logging
import time
import json
from dotenv import load_dotenv
# Add the parent directory to Python's path so 'src' module can be found
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
# Load environment variables from .env file
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger('token-cache-test')
def test_token_cache(cache_file: str = "test_token_cache.json") -> bool:
"""Test the token caching functionality"""
try:
import requests
except ImportError:
logger.error("The 'requests' library is required. Install it with: pip install requests")
return False
# Import the bot class
from src.core.twitch import TwitchBot
from src.core.auth import TwitchAuth
# Get credentials from environment variables
client_id = os.environ.get("TWITCH_CLIENT_ID")
client_secret = os.environ.get("TWITCH_CLIENT_SECRET")
username = os.environ.get("TWITCH_USERNAME")
channel = os.environ.get("TWITCH_CHANNEL")
if not all([client_id, client_secret, username, channel]):
logger.error("Missing required environment variables")
logger.info("Please set TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET, TWITCH_USERNAME, and TWITCH_CHANNEL")
return False
# Remove the cache file if it exists (to start fresh)
if os.path.exists(cache_file):
logger.info(f"Removing existing cache file: {cache_file}")
os.remove(cache_file)
# Use mock tokens for testing
mock_access_token = "mock_access_token_for_testing"
mock_refresh_token = "mock_refresh_token_for_testing"
mock_expires_in = 14400 # 4 hours
# Create a bot instance with the test cache file
logger.info("Creating bot instance...")
bot = TwitchBot(
username=username,
client_id=client_id,
client_secret=client_secret,
channel=channel,
access_token=mock_access_token,
refresh_token=mock_refresh_token,
token_cache_file=cache_file
)
# First call should use the provided token and save it
logger.info("First call to get_oauth_token (should use the provided token)...")
oauth_token1 = bot.get_oauth_token()
# Verify the cache file was created
if not os.path.exists(cache_file):
logger.error(f"Cache file was not created: {cache_file}")
return False
# Load and display cache file
with open(cache_file, 'r') as f:
cache_data = json.load(f)
logger.info(f"Cache file created with {len(cache_data)} entries")
logger.info(f"Token expires at: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(cache_data['expires_at']))}")
# Save the token for comparison
token1 = bot.access_token
# Create a new bot instance to test loading from cache
logger.info("Creating a second bot instance (should load token from cache)...")
bot2 = TwitchBot(
username=username,
client_id=client_id,
client_secret=client_secret,
channel=channel,
token_cache_file=cache_file
)
# Second call should use the cached token
logger.info("Second call to get_oauth_token (should use cached token)...")
oauth_token2 = bot2.get_oauth_token()
token2 = bot2.access_token
# Compare tokens
if token1 == token2:
logger.info("SUCCESS: Both instances used the same token")
else:
logger.error("FAILURE: Different tokens were used")
return False
# Simulate token expiration by modifying the cache file
logger.info("Simulating token expiration...")
with open(cache_file, 'r') as f:
cache_data = json.load(f)
# Set expiry to now minus 10 minutes
cache_data['expires_at'] = time.time() - 600
with open(cache_file, 'w') as f:
json.dump(cache_data, f)
# Create a third bot instance with the "expired" token
# Since we don't want to trigger a real OAuth flow in tests,
# we'll provide a new mock token to use
logger.info("Creating a third bot instance with expired token cache...")
mock_new_token = "mock_new_token_after_expiration"
mock_new_refresh = "mock_new_refresh_after_expiration"
bot3 = TwitchBot(
username=username,
client_id=client_id,
client_secret=client_secret,
channel=channel,
access_token=mock_new_token,
refresh_token=mock_new_refresh,
token_cache_file=cache_file
)
# Third call should use the new token since the cached one is expired
logger.info("Third call to get_oauth_token (should use the new mock token due to expiration)...")
oauth_token3 = bot3.get_oauth_token()
token3 = bot3.access_token
# Compare tokens - they should be different
if token1 != token3:
logger.info("SUCCESS: Token was refreshed after expiration")
else:
logger.error("FAILURE: Expired token was not refreshed")
return False
# Clean up
if os.path.exists(cache_file):
os.remove(cache_file)
logger.info(f"Removed test cache file: {cache_file}")
logger.info("All token cache tests passed!")
return True
if __name__ == "__main__":
print("Testing token caching functionality...")
if test_token_cache():
print("All token cache tests PASSED!")
sys.exit(0)
else:
print("Token cache tests FAILED!")
sys.exit(1)