gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/cli/cli_test.go (about) 1 // Copyright 2023 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cli 16 17 import ( 18 "reflect" 19 "testing" 20 21 "github.com/google/subcommands" 22 "gvisor.dev/gvisor/runsc/flag" 23 ) 24 25 var fakeFlagValues = [...]string{ 26 "1", 27 "2:2", 28 "foo", 29 "none", 30 "1,2,3", 31 "2h45m", 32 "1:1,2:2", 33 "0 0 1,100000 100000 65536", 34 "lisafs:self,lisafs:none", 35 } 36 37 func dupFlag(t *testing.T, cmd subcommands.Command, flagName string) *flag.Flag { 38 // To create a true duplicate of the flag, we need to duplicate the command 39 // and its FlagSet. 40 var cmd2 subcommands.Command 41 var fs2 flag.FlagSet 42 cmd2 = reflect.New(reflect.TypeOf(cmd).Elem()).Interface().(subcommands.Command) 43 cmd2.SetFlags(&fs2) 44 flag2 := fs2.Lookup(flagName) 45 if flag2 == nil { 46 t.Fatalf("duplicate FlagSet does not contain flag %q for cmd %q", flagName, cmd.Name()) 47 } 48 return flag2 49 } 50 51 // Tests that all the flags in all commands are idempotent; i.e. Set(String()) 52 // should be an idempotent operation. 53 func TestFlagSetIdempotent(t *testing.T) { 54 cmds := make(map[string][]subcommands.Command) 55 forEachCmd(func(cmd subcommands.Command, group string) { 56 if cmdList, ok := cmds[group]; ok { 57 cmds[group] = append(cmdList, cmd) 58 } else { 59 cmds[group] = []subcommands.Command{cmd} 60 } 61 }) 62 63 for group, cmdList := range cmds { 64 t.Run(group, func(t *testing.T) { 65 for _, cmd := range cmdList { 66 t.Run(cmd.Name(), func(t *testing.T) { 67 var fs flag.FlagSet 68 cmd.SetFlags(&fs) 69 70 // Iterate through all flags configured by this command. 71 fs.VisitAll(func(flag *flag.Flag) { 72 // Try a list of possible values for this flag. 73 matchedOneFlag := false 74 for _, v := range fakeFlagValues { 75 // Set() may have side effects even when it fails. So create a new 76 // flag for each try. 77 curFlag := dupFlag(t, cmd, flag.Name) 78 if err := curFlag.Value.Set(v); err != nil { 79 continue 80 } 81 // Worked. Now test that this flag is idempotent. 82 oldValue := curFlag.Value.String() 83 // Get a fresh flag.Flag to Set() this old value on. 84 newFlag := dupFlag(t, cmd, flag.Name) 85 if err := newFlag.Value.Set(oldValue); err != nil { 86 t.Errorf("flag %q from cmd %q is not idempotent: oldValue = %q, err = %v", flag.Name, cmd.Name(), oldValue, err) 87 return 88 } 89 // Compare this new flag value with old value. 90 if newValue := newFlag.Value.String(); newValue != oldValue { 91 t.Errorf("flag %q from cmd %q is not idempotent: oldValue = %q, newValue = %q", flag.Name, cmd.Name(), oldValue, newValue) 92 return 93 } 94 matchedOneFlag = true 95 } 96 if !matchedOneFlag { 97 t.Fatalf("none of the fake flag values work for flag %q from cmd %q", flag.Name, cmd.Name()) 98 } 99 }) 100 }) 101 } 102 }) 103 } 104 }