""" Tests for Scenario Creation Endpoint Error Handling. Tests comprehensive error handling for POST /api/v1/package/{uuid}/scenario/ including package not found, permission denied, validation errors, and database errors. """ from django.test import TestCase, tag import json from uuid import uuid4 from epdb.logic import PackageManager, UserManager from epdb.models import Scenario @tag("api", "scenario_creation") class ScenarioCreationAPITests(TestCase): """Test scenario creation endpoint error handling.""" @classmethod def setUpTestData(cls): """Set up test data: users and packages.""" cls.user = UserManager.create_user( "scenario-test-user", "scenario-test@envipath.com", "SuperSafe", set_setting=False, add_to_group=False, is_active=True, ) cls.other_user = UserManager.create_user( "other-user", "other@envipath.com", "SuperSafe", set_setting=False, add_to_group=False, is_active=True, ) cls.package = PackageManager.create_package( cls.user, "Test Package", "Test package for scenario creation" ) def test_create_scenario_package_not_found(self): """Test that non-existent package UUID returns 404.""" self.client.force_login(self.user) fake_uuid = uuid4() payload = { "name": "Test Scenario", "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [], } response = self.client.post( f"/api/v1/package/{fake_uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 404) self.assertIn("Package not found", response.json()["detail"]) def test_create_scenario_insufficient_permissions(self): """Test that unauthorized access returns 403.""" self.client.force_login(self.other_user) payload = { "name": "Test Scenario", "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 403) self.assertIn("permission", response.json()["detail"].lower()) def test_create_scenario_invalid_ai_type(self): """Test that unknown additional information type returns 400.""" self.client.force_login(self.user) payload = { "name": "Test Scenario", "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [ {"type": "invalid_type_that_does_not_exist", "data": {"some_field": "some_value"}} ], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 400) response_data = response.json() self.assertIn("Validation errors", response_data["detail"]) def test_create_scenario_validation_error(self): """Test that invalid additional information data returns 400.""" self.client.force_login(self.user) # Use malformed data structure for an actual AI type payload = { "name": "Test Scenario", "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [ { "type": "invalid_type_name", "data": None, # This should cause a validation error } ], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) # Should return 422 for validation errors self.assertEqual(response.status_code, 422) def test_create_scenario_success(self): """Test that valid scenario creation returns 200.""" self.client.force_login(self.user) payload = { "name": "Test Scenario", "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data["name"], "Test Scenario") self.assertEqual(data["description"], "Test description") # Verify scenario was actually created scenario = Scenario.objects.get(name="Test Scenario") self.assertEqual(scenario.package, self.package) self.assertEqual(scenario.scenario_type, "biodegradation") def test_create_scenario_auto_name(self): """Test that empty name triggers auto-generation.""" self.client.force_login(self.user) payload = { "name": "", # Empty name should be auto-generated "description": "Test description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 200) data = response.json() # Auto-generated name should follow pattern "Scenario N" self.assertTrue(data["name"].startswith("Scenario ")) def test_create_scenario_xss_protection(self): """Test that XSS attempts are sanitized.""" self.client.force_login(self.user) payload = { "name": "Clean Name", "description": "Description", "scenario_date": "2024-01-01", "scenario_type": "biodegradation", "additional_information": [], } response = self.client.post( f"/api/v1/package/{self.package.uuid}/scenario/", data=json.dumps(payload), content_type="application/json", ) self.assertEqual(response.status_code, 200) data = response.json() # XSS should be cleaned out self.assertNotIn("