LinkDesk/backend/test_bulk_shot_requirements...

213 lines
7.0 KiB
Python

"""
Test script to validate all requirements for bulk shot creation enhancement
Validates Requirements 3.5: Bulk shot creation project consistency
"""
import requests
import json
BASE_URL = "http://localhost:8000"
# Test credentials
LOGIN_DATA = {
"email": "admin@vfx.com",
"password": "admin123"
}
def login():
"""Login and get access token"""
response = requests.post(f"{BASE_URL}/auth/login", json=LOGIN_DATA)
if response.status_code == 200:
return response.json()["access_token"]
else:
print(f"Login failed: {response.status_code}")
return None
def test_requirement_3_5():
"""
Test Requirement 3.5: WHEN bulk creating shots, THE VFX_System SHALL validate
that all shots belong to the same project as the episode
"""
print("=== Testing Requirement 3.5: Bulk Shot Project Consistency ===\n")
token = login()
if not token:
return False
headers = {"Authorization": f"Bearer {token}"}
episode_id = 1
# Get episode information first to know which project it belongs to
episode_response = requests.get(f"{BASE_URL}/episodes/{episode_id}", headers=headers)
if episode_response.status_code != 200:
print(f" ✗ Could not get episode info: {episode_response.json()}")
return False
episode_data = episode_response.json()
expected_project_id = episode_data['project_id']
print(f" Episode {episode_id} belongs to project {expected_project_id}")
# Test 1: Verify all shots in bulk creation belong to same project as episode
print("\n1. Testing project consistency validation...")
import time
timestamp = int(time.time())
bulk_data = {
"name_prefix": f"REQ35_{timestamp}_",
"shot_count": 5,
"start_number": 1,
"number_padding": 3,
"frame_start": 1001,
"frame_end": 1100,
"description_template": "Requirement 3.5 test shot {shot_name}",
"create_default_tasks": True
}
response = requests.post(
f"{BASE_URL}/shots/bulk?episode_id={episode_id}",
headers=headers,
json=bulk_data
)
if response.status_code != 201:
print(f" ✗ Bulk creation failed: {response.json()}")
return False
result = response.json()
created_shots = result['created_shots']
# Verify all shots have the same project_id as the episode
project_ids = [shot['project_id'] for shot in created_shots]
all_same_project = len(set(project_ids)) == 1
correct_project = all(pid == expected_project_id for pid in project_ids)
print(f" ✓ Created {len(created_shots)} shots")
print(f" ✓ All shots have same project_id: {all_same_project}")
print(f" ✓ All shots belong to episode's project ({expected_project_id}): {correct_project}")
if not (all_same_project and correct_project):
print(f" ✗ Project consistency validation failed!")
print(f" Expected project_id: {expected_project_id}")
print(f" Actual project_ids: {project_ids}")
return False
# Test 2: Verify project-scoped uniqueness validation
print("\n2. Testing project-scoped uniqueness validation...")
# Try to create shots with same names in same project (should fail)
duplicate_data = {
"name_prefix": f"REQ35_{timestamp}_", # Same prefix as above
"shot_count": 3,
"start_number": 1, # Same start number - will create duplicates
"number_padding": 3,
"frame_start": 1001,
"frame_end": 1100,
"create_default_tasks": False
}
response = requests.post(
f"{BASE_URL}/shots/bulk?episode_id={episode_id}",
headers=headers,
json=duplicate_data
)
if response.status_code == 400:
error_detail = response.json()['detail']
if "already exist in project" in error_detail:
print(f" ✓ Correctly rejected duplicate names in project: {error_detail}")
else:
print(f" ✗ Wrong error message: {error_detail}")
return False
else:
print(f" ✗ Should have rejected duplicate names: {response.json()}")
return False
# Test 3: Verify bulk validation prevents partial creation
print("\n3. Testing atomic bulk validation...")
# Create a scenario where some names would be duplicates
mixed_data = {
"name_prefix": f"MIXED_{timestamp}_",
"shot_count": 5,
"start_number": 1,
"number_padding": 3,
"frame_start": 1001,
"frame_end": 1100,
"create_default_tasks": False
}
# First, create some shots
response1 = requests.post(
f"{BASE_URL}/shots/bulk?episode_id={episode_id}",
headers=headers,
json=mixed_data
)
if response1.status_code != 201:
print(f" ✗ First bulk creation failed: {response1.json()}")
return False
# Now try to create overlapping shots (should fail completely)
overlapping_data = {
"name_prefix": f"MIXED_{timestamp}_",
"shot_count": 5,
"start_number": 3, # Will overlap with shots 3, 4, 5 from above
"number_padding": 3,
"frame_start": 1001,
"frame_end": 1100,
"create_default_tasks": False
}
response2 = requests.post(
f"{BASE_URL}/shots/bulk?episode_id={episode_id}",
headers=headers,
json=overlapping_data
)
if response2.status_code == 400:
print(f" ✓ Correctly rejected overlapping bulk creation")
# Verify no partial shots were created by checking shot count
list_response = requests.get(
f"{BASE_URL}/shots/?episode_id={episode_id}",
headers=headers
)
if list_response.status_code == 200:
shots = list_response.json()
mixed_shots = [s for s in shots if s['name'].startswith(f"MIXED_{timestamp}_")]
if len(mixed_shots) == 5: # Only the first 5 should exist
print(f" ✓ No partial creation occurred - atomic validation working")
else:
print(f" ✗ Partial creation detected: {len(mixed_shots)} shots found")
return False
else:
print(f" ✗ Could not verify shot count: {list_response.json()}")
return False
else:
print(f" ✗ Should have rejected overlapping creation: {response2.json()}")
return False
print("\n✓ All Requirement 3.5 validations passed!")
return True
def main():
"""Run all requirement validation tests"""
print("=== Bulk Shot Creation Requirements Validation ===\n")
success = test_requirement_3_5()
if success:
print("\n🎉 All requirements validated successfully!")
print("✓ Requirement 3.5: Bulk shot project consistency - PASSED")
else:
print("\n❌ Requirements validation failed!")
return 1
return 0
if __name__ == "__main__":
exit(main())