Gatherings MCP Server

#!/usr/bin/env python3 """ Test script for the Gatherings application. This script demonstrates the functionality of the Gatherings application by running through the example scenario from the requirements. """ import os import sys from models import DatabaseManager from services import GatheringService def main(): # Remove the test database if it exists if os.path.exists("test_gatherings.db"): os.remove("test_gatherings.db") # Initialize the database and service db_manager = DatabaseManager("test_gatherings.db") service = GatheringService(db_manager) print("=== Gatherings Application Test ===") # Step 1: Create a gathering with 5 members print("\n1. Creating gathering with 5 members...") gathering_id = "2025-03-01-friendsbeer" gathering = service.create_gathering(gathering_id, 5) print(f"Created gathering: {gathering.id}") print(f"Total members: {gathering.total_members}") print(f"Status: {gathering.status.value}") # Debug: Print all member names to see what's available members_names = [m.name for m in gathering.members] print(f"Members: {', '.join(members_names)}") # Step 2: Add expenses for members print("\n2. Adding expenses...") # First expense will rename an unnamed member to "Roy" gathering, member = service.add_expense(gathering_id, "Roy", 50) print(f"Added expense of $50.00 for {member.name}") # Second expense will rename another unnamed member to "David" gathering, member = service.add_expense(gathering_id, "David", 100) print(f"Added expense of $100.00 for {member.name}") # Third expense will rename another unnamed member to "Felix" gathering, member = service.add_expense(gathering_id, "Felix", 50) print(f"Added expense of $50.00 for {member.name}") print(f"Total expenses: ${gathering.total_expenses:.2f}") # Get updated member list to see renamed members members_names = [m.name for m in gathering.members] print(f"Updated members: {', '.join(members_names)}") # Step 3: Calculate reimbursements print("\n3. Calculating reimbursements...") reimbursements = service.calculate_reimbursements(gathering_id) # Get fresh data after status change gathering = service.get_gathering(gathering_id) print(f"Expense per member: ${gathering.expense_per_member:.2f}") print("Reimbursements:") for name, amount in reimbursements.items(): if amount < 0: print(f" {name} gets reimbursed ${abs(amount):.2f}") else: print(f" {name} needs to pay ${amount:.2f}") # Step 4: Record payments from unnamed members print("\n4. Recording payments from unnamed members...") # Use the actual member names from the database unnamed_members = [m.name for m in gathering.members if m.name.startswith("member")] if len(unnamed_members) >= 2: # Record payment for first unnamed member gathering, member = service.record_payment(gathering_id, unnamed_members[0], 40) print(f"Recorded payment of $40.00 from {member.name}") # Record payment for second unnamed member gathering, member = service.record_payment(gathering_id, unnamed_members[1], 40) print(f"Recorded payment of $40.00 from {member.name}") else: print("Warning: Not enough unnamed members available.") # Step 5: Record reimbursements to named members print("\n5. Recording reimbursements to named members...") # Roy needs to receive 10, so he pays -10 gathering, member = service.record_payment(gathering_id, "Roy", -10) print(f"Recorded reimbursement of $10.00 to {member.name}") # David needs to receive 60, so he pays -60 gathering, member = service.record_payment(gathering_id, "David", -60) print(f"Recorded reimbursement of $60.00 to {member.name}") # Felix needs to receive 10, so he pays -10 gathering, member = service.record_payment(gathering_id, "Felix", -10) print(f"Recorded reimbursement of $10.00 to {member.name}") # Step 6: Close the gathering print("\n6. Closing the gathering...") gathering = service.close_gathering(gathering_id) print(f"Gathering status: {gathering.status.value}") # Step 7: Testing member addition and removal print("\n7. Testing member addition and removal...") # Create a new gathering specifically for testing member operations member_ops_id = "2025-03-05-membertest" member_gathering = service.create_gathering(member_ops_id, 3) print(f"Created test gathering: {member_ops_id}") print(f"Initial members: {[m.name for m in member_gathering.members]}") # Add a new member gathering, new_member = service.add_member(member_ops_id, "Charlie") print(f"Added member: {new_member.name}") print(f"Total members: {gathering.total_members}") print(f"Updated members: {[m.name for m in gathering.members]}") # Try adding a member with a duplicate name try: service.add_member(member_ops_id, "Charlie") print("ERROR: Should not be able to add duplicate member!") except ValueError as e: print(f"Successfully prevented adding duplicate member: {e}") # Try removing a member who doesn't exist try: service.remove_member(member_ops_id, "NonExistentMember") print("ERROR: Should not be able to remove non-existent member!") except ValueError as e: print(f"Successfully prevented removing non-existent member: {e}") # Try removing a member with expenses try: # Add an expense for a member first service.add_expense(member_ops_id, "Charlie", 25) print("Added expense for Charlie") # Try to remove the member service.remove_member(member_ops_id, "Charlie") print("ERROR: Should not be able to remove member with expenses!") except ValueError as e: print(f"Successfully prevented removing member with expenses: {e}") # Remove an unused member # First find an unused member all_members = [m.name for m in gathering.members] unused_members = [m for m in all_members if m.startswith("member")] if unused_members: unused_member = unused_members[0] gathering = service.remove_member(member_ops_id, unused_member) print(f"Successfully removed unused member: {unused_member}") print(f"Total members: {gathering.total_members}") print(f"Remaining members: {[m.name for m in gathering.members]}") else: print("No unused members to remove") # Try closing and then adding/removing members service.close_gathering(member_ops_id) print(f"Closed gathering: {member_ops_id}") try: service.add_member(member_ops_id, "TooLate") print("ERROR: Should not be able to add member to closed gathering!") except ValueError as e: print(f"Successfully prevented adding member to closed gathering: {e}") try: service.remove_member(member_ops_id, "Charlie") print("ERROR: Should not be able to remove member from closed gathering!") except ValueError as e: print(f"Successfully prevented removing member from closed gathering: {e}") # Step 8: Testing gathering deletion print("\n8. Testing gathering deletion...") try: # Try to delete a closed gathering (should fail) try: service.delete_gathering(gathering_id) print("ERROR: Should not be able to delete a closed gathering!") except ValueError as e: print(f"Successfully prevented deletion of closed gathering: {e}") # Test force deletion of a closed gathering try: service.delete_gathering(gathering_id, force=True) # Verify force deletion deleted_gathering = service.get_gathering(gathering_id) if deleted_gathering is None: print("Successfully force-deleted a closed gathering") else: print("ERROR: Force deletion of closed gathering failed!") except Exception as e: print(f"ERROR: Force deletion should have worked: {e}") # Create a new gathering with expenses for deletion test test_gathering_id = "2025-03-02-deletetest" test_gathering = service.create_gathering(test_gathering_id, 3) print(f"Created test gathering: {test_gathering_id}") # Add some expenses to the test gathering service.add_expense(test_gathering_id, "Alice", 30) service.add_expense(test_gathering_id, "Bob", 45) print("Added expenses to test gathering") # Delete the test gathering service.delete_gathering(test_gathering_id) # Verify deletion deleted_gathering = service.get_gathering(test_gathering_id) if deleted_gathering is None: print("Successfully deleted test gathering with expenses") else: print("ERROR: Gathering with expenses was not deleted!") # Create another gathering for deletion test another_gathering_id = "2025-03-03-deletetest" another_gathering = service.create_gathering(another_gathering_id, 2) print(f"Created another test gathering: {another_gathering_id}") # Delete the gathering service.delete_gathering(another_gathering_id) # Verify deletion deleted_gathering = service.get_gathering(another_gathering_id) if deleted_gathering is None: print("Successfully deleted empty gathering") else: print("ERROR: Empty gathering was not deleted!") except Exception as e: print(f"Error during deletion test: {e}") # Print final summary print("\n=== Final Summary ===") # Create a new gathering that mirrors our original test scenario final_gathering_id = "2025-03-04-finaltest" final_gathering = service.create_gathering(final_gathering_id, 5) # Add the same expenses as in the original test service.add_expense(final_gathering_id, "Roy", 50) service.add_expense(final_gathering_id, "David", 100) service.add_expense(final_gathering_id, "Felix", 50) # Record the same payments as in the original test # Get the unnamed members final_gathering = service.get_gathering(final_gathering_id) # Print all member names to verify what members exist in the database print(f"All members in new gathering: {[m.name for m in final_gathering.members]}") # Add some expenses and payments to demonstrate the summary service.add_expense(final_gathering_id, "Alice", 60) service.add_expense(final_gathering_id, "Bob", 30) # Get fresh data after adding expenses final_gathering = service.get_gathering(final_gathering_id) # Get the remaining unnamed member - check if any exist unnamed = [m.name for m in final_gathering.members if m.name.startswith("member")] print(f"Unnamed members after expenses: {unnamed}") # Only try to record a payment if there's an unnamed member if unnamed: try: service.record_payment(final_gathering_id, unnamed[0], 30) print(f"Recorded payment of $30.00 from {unnamed[0]}") except ValueError as e: print(f"Error recording payment: {e}") else: print("No unnamed members available for payment recording.") # Get the summary try: summary = service.get_payment_summary(final_gathering_id) print(f"Total expenses: ${summary['total_expenses']:.2f}") print(f"Expense per member: ${summary['expense_per_member']:.2f}") print("\nMember details:") for name, data in summary["members"].items(): print(f" {name}:") print(f" Expenses: ${data['expenses']:.2f}") print(f" Paid: ${data['paid']:.2f}") print(f" Balance: ${data['balance']:.2f}") print(f" Status: {data['status']}") except Exception as e: print(f"Error getting payment summary: {e}") print("\nTest completed successfully!") if __name__ == "__main__": main()