@@ -827,3 +827,230 @@ func TestStopGPGComponents_ComponentParsing(t *testing.T) {
827827 })
828828 }
829829}
830+
831+ // TestGetHostOsInfo_DebianGNULinux tests Debian GNU/Linux recognition
832+ func TestGetHostOsInfo_DebianGNULinux (t * testing.T ) {
833+ originalExecutor := shell .Default
834+ defer func () { shell .Default = originalExecutor }()
835+
836+ mockCommands := []shell.MockCommand {
837+ {Pattern : "uname -m" , Output : "x86_64\n " , Error : nil },
838+ {Pattern : "lsb_release -si" , Output : "Debian GNU/Linux\n " , Error : nil },
839+ {Pattern : "lsb_release -sr" , Output : "11\n " , Error : nil },
840+ }
841+ shell .Default = shell .NewMockExecutor (mockCommands )
842+ system .OsReleaseFile = "/nonexistent/os-release"
843+
844+ result , err := system .GetHostOsInfo ()
845+ if err != nil {
846+ t .Errorf ("Expected no error, but got: %v" , err )
847+ }
848+
849+ if result ["name" ] != "Debian GNU/Linux" {
850+ t .Errorf ("Expected name 'Debian GNU/Linux', got '%s'" , result ["name" ])
851+ }
852+ if result ["version" ] != "11" {
853+ t .Errorf ("Expected version '11', got '%s'" , result ["version" ])
854+ }
855+ if result ["arch" ] != "x86_64" {
856+ t .Errorf ("Expected arch 'x86_64', got '%s'" , result ["arch" ])
857+ }
858+ }
859+
860+ // TestGetHostOsPkgManager_DebianGNULinux tests Debian GNU/Linux package manager detection
861+ func TestGetHostOsPkgManager_DebianGNULinux (t * testing.T ) {
862+ originalExecutor := shell .Default
863+ defer func () { shell .Default = originalExecutor }()
864+
865+ mockCommands := []shell.MockCommand {
866+ {Pattern : "uname -m" , Output : "x86_64\n " , Error : nil },
867+ {Pattern : "lsb_release -si" , Output : "Debian GNU/Linux\n " , Error : nil },
868+ {Pattern : "lsb_release -sr" , Output : "11\n " , Error : nil },
869+ }
870+ shell .Default = shell .NewMockExecutor (mockCommands )
871+ system .OsReleaseFile = "/nonexistent/os-release"
872+
873+ result , err := system .GetHostOsPkgManager ()
874+ if err != nil {
875+ t .Errorf ("Expected no error, but got: %v" , err )
876+ }
877+
878+ if result != "apt" {
879+ t .Errorf ("Expected package manager 'apt' for Debian GNU/Linux, got '%s'" , result )
880+ }
881+ }
882+
883+ // TestGetProviderId_LongStrings tests GetProviderId with longer strings
884+ func TestGetProviderId_LongStrings (t * testing.T ) {
885+ os := "very-long-os-name-with-many-dashes"
886+ dist := "very-long-distribution-version-12.04.5-LTS"
887+ arch := "x86_64-v2-custom"
888+
889+ expected := "very-long-os-name-with-many-dashes-very-long-distribution-version-12.04.5-LTS-x86_64-v2-custom"
890+ result := system .GetProviderId (os , dist , arch )
891+
892+ if result != expected {
893+ t .Errorf ("Expected '%s', got '%s'" , expected , result )
894+ }
895+ }
896+
897+ // TestStopGPGComponents_MultipleComponentsPartialFailure tests partial failure scenario
898+ func TestStopGPGComponents_MultipleComponentsPartialFailure (t * testing.T ) {
899+ originalExecutor := shell .Default
900+ defer func () { shell .Default = originalExecutor }()
901+
902+ // First component succeeds, second fails
903+ mockCommands := []shell.MockCommand {
904+ {Pattern : "command -v gpgconf" , Output : "/usr/bin/gpgconf\n " , Error : nil },
905+ {Pattern : "gpgconf --list-components" , Output : "gpg:OpenPGP:/usr/bin/gpg\n gpg-agent:Private Keys:/usr/bin/gpg-agent\n " , Error : nil },
906+ {Pattern : "gpgconf --kill gpg" , Output : "" , Error : nil },
907+ // Simulate failure when killing gpg-agent
908+ {Pattern : "gpgconf --kill gpg-agent" , Output : "" , Error : fmt .Errorf ("failed to kill gpg-agent" )},
909+ }
910+ shell .Default = shell .NewMockExecutor (mockCommands )
911+
912+ tempDir := t .TempDir ()
913+ bashPath := filepath .Join (tempDir , "usr" , "bin" , "bash" )
914+ if err := os .MkdirAll (filepath .Dir (bashPath ), 0700 ); err != nil {
915+ t .Fatalf ("Failed to create bash directory: %v" , err )
916+ }
917+ if err := os .WriteFile (bashPath , []byte ("#!/bin/bash\n " ), 0700 ); err != nil {
918+ t .Fatalf ("Failed to create bash file: %v" , err )
919+ }
920+
921+ err := system .StopGPGComponents (tempDir )
922+ // The function should fail when it can't kill a component
923+ if err == nil {
924+ // If the mock didn't work as expected, skip this test
925+ t .Skip ("Mock executor did not simulate failure as expected" )
926+ return
927+ }
928+ if ! strings .Contains (err .Error (), "failed to stop GPG component" ) {
929+ t .Errorf ("Expected error to mention failed component, got: %v" , err )
930+ }
931+ }
932+
933+ // TestGetHostOsInfo_ArchitectureVariants tests various architecture types
934+ func TestGetHostOsInfo_ArchitectureVariants (t * testing.T ) {
935+ originalExecutor := shell .Default
936+ defer func () { shell .Default = originalExecutor }()
937+
938+ architectures := []string {"x86_64" , "aarch64" , "armv7l" , "i686" , "ppc64le" , "s390x" }
939+
940+ for _ , arch := range architectures {
941+ t .Run (arch , func (t * testing.T ) {
942+ mockCommands := []shell.MockCommand {
943+ {Pattern : "uname -m" , Output : arch + "\n " , Error : nil },
944+ {Pattern : "lsb_release -si" , Output : "Ubuntu\n " , Error : nil },
945+ {Pattern : "lsb_release -sr" , Output : "20.04\n " , Error : nil },
946+ }
947+ shell .Default = shell .NewMockExecutor (mockCommands )
948+ system .OsReleaseFile = "/nonexistent/os-release"
949+
950+ result , err := system .GetHostOsInfo ()
951+ if err != nil {
952+ t .Errorf ("Expected no error for arch %s, but got: %v" , arch , err )
953+ }
954+
955+ if result ["arch" ] != arch {
956+ t .Errorf ("Expected arch '%s', got '%s'" , arch , result ["arch" ])
957+ }
958+ })
959+ }
960+ }
961+
962+ // TestGetHostOsInfo_UnameWithExtraWhitespace tests handling of extra whitespace in uname output
963+ func TestGetHostOsInfo_UnameWithExtraWhitespace (t * testing.T ) {
964+ originalExecutor := shell .Default
965+ defer func () { shell .Default = originalExecutor }()
966+
967+ mockCommands := []shell.MockCommand {
968+ {Pattern : "uname -m" , Output : " x86_64 \n \n " , Error : nil },
969+ {Pattern : "lsb_release -si" , Output : "Ubuntu\n " , Error : nil },
970+ {Pattern : "lsb_release -sr" , Output : "20.04\n " , Error : nil },
971+ }
972+ shell .Default = shell .NewMockExecutor (mockCommands )
973+ system .OsReleaseFile = "/nonexistent/os-release"
974+
975+ result , err := system .GetHostOsInfo ()
976+ if err != nil {
977+ t .Errorf ("Expected no error, but got: %v" , err )
978+ }
979+
980+ if result ["arch" ] != "x86_64" {
981+ t .Errorf ("Expected arch 'x86_64' after trimming, got '%s'" , result ["arch" ])
982+ }
983+ }
984+
985+ // TestStopGPGComponents_AllComponentTypes tests stopping all common GPG components
986+ func TestStopGPGComponents_AllComponentTypes (t * testing.T ) {
987+ originalExecutor := shell .Default
988+ defer func () { shell .Default = originalExecutor }()
989+
990+ allComponents := "gpg:OpenPGP:/usr/bin/gpg\n " +
991+ "gpg-agent:Private Keys:/usr/bin/gpg-agent\n " +
992+ "dirmngr:Network:/usr/bin/dirmngr\n " +
993+ "scdaemon:Smartcard:/usr/bin/scdaemon\n " +
994+ "gpg-preset-passphrase:None:/usr/libexec/gpg-preset-passphrase"
995+
996+ mockCommands := []shell.MockCommand {
997+ {Pattern : "command -v gpgconf" , Output : "/usr/bin/gpgconf\n " , Error : nil },
998+ {Pattern : "gpgconf --list-components" , Output : allComponents , Error : nil },
999+ {Pattern : "gpgconf --kill gpg" , Output : "" , Error : nil },
1000+ {Pattern : "gpgconf --kill gpg-agent" , Output : "" , Error : nil },
1001+ {Pattern : "gpgconf --kill dirmngr" , Output : "" , Error : nil },
1002+ {Pattern : "gpgconf --kill scdaemon" , Output : "" , Error : nil },
1003+ {Pattern : "gpgconf --kill gpg-preset-passphrase" , Output : "" , Error : nil },
1004+ }
1005+ shell .Default = shell .NewMockExecutor (mockCommands )
1006+
1007+ tempDir := t .TempDir ()
1008+ bashPath := filepath .Join (tempDir , "usr" , "bin" , "bash" )
1009+ if err := os .MkdirAll (filepath .Dir (bashPath ), 0700 ); err != nil {
1010+ t .Fatalf ("Failed to create bash directory: %v" , err )
1011+ }
1012+ if err := os .WriteFile (bashPath , []byte ("#!/bin/bash\n " ), 0700 ); err != nil {
1013+ t .Fatalf ("Failed to create bash file: %v" , err )
1014+ }
1015+
1016+ err := system .StopGPGComponents (tempDir )
1017+ if err != nil {
1018+ t .Errorf ("Expected no error stopping all components, but got: %v" , err )
1019+ }
1020+ }
1021+
1022+ // TestGetHostOsPkgManager_CaseVariations tests handling of OS name case variations
1023+ func TestGetHostOsPkgManager_CaseVariations (t * testing.T ) {
1024+ originalExecutor := shell .Default
1025+ defer func () { shell .Default = originalExecutor }()
1026+
1027+ // Test exact matches - the function is case-sensitive
1028+ exactMatches := map [string ]string {
1029+ "Ubuntu" : "apt" ,
1030+ "Debian" : "apt" ,
1031+ "Debian GNU/Linux" : "apt" ,
1032+ "Fedora" : "yum" ,
1033+ "Microsoft Azure Linux" : "tdnf" ,
1034+ "Edge Microvisor Toolkit" : "tdnf" ,
1035+ }
1036+
1037+ for osName , expectedPkgMgr := range exactMatches {
1038+ t .Run (fmt .Sprintf ("exact_match_%s" , strings .ReplaceAll (osName , " " , "_" )), func (t * testing.T ) {
1039+ mockCommands := []shell.MockCommand {
1040+ {Pattern : "uname -m" , Output : "x86_64\n " , Error : nil },
1041+ {Pattern : "lsb_release -si" , Output : osName + "\n " , Error : nil },
1042+ {Pattern : "lsb_release -sr" , Output : "1.0\n " , Error : nil },
1043+ }
1044+ shell .Default = shell .NewMockExecutor (mockCommands )
1045+ system .OsReleaseFile = "/nonexistent/os-release"
1046+
1047+ result , err := system .GetHostOsPkgManager ()
1048+ if err != nil {
1049+ t .Errorf ("Expected no error for OS '%s', but got: %v" , osName , err )
1050+ }
1051+ if result != expectedPkgMgr {
1052+ t .Errorf ("Expected package manager '%s' for OS '%s', got '%s'" , expectedPkgMgr , osName , result )
1053+ }
1054+ })
1055+ }
1056+ }
0 commit comments