@@ -539,3 +539,341 @@ func TestRunDockerInspect(t *testing.T) {
539539 })
540540 }
541541}
542+
543+ func TestCheckDockerAccessible (t * testing.T ) {
544+ t .Run ("check docker accessibility" , func (t * testing.T ) {
545+ // This test verifies the function runs without panicking
546+ // In CI environments, Docker may or may not be available
547+ result := checkDockerAccessible ()
548+ t .Logf ("Docker accessible: %v" , result )
549+ // We don't assert the result since Docker availability varies by environment
550+ })
551+
552+ t .Run ("with custom DOCKER_HOST" , func (t * testing.T ) {
553+ // Test with a custom DOCKER_HOST that doesn't exist
554+ originalHost := os .Getenv ("DOCKER_HOST" )
555+ defer func () {
556+ if originalHost != "" {
557+ os .Setenv ("DOCKER_HOST" , originalHost )
558+ } else {
559+ os .Unsetenv ("DOCKER_HOST" )
560+ }
561+ }()
562+
563+ os .Setenv ("DOCKER_HOST" , "unix:///nonexistent/docker.sock" )
564+ result := checkDockerAccessible ()
565+ assert .False (t , result , "Should return false for nonexistent socket" )
566+ })
567+
568+ t .Run ("with unix:// prefix in DOCKER_HOST" , func (t * testing.T ) {
569+ originalHost := os .Getenv ("DOCKER_HOST" )
570+ defer func () {
571+ if originalHost != "" {
572+ os .Setenv ("DOCKER_HOST" , originalHost )
573+ } else {
574+ os .Unsetenv ("DOCKER_HOST" )
575+ }
576+ }()
577+
578+ // Set DOCKER_HOST with unix:// prefix
579+ os .Setenv ("DOCKER_HOST" , "unix:///var/run/docker.sock" )
580+ // Function should strip the unix:// prefix and check the path
581+ checkDockerAccessible ()
582+ // If it doesn't panic, the prefix stripping works
583+ })
584+ }
585+
586+ func TestCheckPortMapping (t * testing.T ) {
587+ tests := []struct {
588+ name string
589+ containerID string
590+ port string
591+ shouldError bool
592+ }{
593+ {
594+ name : "empty container ID" ,
595+ containerID : "" ,
596+ port : "8080" ,
597+ shouldError : true ,
598+ },
599+ {
600+ name : "invalid container ID" ,
601+ containerID : "invalid;id" ,
602+ port : "8080" ,
603+ shouldError : true ,
604+ },
605+ {
606+ name : "valid container ID format - nonexistent container" ,
607+ containerID : "abcdef123456" ,
608+ port : "8080" ,
609+ shouldError : true , // Will fail because container doesn't exist
610+ },
611+ {
612+ name : "empty port" ,
613+ containerID : "abcdef123456" ,
614+ port : "" ,
615+ shouldError : true ,
616+ },
617+ }
618+
619+ for _ , tt := range tests {
620+ t .Run (tt .name , func (t * testing.T ) {
621+ mapped , err := checkPortMapping (tt .containerID , tt .port )
622+
623+ if tt .shouldError {
624+ assert .Error (t , err , "Expected error for %s" , tt .name )
625+ assert .False (t , mapped , "Port should not be mapped on error" )
626+ } else {
627+ assert .NoError (t , err , "Unexpected error" )
628+ }
629+ })
630+ }
631+ }
632+
633+ func TestCheckStdinInteractive (t * testing.T ) {
634+ tests := []struct {
635+ name string
636+ containerID string
637+ expected bool
638+ }{
639+ {
640+ name : "empty container ID" ,
641+ containerID : "" ,
642+ expected : false ,
643+ },
644+ {
645+ name : "invalid container ID" ,
646+ containerID : "invalid;id" ,
647+ expected : false ,
648+ },
649+ {
650+ name : "valid container ID format - nonexistent container" ,
651+ containerID : "abcdef123456" ,
652+ expected : false , // Will fail because container doesn't exist
653+ },
654+ }
655+
656+ for _ , tt := range tests {
657+ t .Run (tt .name , func (t * testing.T ) {
658+ result := checkStdinInteractive (tt .containerID )
659+ assert .Equal (t , tt .expected , result , "Unexpected result for %s" , tt .name )
660+ })
661+ }
662+ }
663+
664+ func TestCheckLogDirMounted (t * testing.T ) {
665+ tests := []struct {
666+ name string
667+ containerID string
668+ logDir string
669+ expected bool
670+ }{
671+ {
672+ name : "empty container ID" ,
673+ containerID : "" ,
674+ logDir : "/tmp/gh-aw/mcp-logs" ,
675+ expected : false ,
676+ },
677+ {
678+ name : "invalid container ID" ,
679+ containerID : "invalid;id" ,
680+ logDir : "/tmp/gh-aw/mcp-logs" ,
681+ expected : false ,
682+ },
683+ {
684+ name : "valid container ID format - nonexistent container" ,
685+ containerID : "abcdef123456" ,
686+ logDir : "/tmp/gh-aw/mcp-logs" ,
687+ expected : false , // Will fail because container doesn't exist
688+ },
689+ {
690+ name : "empty log directory" ,
691+ containerID : "abcdef123456" ,
692+ logDir : "" ,
693+ expected : false ,
694+ },
695+ }
696+
697+ for _ , tt := range tests {
698+ t .Run (tt .name , func (t * testing.T ) {
699+ result := checkLogDirMounted (tt .containerID , tt .logDir )
700+ assert .Equal (t , tt .expected , result , "Unexpected result for %s" , tt .name )
701+ })
702+ }
703+ }
704+
705+ func TestValidateContainerizedEnvironment (t * testing.T ) {
706+ // Save original env vars
707+ origPort := os .Getenv ("MCP_GATEWAY_PORT" )
708+ origDomain := os .Getenv ("MCP_GATEWAY_DOMAIN" )
709+ origAPIKey := os .Getenv ("MCP_GATEWAY_API_KEY" )
710+ origLogDir := os .Getenv ("MCP_GATEWAY_LOG_DIR" )
711+ defer func () {
712+ if origPort != "" {
713+ os .Setenv ("MCP_GATEWAY_PORT" , origPort )
714+ } else {
715+ os .Unsetenv ("MCP_GATEWAY_PORT" )
716+ }
717+ if origDomain != "" {
718+ os .Setenv ("MCP_GATEWAY_DOMAIN" , origDomain )
719+ } else {
720+ os .Unsetenv ("MCP_GATEWAY_DOMAIN" )
721+ }
722+ if origAPIKey != "" {
723+ os .Setenv ("MCP_GATEWAY_API_KEY" , origAPIKey )
724+ } else {
725+ os .Unsetenv ("MCP_GATEWAY_API_KEY" )
726+ }
727+ if origLogDir != "" {
728+ os .Setenv ("MCP_GATEWAY_LOG_DIR" , origLogDir )
729+ } else {
730+ os .Unsetenv ("MCP_GATEWAY_LOG_DIR" )
731+ }
732+ }()
733+
734+ t .Run ("empty container ID" , func (t * testing.T ) {
735+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
736+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
737+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
738+
739+ result := ValidateContainerizedEnvironment ("" )
740+
741+ assert .True (t , result .IsContainerized , "Should be marked as containerized" )
742+ assert .Equal (t , "" , result .ContainerID , "Container ID should be empty" )
743+ assert .False (t , result .IsValid (), "Should be invalid with empty container ID" )
744+ assert .Contains (t , result .Error (), "Container ID could not be determined" )
745+ })
746+
747+ t .Run ("valid container ID with all env vars" , func (t * testing.T ) {
748+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
749+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
750+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
751+
752+ result := ValidateContainerizedEnvironment ("abcdef123456" )
753+
754+ assert .True (t , result .IsContainerized , "Should be marked as containerized" )
755+ assert .Equal (t , "abcdef123456" , result .ContainerID )
756+ // Will fail validation because Docker checks will fail in test environment
757+ // but we verify the container ID was set correctly
758+ })
759+
760+ t .Run ("missing required env vars" , func (t * testing.T ) {
761+ os .Unsetenv ("MCP_GATEWAY_PORT" )
762+ os .Unsetenv ("MCP_GATEWAY_DOMAIN" )
763+ os .Unsetenv ("MCP_GATEWAY_API_KEY" )
764+
765+ result := ValidateContainerizedEnvironment ("abcdef123456" )
766+
767+ assert .True (t , result .IsContainerized )
768+ assert .Equal (t , "abcdef123456" , result .ContainerID )
769+ assert .False (t , result .IsValid (), "Should be invalid with missing env vars" )
770+ assert .Len (t , result .MissingEnvVars , 3 , "Should have 3 missing env vars" )
771+ })
772+
773+ t .Run ("port validation failure" , func (t * testing.T ) {
774+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
775+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
776+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
777+
778+ result := ValidateContainerizedEnvironment ("abcdef123456" )
779+
780+ assert .True (t , result .IsContainerized )
781+ // Port mapping check will fail (container doesn't exist)
782+ assert .False (t , result .PortMapped , "Port should not be mapped for nonexistent container" )
783+ })
784+
785+ t .Run ("stdin interactive check" , func (t * testing.T ) {
786+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
787+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
788+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
789+
790+ result := ValidateContainerizedEnvironment ("abcdef123456" )
791+
792+ assert .True (t , result .IsContainerized )
793+ // Stdin check will fail (container doesn't exist)
794+ assert .False (t , result .StdinInteractive , "Stdin should not be interactive for nonexistent container" )
795+ })
796+
797+ t .Run ("log directory mount check with default" , func (t * testing.T ) {
798+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
799+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
800+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
801+ os .Unsetenv ("MCP_GATEWAY_LOG_DIR" )
802+
803+ result := ValidateContainerizedEnvironment ("abcdef123456" )
804+
805+ assert .True (t , result .IsContainerized )
806+ // Log dir check will fail (container doesn't exist)
807+ assert .False (t , result .LogDirMounted , "Log dir should not be mounted for nonexistent container" )
808+ // Should have a warning about log dir not being mounted
809+ assert .Greater (t , len (result .ValidationWarnings ), 0 , "Should have warnings" )
810+ })
811+
812+ t .Run ("log directory mount check with custom dir" , func (t * testing.T ) {
813+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
814+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
815+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
816+ os .Setenv ("MCP_GATEWAY_LOG_DIR" , "/custom/log/path" )
817+
818+ result := ValidateContainerizedEnvironment ("abcdef123456" )
819+
820+ assert .True (t , result .IsContainerized )
821+ assert .False (t , result .LogDirMounted )
822+ // Verify the warning mentions the custom path
823+ hasCustomPathWarning := false
824+ for _ , warning := range result .ValidationWarnings {
825+ if assert .Contains (t , warning , "/custom/log/path" ) {
826+ hasCustomPathWarning = true
827+ break
828+ }
829+ }
830+ if len (result .ValidationWarnings ) > 0 {
831+ assert .True (t , hasCustomPathWarning , "Should have warning with custom log path" )
832+ }
833+ })
834+
835+ t .Run ("docker not accessible" , func (t * testing.T ) {
836+ // Set a DOCKER_HOST that doesn't exist
837+ originalHost := os .Getenv ("DOCKER_HOST" )
838+ defer func () {
839+ if originalHost != "" {
840+ os .Setenv ("DOCKER_HOST" , originalHost )
841+ } else {
842+ os .Unsetenv ("DOCKER_HOST" )
843+ }
844+ }()
845+
846+ os .Setenv ("DOCKER_HOST" , "unix:///nonexistent/docker.sock" )
847+ os .Setenv ("MCP_GATEWAY_PORT" , "8080" )
848+ os .Setenv ("MCP_GATEWAY_DOMAIN" , "localhost" )
849+ os .Setenv ("MCP_GATEWAY_API_KEY" , "test-key" )
850+
851+ result := ValidateContainerizedEnvironment ("abcdef123456" )
852+
853+ assert .False (t , result .DockerAccessible , "Docker should not be accessible" )
854+ assert .False (t , result .IsValid (), "Should be invalid when Docker is not accessible" )
855+ // Should have error about Docker not being accessible
856+ hasDockerError := false
857+ for _ , err := range result .ValidationErrors {
858+ if assert .Contains (t , err , "Docker daemon" ) {
859+ hasDockerError = true
860+ break
861+ }
862+ }
863+ assert .True (t , hasDockerError , "Should have Docker accessibility error" )
864+ })
865+
866+ t .Run ("validation result error message format" , func (t * testing.T ) {
867+ os .Unsetenv ("MCP_GATEWAY_PORT" )
868+ os .Unsetenv ("MCP_GATEWAY_DOMAIN" )
869+ os .Unsetenv ("MCP_GATEWAY_API_KEY" )
870+
871+ result := ValidateContainerizedEnvironment ("abcdef123456" )
872+
873+ errorMsg := result .Error ()
874+ assert .NotEmpty (t , errorMsg , "Error message should not be empty" )
875+ assert .Contains (t , errorMsg , "Environment validation failed" , "Error should have header" )
876+ // Each error should be on its own line with bullet point
877+ assert .Contains (t , errorMsg , "\n - " , "Errors should be formatted with bullets" )
878+ })
879+ }
0 commit comments