Init Repo
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user