@@ -218,7 +218,7 @@ def test_init_with_services_and_components_together(self):
218218 "--services" ,
219219 "auth" ,
220220 "--components" ,
221- "worker" ,
221+ "database, worker" , # Auth needs database (backend always included), plus explicit worker
222222 "--no-interactive" ,
223223 "--yes" ,
224224 "--output-dir" ,
@@ -234,12 +234,12 @@ def test_init_with_services_and_components_together(self):
234234 # Should show both services and components
235235 assert "🔧 Services: auth" in output
236236 assert "📦 Infrastructure:" in output
237- # Both auth (database) and worker (redis) dependencies should be present
238- assert (
239- ( "database" in output and "redis" in output )
240- or "database, redis " in output
241- or " redis, database" in output
242- )
237+ # Should have all components: backend, database (auth), worker and redis (worker dep)
238+ assert "backend" in output
239+ assert "database" in output
240+ assert "worker " in output
241+ # Worker adds redis as dependency
242+ assert "redis" in output
243243
244244 def test_init_services_help_text_accuracy (self ):
245245 """Test that init command help shows correct services help text."""
@@ -478,3 +478,183 @@ def test_service_with_whitespace(self):
478478 )
479479
480480 assert result .returncode == 0 # Should handle whitespace gracefully
481+
482+
483+ class TestServiceComponentCompatibilityValidation :
484+ """Test service-component compatibility validation in CLI."""
485+
486+ def test_services_with_compatible_explicit_components_success (self ):
487+ """Test that services work when user provides compatible explicit components."""
488+ with tempfile .TemporaryDirectory () as temp_dir :
489+ result = subprocess .run (
490+ [
491+ "uv" ,
492+ "run" ,
493+ "python" ,
494+ "-m" ,
495+ "aegis" ,
496+ "init" ,
497+ "test-compatible" ,
498+ "--services" ,
499+ "auth" ,
500+ "--components" ,
501+ "database" , # Auth requires database (backend is always included)
502+ "--no-interactive" ,
503+ "--yes" ,
504+ "--output-dir" ,
505+ temp_dir ,
506+ ],
507+ capture_output = True ,
508+ text = True ,
509+ )
510+
511+ assert result .returncode == 0
512+ assert "🔧 Services: auth" in result .stdout
513+ assert "backend" in result .stdout
514+ assert "database" in result .stdout
515+
516+ def test_services_with_insufficient_explicit_components_failure (self ):
517+ """Test that services fail when user provides insufficient explicit components."""
518+ result = subprocess .run (
519+ [
520+ "uv" ,
521+ "run" ,
522+ "python" ,
523+ "-m" ,
524+ "aegis" ,
525+ "init" ,
526+ "test-insufficient" ,
527+ "--services" ,
528+ "auth" ,
529+ "--components" ,
530+ "worker" , # Auth requires database, but user only provided worker
531+ "--no-interactive" ,
532+ "--yes" ,
533+ "--output-dir" ,
534+ "/tmp" , # Won't be created due to validation failure
535+ ],
536+ capture_output = True ,
537+ text = True ,
538+ )
539+
540+ assert result .returncode == 1
541+ assert "Service-component compatibility errors:" in result .stderr
542+ assert "Service 'auth' requires component 'database'" in result .stderr
543+ assert "💡 Suggestion:" in result .stderr
544+ # Should suggest adding missing components (worker auto-adds redis dependency)
545+ assert "database" in result .stderr
546+
547+ def test_services_with_no_explicit_components_auto_add (self ):
548+ """Test that services auto-add components when user doesn't provide --components."""
549+ with tempfile .TemporaryDirectory () as temp_dir :
550+ result = subprocess .run (
551+ [
552+ "uv" ,
553+ "run" ,
554+ "python" ,
555+ "-m" ,
556+ "aegis" ,
557+ "init" ,
558+ "test-auto-add" ,
559+ "--services" ,
560+ "auth" ,
561+ "--no-interactive" ,
562+ "--yes" ,
563+ "--output-dir" ,
564+ temp_dir ,
565+ ],
566+ capture_output = True ,
567+ text = True ,
568+ )
569+
570+ assert result .returncode == 0
571+ assert "🔧 Services: auth" in result .stdout
572+ # Should auto-add both required components
573+ assert "backend" in result .stdout
574+ assert "database" in result .stdout
575+
576+ def test_services_with_partial_explicit_components_failure (self ):
577+ """Test that services fail when explicit components are partially sufficient."""
578+ result = subprocess .run (
579+ [
580+ "uv" ,
581+ "run" ,
582+ "python" ,
583+ "-m" ,
584+ "aegis" ,
585+ "init" ,
586+ "test-partial" ,
587+ "--services" ,
588+ "auth" ,
589+ "--components" ,
590+ "redis" , # Auth requires database (missing database, backend is always included)
591+ "--no-interactive" ,
592+ "--yes" ,
593+ "--output-dir" ,
594+ "/tmp" ,
595+ ],
596+ capture_output = True ,
597+ text = True ,
598+ )
599+
600+ assert result .returncode == 1
601+ assert "Service-component compatibility errors:" in result .stderr
602+ assert "Service 'auth' requires component 'database'" in result .stderr
603+
604+ def test_multiple_services_with_insufficient_components_failure (self ):
605+ """Test validation with multiple services and insufficient components."""
606+ # Note: This test assumes we might add more services in the future
607+ # For now, we only have auth service, so this tests the error handling pattern
608+ result = subprocess .run (
609+ [
610+ "uv" ,
611+ "run" ,
612+ "python" ,
613+ "-m" ,
614+ "aegis" ,
615+ "init" ,
616+ "test-multi-insufficient" ,
617+ "--services" ,
618+ "auth" , # Only auth available for now
619+ "--components" ,
620+ "worker,scheduler" , # Missing database for auth
621+ "--no-interactive" ,
622+ "--yes" ,
623+ "--output-dir" ,
624+ "/tmp" ,
625+ ],
626+ capture_output = True ,
627+ text = True ,
628+ )
629+
630+ assert result .returncode == 1
631+ assert "Service-component compatibility errors:" in result .stderr
632+ assert "Service 'auth' requires component 'database'" in result .stderr
633+
634+ def test_services_error_message_suggests_alternatives (self ):
635+ """Test that error message suggests both adding components and removing --components."""
636+ result = subprocess .run (
637+ [
638+ "uv" ,
639+ "run" ,
640+ "python" ,
641+ "-m" ,
642+ "aegis" ,
643+ "init" ,
644+ "test-suggestions" ,
645+ "--services" ,
646+ "auth" ,
647+ "--components" ,
648+ "redis" , # Wrong component for auth
649+ "--no-interactive" ,
650+ "--yes" ,
651+ "--output-dir" ,
652+ "/tmp" ,
653+ ],
654+ capture_output = True ,
655+ text = True ,
656+ )
657+
658+ assert result .returncode == 1
659+ assert "💡 Suggestion: Add missing components" in result .stderr
660+ assert "remove --components to let services auto-add" in result .stderr
0 commit comments