""" Test script for DELETE custom task status endpoint Tests: 1. Delete unused custom status 2. Delete status in use without reassignment (should fail) 3. Delete status in use with reassignment 4. Delete default status (should auto-assign new default) 5. Prevent deletion of last status 6. Delete non-existent status (should fail) """ import requests import json BASE_URL = "http://localhost:8000" def login_as_admin(): """Login and get access token""" response = requests.post( f"{BASE_URL}/auth/login", json={ "email": "admin@vfx.com", "password": "admin123" } ) if response.status_code == 200: return response.json()["access_token"] else: print(f"Login failed: {response.status_code}") print(response.text) return None def get_headers(token): """Get authorization headers""" return {"Authorization": f"Bearer {token}"} def test_delete_unused_status(token, project_id): """Test 1: Delete unused custom status""" print("\n=== Test 1: Delete unused custom status ===") # First, create a custom status create_response = requests.post( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token), json={"name": "Test Delete Status", "color": "#FF0000"} ) if create_response.status_code != 201: print(f"Failed to create status: {create_response.status_code}") print(create_response.text) return created_status = create_response.json()["status"] status_id = created_status["id"] print(f"Created status: {created_status['name']} (ID: {status_id})") # Now delete it delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{status_id}", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 200: result = delete_response.json() print(f"Message: {result['message']}") print(f"Remaining custom statuses: {len(result['all_statuses']['statuses'])}") else: print(f"Error: {delete_response.text}") def test_delete_status_in_use_without_reassignment(token, project_id): """Test 2: Delete status in use without reassignment (should fail)""" print("\n=== Test 2: Delete status in use without reassignment ===") # First, create a custom status create_response = requests.post( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token), json={"name": "In Use Status", "color": "#00FF00"} ) if create_response.status_code != 201: print(f"Failed to create status: {create_response.status_code}") return created_status = create_response.json()["status"] status_id = created_status["id"] print(f"Created status: {created_status['name']} (ID: {status_id})") # Get a task and update its status to the new custom status tasks_response = requests.get( f"{BASE_URL}/tasks/?project_id={project_id}", headers=get_headers(token) ) if tasks_response.status_code == 200: tasks = tasks_response.json() if tasks: task_id = tasks[0]["id"] print(f"Found task ID: {task_id}") # Update task status update_response = requests.put( f"{BASE_URL}/tasks/{task_id}/status", headers=get_headers(token), json={"status": status_id} ) if update_response.status_code == 200: print(f"Updated task {task_id} to status {status_id}") else: print(f"Failed to update task: {update_response.status_code}") print(update_response.text) return # Try to delete the status without reassignment delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{status_id}", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 422: error_detail = delete_response.json()["detail"] print(f"Expected error received:") print(f" Error: {error_detail.get('error', 'N/A')}") print(f" Task count: {error_detail.get('task_count', 'N/A')}") print(f" Task IDs: {error_detail.get('task_ids', 'N/A')}") else: print(f"Unexpected response: {delete_response.text}") def test_delete_status_with_reassignment(token, project_id): """Test 3: Delete status in use with reassignment""" print("\n=== Test 3: Delete status in use with reassignment ===") # Get the status we created in test 2 (should still exist) statuses_response = requests.get( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token) ) if statuses_response.status_code != 200: print("Failed to get statuses") return all_statuses = statuses_response.json() custom_statuses = all_statuses["statuses"] # Find the "In Use Status" status_to_delete = None for status in custom_statuses: if status["name"] == "In Use Status": status_to_delete = status break if not status_to_delete: print("Status 'In Use Status' not found") return status_id = status_to_delete["id"] print(f"Found status to delete: {status_to_delete['name']} (ID: {status_id})") # Delete with reassignment to system status "not_started" delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{status_id}?reassign_to_status_id=not_started", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 200: result = delete_response.json() print(f"Message: {result['message']}") print(f"Remaining custom statuses: {len(result['all_statuses']['statuses'])}") else: print(f"Error: {delete_response.text}") def test_delete_default_status(token, project_id): """Test 4: Delete default status (should auto-assign new default)""" print("\n=== Test 4: Delete default status ===") # Create two custom statuses status1_response = requests.post( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token), json={"name": "Default Status Test", "color": "#0000FF"} ) status2_response = requests.post( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token), json={"name": "Non-Default Status", "color": "#FFFF00"} ) if status1_response.status_code != 201 or status2_response.status_code != 201: print("Failed to create statuses") return status1 = status1_response.json()["status"] status1_id = status1["id"] # Set status1 as default update_response = requests.put( f"{BASE_URL}/projects/{project_id}/task-statuses/{status1_id}", headers=get_headers(token), json={"is_default": True} ) if update_response.status_code != 200: print("Failed to set default status") return print(f"Set '{status1['name']}' as default") # Delete the default status delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{status1_id}", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 200: result = delete_response.json() print(f"Message: {result['message']}") new_default = result['all_statuses']['default_status_id'] print(f"New default status ID: {new_default}") # Verify a new default was assigned if new_default != "not_started": print("✓ New default status was auto-assigned") else: print("✗ Default reverted to system status") else: print(f"Error: {delete_response.text}") def test_prevent_delete_last_status(token, project_id): """Test 5: Prevent deletion of last status""" print("\n=== Test 5: Prevent deletion of last status ===") # Get all custom statuses statuses_response = requests.get( f"{BASE_URL}/projects/{project_id}/task-statuses", headers=get_headers(token) ) if statuses_response.status_code != 200: print("Failed to get statuses") return all_statuses = statuses_response.json() custom_statuses = all_statuses["statuses"] print(f"Current custom statuses: {len(custom_statuses)}") # Delete all but one while len(custom_statuses) > 1: status_to_delete = custom_statuses[0] delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{status_to_delete['id']}", headers=get_headers(token) ) if delete_response.status_code == 200: custom_statuses.pop(0) print(f"Deleted status: {status_to_delete['name']}") else: print(f"Failed to delete: {delete_response.text}") break # Try to delete the last one if len(custom_statuses) == 1: last_status = custom_statuses[0] print(f"\nAttempting to delete last status: {last_status['name']}") delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{last_status['id']}", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 422: print(f"✓ Expected error: {delete_response.json()['detail']}") else: print(f"✗ Unexpected response: {delete_response.text}") def test_delete_nonexistent_status(token, project_id): """Test 6: Delete non-existent status (should fail)""" print("\n=== Test 6: Delete non-existent status ===") fake_status_id = "custom_nonexistent" delete_response = requests.delete( f"{BASE_URL}/projects/{project_id}/task-statuses/{fake_status_id}", headers=get_headers(token) ) print(f"Status: {delete_response.status_code}") if delete_response.status_code == 404: print(f"✓ Expected error: {delete_response.json()['detail']}") else: print(f"✗ Unexpected response: {delete_response.text}") def main(): print("Testing DELETE custom task status endpoint") print("=" * 50) # Login token = login_as_admin() if not token: print("Failed to login") return print("✓ Logged in successfully") # Get first project projects_response = requests.get( f"{BASE_URL}/projects/", headers=get_headers(token) ) if projects_response.status_code != 200: print("Failed to get projects") return projects = projects_response.json() if not projects: print("No projects found") return project_id = projects[0]["id"] print(f"Using project ID: {project_id}") # Run tests test_delete_unused_status(token, project_id) test_delete_status_in_use_without_reassignment(token, project_id) test_delete_status_with_reassignment(token, project_id) test_delete_default_status(token, project_id) test_prevent_delete_last_status(token, project_id) test_delete_nonexistent_status(token, project_id) print("\n" + "=" * 50) print("All tests completed!") if __name__ == "__main__": main()