| // Copyright 2024 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| //go:build linux | |
| package command | |
| import ( | |
| "os" | |
| "os/user" | |
| "path" | |
| "strconv" | |
| "syscall" | |
| "testing" | |
| "github.com/GoogleCloudPlatform/google-guest-agent/internal/cfg" | |
| ) | |
| func TestPipeName(t *testing.T) { | |
| if err := cfg.Load(nil); err != nil { | |
| t.Fatal(err) | |
| } | |
| tests := []struct { | |
| name string | |
| listener KnownListeners | |
| customDir string | |
| want string | |
| }{ | |
| { | |
| name: "default_coreplugin", | |
| listener: ListenerCorePlugin, | |
| want: "/run/google-guest-agent/cmd-monitors/coreplugin", | |
| }, | |
| { | |
| name: "default_guest", | |
| listener: ListenerGuestAgent, | |
| want: "/run/google-guest-agent/cmd-monitors/guestagent", | |
| }, | |
| { | |
| name: "custom_pipe_name", | |
| listener: ListenerGuestAgent, | |
| customDir: "/run/custom", | |
| want: "/run/custom/guestagent", | |
| }, | |
| } | |
| for _, tc := range tests { | |
| t.Run(tc.name, func(t *testing.T) { | |
| if tc.customDir != "" { | |
| cfg.Retrieve().Unstable.CommandPipePath = tc.customDir | |
| } | |
| if got := PipeName(tc.listener); got != tc.want { | |
| t.Errorf("PipeName(%q) = %q, want: %q", tc.listener, got, tc.want) | |
| } | |
| }) | |
| } | |
| } | |
| func TestMkdirpWithPerms(t *testing.T) { | |
| self, err := user.Current() | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| uidself, err := strconv.Atoi(self.Uid) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| gidself, err := strconv.Atoi(self.Gid) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| testcases := []struct { | |
| name string | |
| dir string | |
| filemode os.FileMode | |
| uid int | |
| gid int | |
| }{ | |
| { | |
| name: "standard create", | |
| dir: path.Join(t.TempDir(), "test"), | |
| filemode: os.FileMode(0700) | os.ModeDir, | |
| uid: uidself, | |
| gid: gidself, | |
| }, | |
| { | |
| name: "nested create", | |
| dir: path.Join(t.TempDir(), "test", "test2", "test3"), | |
| filemode: os.FileMode(0700) | os.ModeDir, | |
| uid: uidself, | |
| gid: gidself, | |
| }, | |
| } | |
| for _, tc := range testcases { | |
| t.Run(tc.name, func(t *testing.T) { | |
| err := mkdirpWithPerms(tc.dir, tc.filemode, tc.uid, tc.gid) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| t.Cleanup(func() { os.RemoveAll(tc.dir) }) | |
| stat, err := os.Stat(tc.dir) | |
| if err != nil { | |
| t.Fatalf("directory %s does not exist: %v", tc.dir, err) | |
| } | |
| statT, ok := stat.Sys().(*syscall.Stat_t) | |
| if !ok { | |
| t.Errorf("could not determine owner of %s", tc.dir) | |
| } | |
| if !stat.IsDir() { | |
| t.Errorf("%s exists and is not a directory", tc.dir) | |
| } | |
| if filemode := stat.Mode(); filemode != tc.filemode { | |
| t.Errorf("incorrect permissions on %s: got %o want %o", tc.dir, filemode, tc.filemode) | |
| } | |
| if statT.Uid != uint32(tc.uid) { | |
| t.Errorf("incorrect owner of %s: got %d want %d", tc.dir, statT.Uid, tc.uid) | |
| } | |
| if statT.Gid != uint32(tc.gid) { | |
| t.Errorf("incorrect group owner of %s: got %d want %d", tc.dir, statT.Gid, tc.gid) | |
| } | |
| }) | |
| } | |
| } | |
| func TestMorePermissive(t *testing.T) { | |
| tests := []struct { | |
| name string | |
| i int | |
| j int | |
| want bool | |
| }{ | |
| { | |
| name: "same_permissions", | |
| i: 0754, | |
| j: 0754, | |
| want: false, | |
| }, | |
| { | |
| name: "more_permissive_user", | |
| i: 0755, | |
| j: 0754, | |
| want: true, | |
| }, | |
| { | |
| name: "more_permissive_group", | |
| i: 0764, | |
| j: 0754, | |
| want: true, | |
| }, | |
| { | |
| name: "more_permissive_world", | |
| i: 0754, | |
| j: 0654, | |
| want: true, | |
| }, | |
| { | |
| name: "less_permissive_user", | |
| i: 0754, | |
| j: 0755, | |
| want: false, | |
| }, | |
| { | |
| name: "less_permissive_group", | |
| i: 0744, | |
| j: 0764, | |
| want: false, | |
| }, | |
| { | |
| name: "less_permissive_world", | |
| i: 0654, | |
| j: 0754, | |
| want: false, | |
| }, | |
| { | |
| name: "missing_read_but_adding_write", | |
| i: 0754, | |
| j: 0764, | |
| want: true, | |
| }, | |
| } | |
| for _, tc := range tests { | |
| t.Run(tc.name, func(t *testing.T) { | |
| got := morePermissive(tc.i, tc.j) | |
| if got != tc.want { | |
| t.Errorf("morePermissive(%o, %o) = %v, want: %v", tc.i, tc.j, got, tc.want) | |
| } | |
| }) | |
| } | |
| } |