LinkDesk/backend/test_delete_custom_task_sta...

346 lines
12 KiB
Python

"""
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()