Skip to content

Commit 4de794b

Browse files
committed
support bool flags
1 parent a21edde commit 4de794b

3 files changed

Lines changed: 199 additions & 8 deletions

File tree

tool/cmdwrapper/cmdwrapper.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
type Flag struct {
1919
DefaultValue string
2020
Description string
21+
IsBool bool
2122
}
2223

2324
const delimiter = "-"
@@ -55,7 +56,21 @@ func AddFlags(prefix string, flagConfigs map[string]Flag) map[string]*string {
5556
if prefix != "" {
5657
flagName = prefix + delimiter + flagName
5758
}
58-
flags[key] = flag.String(flagName, flagConfig.DefaultValue, flagConfig.Description)
59+
if flagConfig.IsBool {
60+
strPtr := new(string)
61+
*strPtr = flagConfig.DefaultValue
62+
flag.BoolFunc(flagName, flagConfig.Description, func(value string) error {
63+
if value == "" || value == "true" {
64+
*strPtr = "true"
65+
} else {
66+
*strPtr = "false"
67+
}
68+
return nil
69+
})
70+
flags[key] = strPtr
71+
} else {
72+
flags[key] = flag.String(flagName, flagConfig.DefaultValue, flagConfig.Description)
73+
}
5974
}
6075
return flags
6176
}
@@ -64,8 +79,14 @@ func ExecuteAgentCommand(command string, flags map[string]*string) error {
6479
args := []string{fmt.Sprintf("-%s", command)}
6580

6681
for key, value := range flags {
67-
if *value != "" {
68-
args = append(args, fmt.Sprintf("-%s%s%s", command, delimiter, key), *value)
82+
if *value != "" && *value != "false" {
83+
if *value == "true" {
84+
// For boolean flags, just add the flag name without value
85+
args = append(args, fmt.Sprintf("-%s%s%s", command, delimiter, key))
86+
} else {
87+
// For string flags, add both flag name and value
88+
args = append(args, fmt.Sprintf("-%s%s%s", command, delimiter, key), *value)
89+
}
6990
}
7091
}
7192

tool/cmdwrapper/cmdwrapper_test.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package cmdwrapper
55

66
import (
77
"flag"
8+
"os"
89
"os/exec"
910
"testing"
1011

@@ -137,3 +138,172 @@ func TestExecuteAgentCommand_HappyPath(t *testing.T) {
137138
}
138139
}
139140
}
141+
142+
func TestExecuteAgentCommand_BooleanFlags(t *testing.T) {
143+
// Save the original execCommand and restore it after the test
144+
originalExecCommand := execCommand
145+
originalFindAgentBinary := findAgentBinary
146+
defer func() {
147+
execCommand = originalExecCommand
148+
findAgentBinary = originalFindAgentBinary
149+
}()
150+
151+
var capturedArgs []string
152+
153+
// Mock execCommand
154+
execCommand = func(path string, args ...string) *exec.Cmd {
155+
capturedArgs = args
156+
cmd := exec.Command("echo", "1")
157+
return cmd
158+
}
159+
findAgentBinary = func(_ string) (string, error) {
160+
return paths.AgentBinaryPath, nil
161+
}
162+
163+
// Test data with boolean and string flags
164+
command := "config-wizard"
165+
trueValue := "true"
166+
falseValue := "false"
167+
stringValue := "test-value"
168+
emptyValue := ""
169+
flags := map[string]*string{
170+
"boolTrue": &trueValue,
171+
"boolFalse": &falseValue,
172+
"stringFlag": &stringValue,
173+
"emptyString": &emptyValue,
174+
}
175+
176+
// Execute the function
177+
err := ExecuteAgentCommand(command, flags)
178+
179+
// Verify no error occurred
180+
if err != nil {
181+
t.Errorf("Expected no error, got %v", err)
182+
}
183+
184+
// Verify the first argument is the command
185+
if len(capturedArgs) == 0 || capturedArgs[0] != "-config-wizard" {
186+
t.Errorf("Expected first argument to be -config-wizard, got %v", capturedArgs)
187+
return
188+
}
189+
190+
// Verify boolean true flag is present (without value)
191+
if !contains(capturedArgs, "-config-wizard-boolTrue") {
192+
t.Errorf("Expected -config-wizard-boolTrue flag to be present in %v", capturedArgs)
193+
}
194+
195+
// Verify string flag is present with value
196+
if !containsSequence(capturedArgs, "-config-wizard-stringFlag", "test-value") {
197+
t.Errorf("Expected -config-wizard-stringFlag test-value sequence in %v", capturedArgs)
198+
}
199+
200+
// Verify boolean false flag is NOT present
201+
if contains(capturedArgs, "-config-wizard-boolFalse") {
202+
t.Errorf("Expected -config-wizard-boolFalse flag to NOT be present in %v", capturedArgs)
203+
}
204+
205+
// Verify empty string flag is NOT present
206+
if contains(capturedArgs, "-config-wizard-emptyString") {
207+
t.Errorf("Expected -config-wizard-emptyString flag to NOT be present in %v", capturedArgs)
208+
}
209+
}
210+
211+
// Helper function to check if slice contains a value
212+
func contains(slice []string, value string) bool {
213+
for _, item := range slice {
214+
if item == value {
215+
return true
216+
}
217+
}
218+
return false
219+
}
220+
221+
// helper to check if slice contains a sequence of values
222+
func containsSequence(slice []string, first, second string) bool {
223+
for i := 0; i < len(slice)-1; i++ {
224+
if slice[i] == first && slice[i+1] == second {
225+
return true
226+
}
227+
}
228+
return false
229+
}
230+
231+
func TestBooleanFlags(t *testing.T) {
232+
tests := []struct {
233+
name string
234+
args []string
235+
expected string
236+
}{
237+
{
238+
name: "boolean flag without value",
239+
args: []string{"-testBool"},
240+
expected: "true",
241+
},
242+
{
243+
name: "boolean flag with true value",
244+
args: []string{"-testBool=true"},
245+
expected: "true",
246+
},
247+
{
248+
name: "boolean flag with false value",
249+
args: []string{"-testBool=false"},
250+
expected: "false",
251+
},
252+
{
253+
name: "boolean flag not provided",
254+
args: []string{},
255+
expected: "false",
256+
},
257+
}
258+
259+
for _, tt := range tests {
260+
t.Run(tt.name, func(t *testing.T) {
261+
flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
262+
263+
flagConfigs := map[string]Flag{
264+
"testBool": {
265+
DefaultValue: "false",
266+
Description: "test boolean flag",
267+
IsBool: true,
268+
},
269+
}
270+
271+
flags := AddFlags("", flagConfigs)
272+
273+
oldArgs := os.Args
274+
os.Args = append([]string{"test"}, tt.args...)
275+
defer func() { os.Args = oldArgs }()
276+
277+
flag.Parse()
278+
279+
if *flags["testBool"] != tt.expected {
280+
t.Errorf("Expected %s, got %s", tt.expected, *flags["testBool"])
281+
}
282+
})
283+
}
284+
}
285+
286+
func TestMixedFlags(t *testing.T) {
287+
flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
288+
289+
flagConfigs := map[string]Flag{
290+
"boolFlag": {DefaultValue: "false", Description: "boolean flag", IsBool: true},
291+
"stringFlag": {DefaultValue: "default", Description: "string flag"},
292+
}
293+
294+
flags := AddFlags("", flagConfigs)
295+
296+
oldArgs := os.Args
297+
os.Args = []string{"test", "-boolFlag", "-stringFlag=value"}
298+
defer func() { os.Args = oldArgs }()
299+
300+
flag.Parse()
301+
302+
if *flags["boolFlag"] != "true" {
303+
t.Errorf("Expected boolean flag to be true, got %s", *flags["boolFlag"])
304+
}
305+
306+
if *flags["stringFlag"] != "value" {
307+
t.Errorf("Expected string flag to be 'value', got %s", *flags["stringFlag"])
308+
}
309+
}

tool/wizard/flags/flags.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ const (
1818
)
1919

2020
var WizardFlags = map[string]cmdwrapper.Flag{
21-
"isNonInteractiveWindowsMigration": {DefaultValue: "false", Description: "If true, it will use command line args to bypass the wizard. Default value is false."},
22-
"isNonInteractiveLinuxMigration": {DefaultValue: "false", Description: "If true, it will do the linux config migration. Default value is false."},
23-
"tracesOnly": {DefaultValue: "false", Description: "If true, only trace configuration will be generated"},
24-
"useParameterStore": {DefaultValue: "false", Description: "If true, it will use the parameter store for the migrated config storage."},
25-
"nonInteractiveXrayMigration": {DefaultValue: "false", Description: "If true, then this is part of non Interactive xray migration tool."},
21+
"isNonInteractiveWindowsMigration": {DefaultValue: "false", Description: "If true, it will use command line args to bypass the wizard. Default value is false.", IsBool: true},
22+
"isNonInteractiveLinuxMigration": {DefaultValue: "false", Description: "If true, it will do the linux config migration. Default value is false.", IsBool: true},
23+
"tracesOnly": {DefaultValue: "false", Description: "If true, only trace configuration will be generated", IsBool: true},
24+
"useParameterStore": {DefaultValue: "false", Description: "If true, it will use the parameter store for the migrated config storage.", IsBool: true},
25+
"nonInteractiveXrayMigration": {DefaultValue: "false", Description: "If true, then this is part of non Interactive xray migration tool.", IsBool: true},
2626
"configFilePath": {DefaultValue: "", Description: fmt.Sprintf("The path of the old config file. Default is %s on Windows or %s on Linux", DefaultFilePathWindowsConfiguration, DefaultFilePathLinuxConfiguration)},
2727
"configOutputPath": {DefaultValue: "", Description: "Specifies where to write the configuration file generated by the wizard"},
2828
"parameterStoreName": {DefaultValue: "", Description: "The parameter store name. Default is AmazonCloudWatch-windows"},

0 commit comments

Comments
 (0)