FASHIONISTAR CI/CD
🔄 Celery Queues Deploy: 4aae6106b1530c3cc7d7d64f5e3c3e1d5015691d [GitHub Actions]
27c799c | # tests/test_ai_workflows.py | |
| """ | |
| Unit tests for FASHIONISTAR AI LangGraph Workflows: | |
| - MeasurementWorkflow | |
| - RecommendationWorkflow | |
| """ | |
| import uuid | |
| from unittest.mock import patch, MagicMock | |
| from django.test import TestCase | |
| from django.contrib.auth import get_user_model | |
| from apps.ai.workflows.measurement import MeasurementWorkflow | |
| from apps.ai.workflows.recommendation import RecommendationWorkflow | |
| from apps.measurements.models.scan import BodyScanSession | |
| from apps.measurements.models import MeasurementProfile | |
| User = get_user_model() | |
| class AIWorkflowsTests(TestCase): | |
| """Verify that both workflows compile and run successfully.""" | |
| def setUp(self): | |
| self.user = User.objects.create_user( | |
| email="ai_workflow_user@fashionistar.test", | |
| password="SecurePass123!", | |
| role="client", | |
| ) | |
| # Create a body scan session | |
| self.session = BodyScanSession.objects.create( | |
| owner=self.user, | |
| device_type="web", | |
| scan_provider="ai_camera", | |
| status="pending", | |
| ) | |
| # Mock the geometry pipeline run | |
| self.mock_geometry_result = { | |
| "is_valid": True, | |
| "validation_message": "Success", | |
| "quality_score": 0.85, | |
| "profile_fields": { | |
| "height": 175.0, | |
| "chest": 95.0, | |
| "waist": 80.0, | |
| "hips": 98.0, | |
| "shoulder_width": 45.0, | |
| }, | |
| "linear": { | |
| "height": 175.0, | |
| "shoulder_width": 45.0, | |
| }, | |
| "circumferences": { | |
| "chest": 95.0, | |
| "waist": 80.0, | |
| "hips": 98.0, | |
| } | |
| } | |
| def test_measurement_workflow_success(self, mock_rec_task, mock_pipeline): | |
| """MeasurementWorkflow runs, saves profile, and completes session.""" | |
| mock_pipeline.return_value = self.mock_geometry_result | |
| # Run workflow | |
| workflow = MeasurementWorkflow() | |
| result = workflow.execute({ | |
| "session_id": str(self.session.session_id), | |
| "user_id": self.user.id, | |
| "user_height_cm": 175.0, | |
| "user_weight_kg": 70.0, | |
| "landmarks": [{"x": 0.1, "y": 0.2, "z": 0.3} for _ in range(33)], | |
| }) | |
| # Assertions | |
| self.assertTrue(result["is_valid"]) | |
| self.assertEqual(result["quality_score"], 0.85) | |
| self.assertEqual(result["errors"], []) | |
| # Check DB updates | |
| self.session.refresh_from_db() | |
| self.assertEqual(self.session.status, "completed") | |
| self.assertEqual(self.session.scan_confidence, 0.85) | |
| # Check MeasurementProfile created | |
| profile = MeasurementProfile.objects.filter(owner=self.user).first() | |
| self.assertIsNotNone(profile) | |
| self.assertEqual(profile.height, 175.0) | |
| # Check recommendation task was fired | |
| mock_rec_task.assert_called_once_with( | |
| profile_id=str(profile.id), | |
| user_id=self.user.id, | |
| ) | |
| def test_recommendation_workflow_empty_candidates(self): | |
| """RecommendationWorkflow handles early exit elegantly when no candidates exist.""" | |
| # Create a measurement profile for the user | |
| profile = MeasurementProfile.objects.create( | |
| owner=self.user, | |
| height=175.0, | |
| bust=95.0, | |
| waist=80.0, | |
| hips=98.0, | |
| ) | |
| workflow = RecommendationWorkflow() | |
| result = workflow.execute({ | |
| "profile_id": str(profile.id), | |
| "user_id": self.user.id, | |
| }) | |
| # Assertions (should complete with empty recommendations since candidate pool is empty) | |
| self.assertEqual(result["recommendation_ids"], []) | |
| self.assertEqual(result["errors"], []) | |