checkpoint 1

This commit is contained in:
2025-08-22 18:27:12 -07:00
parent 5f0cd85406
commit 6273138a65
19 changed files with 350 additions and 5 deletions

View File

@@ -0,0 +1,114 @@
#!/bin/bash
# Activity Table Validation Script
# This script tests the activity table implementation
# Configuration
API_URL="http://localhost:8888/api/api/activities" # Changed port to 8888 to match container
TIMEOUT=10
# Function to display test results
display_result() {
local test_name=$1
local result=$2
local message=$3
if [ "$result" = "PASS" ]; then
echo "$test_name: $message"
else
echo "$test_name: $message"
fi
}
# Function to wait for API to be ready
wait_for_api() {
echo "Waiting for API to start..."
attempts=0
max_attempts=60 # Increased timeout to 60 seconds
while true; do
# Check for startup messages
if curl -s -m 1 "http://localhost:8888" | grep -q "Uvicorn running on" || \
curl -s -m 1 "http://localhost:8888" | grep -q "Application startup complete" || \
curl -s -m 1 "http://localhost:8888" | grep -q "Server is ready"; then
echo "API started successfully"
break
fi
attempts=$((attempts+1))
if [ $attempts -ge $max_attempts ]; then
echo "API failed to start within $max_attempts seconds"
exit 1
fi
sleep 1
done
}
# Wait for API to be ready
wait_for_api
# Test 1: Basic API response
echo "Running basic API response test..."
response=$(curl -s -m $TIMEOUT "$API_URL" | jq '.')
if [ $? -eq 0 ]; then
if [[ "$response" == *"activities"* ]] && [[ "$response" == *"total_pages"* ]] && [[ "$response" == *"status"* ]]; then
display_result "Basic API Response" PASS "API returns expected structure"
else
display_result "Basic API Response" FAIL "API response doesn't contain expected fields"
fi
else
display_result "Basic API Response" FAIL "API request failed"
fi
# Test 2: Pagination test
echo "Running pagination test..."
page1=$(curl -s -m $TIMEOUT "$API_URL?page=1" | jq '.')
page2=$(curl -s -m $TIMEOUT "$API_URL?page=2" | jq '.')
if [ $? -eq 0 ]; then
page1_count=$(echo "$page1" | jq '.activities | length')
page2_count=$(echo "$page2" | jq '.activities | length')
if [ "$page1_count" -gt 0 ] && [ "$page2_count" -gt 0 ]; then
display_result "Pagination Test" PASS "Both pages contain activities"
else
display_result "Pagination Test" FAIL "One or more pages are empty"
fi
else
display_result "Pagination Test" FAIL "API request failed"
fi
# Test 3: Data consistency test
echo "Running data consistency test..."
activity_id=$(echo "$page1" | jq -r '.activities[0].id')
activity_name=$(echo "$page1" | jq -r '.activities[0].name')
details_response=$(curl -s -m $TIMEOUT "$API_URL/$activity_id" | jq '.')
if [ $? -eq 0 ]; then
details_id=$(echo "$details_response" | jq -r '.id')
details_name=$(echo "$details_response" | jq -r '.name')
if [ "$activity_id" = "$details_id" ] && [ "$activity_name" = "$details_name" ]; then
display_result "Data Consistency Test" PASS "Activity details match API response"
else
display_result "Data Consistency Test" FAIL "Activity details don't match API response"
fi
else
display_result "Data Consistency Test" FAIL "API request failed"
fi
# Test 4: Error handling test
echo "Running error handling test..."
error_response=$(curl -s -m $TIMEOUT "$API_URL/999999999" | jq '.')
if [ $? -eq 0 ]; then
if [[ "$error_response" == *"detail"* ]] && [[ "$error_response" == *"not found"* ]]; then
display_result "Error Handling Test" PASS "API returns expected error for non-existent activity"
else
display_result "Error Handling Test" FAIL "API doesn't return expected error for non-existent activity"
fi
else
display_result "Error Handling Test" FAIL "API request failed"
fi
echo "All tests completed."

102
tests/test_sync.py Normal file
View File

@@ -0,0 +1,102 @@
import pytest
import sys
from unittest.mock import Mock, patch
# Add the project root to the Python path
sys.path.insert(0, '/app')
from garminsync.database import sync_database
from garminsync.garmin import GarminClient
def test_sync_database_with_valid_activities():
"""Test sync_database with valid API response"""
mock_client = Mock(spec=GarminClient)
mock_client.get_activities.return_value = [
{"activityId": 12345, "startTimeLocal": "2023-01-01T10:00:00"},
{"activityId": 67890, "startTimeLocal": "2023-01-02T11:00:00"}
]
with patch('garminsync.database.get_session') as mock_session:
mock_session.return_value.query.return_value.filter_by.return_value.first.return_value = None
sync_database(mock_client)
# Verify get_activities was called
mock_client.get_activities.assert_called_once_with(0, 1000)
# Verify database operations
mock_session.return_value.add.assert_called()
mock_session.return_value.commit.assert_called()
def test_sync_database_with_none_activities():
"""Test sync_database with None response from API"""
mock_client = Mock(spec=GarminClient)
mock_client.get_activities.return_value = None
with patch('garminsync.database.get_session') as mock_session:
sync_database(mock_client)
# Verify get_activities was called
mock_client.get_activities.assert_called_once_with(0, 1000)
# Verify no database operations
mock_session.return_value.add.assert_not_called()
mock_session.return_value.commit.assert_not_called()
def test_sync_database_with_missing_fields():
"""Test sync_database with activities missing required fields"""
mock_client = Mock(spec=GarminClient)
mock_client.get_activities.return_value = [
{"activityId": 12345}, # Missing startTimeLocal
{"startTimeLocal": "2023-01-02T11:00:00"}, # Missing activityId
{"activityId": 67890, "startTimeLocal": "2023-01-03T12:00:00"} # Valid
]
with patch('garminsync.database.get_session') as mock_session:
mock_session.return_value.query.return_value.filter_by.return_value.first.return_value = None
sync_database(mock_client)
# Verify only one activity was added (the valid one)
assert mock_session.return_value.add.call_count == 1
mock_session.return_value.commit.assert_called()
def test_sync_database_with_existing_activities():
"""Test sync_database doesn't duplicate existing activities"""
mock_client = Mock(spec=GarminClient)
mock_client.get_activities.return_value = [
{"activityId": 12345, "startTimeLocal": "2023-01-01T10:00:00"}
]
with patch('garminsync.database.get_session') as mock_session:
# Mock existing activity
mock_session.return_value.query.return_value.filter_by.return_value.first.return_value = Mock()
sync_database(mock_client)
# Verify no new activities were added
mock_session.return_value.add.assert_not_called()
mock_session.return_value.commit.assert_called()
def test_sync_database_with_invalid_activity_data():
"""Test sync_database with invalid activity data types"""
mock_client = Mock(spec=GarminClient)
mock_client.get_activities.return_value = [
"invalid activity data", # Not a dict
None, # None value
{"activityId": 12345, "startTimeLocal": "2023-01-01T10:00:00"} # Valid
]
with patch('garminsync.database.get_session') as mock_session:
mock_session.return_value.query.return_value.filter_by.return_value.first.return_value = None
sync_database(mock_client)
# Verify only one activity was added (the valid one)
assert mock_session.return_value.add.call_count == 1
mock_session.return_value.commit.assert_called()