From 13e4db3208b4bef83d85a9096ef449810f9e66bb Mon Sep 17 00:00:00 2001 From: Vasubabu <3358152+vasubabu@users.noreply.github.com> Date: Mon, 14 Aug 2023 21:52:35 +0530 Subject: [PATCH] Fix: Resetting always_pxe flag as per user configuration --- docs/metal_device_create.md | 4 +- internal/devices/create.go | 86 ++++++++++++--- internal/devices/update.go | 5 +- .../device_create_flags_test.go | 101 ++++++++++++++++++ .../devicecreatetest/device_create_test.go | 32 ++++-- .../devices/devicegettest/device_get_test.go | 29 +++-- test/helper/helper.go | 43 ++++---- 7 files changed, 248 insertions(+), 52 deletions(-) create mode 100644 test/e2e/devices/devicecreateflagstest/device_create_flags_test.go diff --git a/docs/metal_device_create.md b/docs/metal_device_create.md index af67616c..a13133c8 100644 --- a/docs/metal_device_create.md +++ b/docs/metal_device_create.md @@ -24,7 +24,7 @@ metal device create -p (-m | -f ) -P -H (-m | -f ) -P -H [-H ] [-d ] [--locked ] [-t ] [-u ] [-c ] [-s ] [--always-pxe]`, @@ -76,7 +75,7 @@ func (c *Client) Update() *cobra.Command { } if alwaysPXE { - deviceUpdate.AlwaysPxe = &alwaysPXE + deviceUpdate.SetAlwaysPxe(alwaysPXE) } if ipxescripturl != "" { @@ -114,7 +113,7 @@ func (c *Client) Update() *cobra.Command { updateDeviceCmd.Flags().BoolVarP(&alwaysPXE, "always-pxe", "a", false, "Sets the device to always iPXE on reboot.") updateDeviceCmd.Flags().StringVarP(&ipxescripturl, "ipxe-script-url", "s", "", "Add or update the URL of the iPXE script.") updateDeviceCmd.Flags().StringVarP(&customdata, "customdata", "c", "", "Adds or updates custom data to be included with your device's metadata.") - _ = updateDeviceCmd.MarkFlagRequired("id") + return updateDeviceCmd } diff --git a/test/e2e/devices/devicecreateflagstest/device_create_flags_test.go b/test/e2e/devices/devicecreateflagstest/device_create_flags_test.go new file mode 100644 index 00000000..de98d5fa --- /dev/null +++ b/test/e2e/devices/devicecreateflagstest/device_create_flags_test.go @@ -0,0 +1,101 @@ +package devicecreateflagstest + +import ( + "io" + "os" + "regexp" + "strings" + "testing" + + root "github.com/equinix/metal-cli/internal/cli" + "github.com/equinix/metal-cli/internal/devices" + outputPkg "github.com/equinix/metal-cli/internal/outputs" + "github.com/equinix/metal-cli/test/helper" + "github.com/spf13/cobra" +) + +func TestCli_Devices_Create_Flags(t *testing.T) { + var projectId, deviceId string + var err error + var resp bool + subCommand := "device" + consumerToken := "" + apiURL := "" + Version := "metal" + rootClient := root.NewClient(consumerToken, apiURL, Version) + type fields struct { + MainCmd *cobra.Command + Outputer outputPkg.Outputer + } + tests := []struct { + name string + fields fields + want *cobra.Command + cmdFunc func(*testing.T, *cobra.Command) + }{ + { + name: "create_device", + fields: fields{ + MainCmd: devices.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + projectId, err = helper.CreateTestProject("metal-cli-create-flags-pro") + if err != nil { + t.Error(err) + } + if len(projectId) != 0 { + + root.SetArgs([]string{subCommand, "create", "-p", projectId, "-P", "m3.small.x86", "-m", "da", "-H", "metal-cli-create-flags-dev", "--operating-system", "custom_ipxe", "--always-pxe=true", "--ipxe-script-url", "https://boot.netboot.xyz/"}) + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + if err := root.Execute(); err != nil { + t.Error(err) + } + w.Close() + out, _ := io.ReadAll(r) + os.Stdout = rescueStdout + if !strings.Contains(string(out[:]), "metal-cli-create-flags-dev") && + !strings.Contains(string(out[:]), "Ubuntu 20.04 LTS") && + !strings.Contains(string(out[:]), "queued") { + t.Error("expected output should include metal-cli-create-flags-dev, Ubuntu 20.04 LTS, and queued strings in the out string ") + } + name := "metal-cli-create-flags-dev" + idNamePattern := `(?m)^\| ([a-zA-Z0-9-]+) +\| *` + name + ` *\|` + + // Find the match of the ID and NAME pattern in the table string + match := regexp.MustCompile(idNamePattern).FindStringSubmatch(string(out[:])) + + // Extract the ID from the match + if len(match) > 1 { + deviceId = strings.TrimSpace(match[1]) + resp, err = helper.IsDeviceStateActive(deviceId) + if err == nil && resp == true { + err = helper.CleanTestDevice(deviceId) + if err != nil { + t.Error(err) + } + err = helper.CleanTestProject(projectId) + if err != nil { + t.Error(err) + } + } else { + t.Error(err) + } + } + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rootCmd := rootClient.NewCommand() + rootCmd.AddCommand(tt.fields.MainCmd) + tt.cmdFunc(t, tt.fields.MainCmd) + }) + } +} diff --git a/test/e2e/devices/devicecreatetest/device_create_test.go b/test/e2e/devices/devicecreatetest/device_create_test.go index cb734659..de0c293c 100644 --- a/test/e2e/devices/devicecreatetest/device_create_test.go +++ b/test/e2e/devices/devicecreatetest/device_create_test.go @@ -14,8 +14,10 @@ import ( "github.com/spf13/cobra" ) -func TestCli_Devices_create(t *testing.T) { +func TestCli_Devices_Create(t *testing.T) { var projectId, deviceId string + var err error + var resp bool subCommand := "device" consumerToken := "" apiURL := "" @@ -40,10 +42,13 @@ func TestCli_Devices_create(t *testing.T) { want: &cobra.Command{}, cmdFunc: func(t *testing.T, c *cobra.Command) { root := c.Root() - projectId = helper.Create_test_project("create-device-pro") + projectId, err = helper.CreateTestProject("metal-cli-create-pro") + if err != nil { + t.Error(err) + } if len(projectId) != 0 { - root.SetArgs([]string{subCommand, "create", "-p", projectId, "-P", "c3.small.x86", "-m", "da", "-O", "ubuntu_20_04", "-H", "create-device-dev"}) + root.SetArgs([]string{subCommand, "create", "-p", projectId, "-P", "m3.small.x86", "-m", "da", "-O", "ubuntu_20_04", "-H", "metal-cli-create-dev"}) rescueStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w @@ -53,12 +58,12 @@ func TestCli_Devices_create(t *testing.T) { w.Close() out, _ := io.ReadAll(r) os.Stdout = rescueStdout - if !strings.Contains(string(out[:]), "create-device-dev") && + if !strings.Contains(string(out[:]), "metal-cli-create-dev") && !strings.Contains(string(out[:]), "Ubuntu 20.04 LTS") && !strings.Contains(string(out[:]), "queued") { - t.Error("expected output should include create-device-dev, Ubuntu 20.04 LTS, and queued strings in the out string ") + t.Error("expected output should include metal-cli-create-dev, Ubuntu 20.04 LTS, and queued strings in the out string ") } - name := "create-device-dev" + name := "metal-cli-create-dev" idNamePattern := `(?m)^\| ([a-zA-Z0-9-]+) +\| *` + name + ` *\|` // Find the match of the ID and NAME pattern in the table string @@ -67,9 +72,18 @@ func TestCli_Devices_create(t *testing.T) { // Extract the ID from the match if len(match) > 1 { deviceId = strings.TrimSpace(match[1]) - if helper.Is_Device_state_active(deviceId) { - helper.Clean_test_device(deviceId) - helper.Clean_test_project(projectId) + resp, err = helper.IsDeviceStateActive(deviceId) + if err == nil && resp == true { + err = helper.CleanTestDevice(deviceId) + if err != nil { + t.Error(err) + } + err = helper.CleanTestProject(projectId) + if err != nil { + t.Error(err) + } + } else { + t.Error(err) } } } diff --git a/test/e2e/devices/devicegettest/device_get_test.go b/test/e2e/devices/devicegettest/device_get_test.go index d9a2b5d3..a8383b53 100644 --- a/test/e2e/devices/devicegettest/device_get_test.go +++ b/test/e2e/devices/devicegettest/device_get_test.go @@ -13,8 +13,10 @@ import ( "github.com/spf13/cobra" ) -func TestCli_Devices_get(t *testing.T) { +func TestCli_Devices_Get(t *testing.T) { var projectId, deviceId string + var err error + var resp bool subCommand := "device" consumerToken := "" apiURL := "" @@ -39,8 +41,14 @@ func TestCli_Devices_get(t *testing.T) { want: &cobra.Command{}, cmdFunc: func(t *testing.T, c *cobra.Command) { root := c.Root() - projectId = helper.Create_test_project("get-by-device-id-pro") - deviceId = helper.Create_test_device(projectId, "get-by-device-id-dev") + projectId, err = helper.CreateTestProject("metal-cli-get-pro") + if err != nil { + t.Error(err) + } + deviceId, err = helper.CreateTestDevice(projectId, "metal-cli-get-dev") + if err != nil { + t.Error(err) + } root.SetArgs([]string{subCommand, "get", "-i", deviceId}) rescueStdout := os.Stdout r, w, _ := os.Pipe() @@ -55,9 +63,18 @@ func TestCli_Devices_get(t *testing.T) { t.Error("expected output should include " + deviceId) } if len(projectId) != 0 && len(deviceId) != 0 { - if helper.Is_Device_state_active(deviceId) { - helper.Clean_test_device(deviceId) - helper.Clean_test_project(projectId) + resp, err = helper.IsDeviceStateActive(deviceId) + if err == nil && resp == true { + err = helper.CleanTestDevice(deviceId) + if err != nil { + t.Error(err) + } + err = helper.CleanTestProject(projectId) + if err != nil { + t.Error(err) + } + } else { + t.Error(err) } } }, diff --git a/test/helper/helper.go b/test/helper/helper.go index ed218800..91112e36 100644 --- a/test/helper/helper.go +++ b/test/helper/helper.go @@ -16,80 +16,83 @@ func TestClient() *openapiclient.APIClient { return apiClient } -func Create_test_project(name string) string { +// func Create_test_project(name string) string { +func CreateTestProject(name string) (string, error) { TestApiClient := TestClient() projectCreateFromRootInput := *openapiclient.NewProjectCreateFromRootInput(name) // ProjectCreateFromRootInput | Project to create - include := []string{"Inner_example"} - exclude := []string{"Inner_example"} - projectResp, r, err := TestApiClient.ProjectsApi.CreateProject(context.Background()).ProjectCreateFromRootInput(projectCreateFromRootInput).Include(include).Exclude(exclude).Execute() + projectResp, r, err := TestApiClient.ProjectsApi.CreateProject(context.Background()).ProjectCreateFromRootInput(projectCreateFromRootInput).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ProjectsApi.CreateProject``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - return "" + return "", err } - return projectResp.GetId() + return projectResp.GetId(), nil } -func Create_test_device(projectId, name string) string { - include := []string{"Inner_example"} - exclude := []string{"Inner_example"} - +func CreateTestDevice(projectId, name string) (string, error) { TestApiClient := TestClient() hostname := name metroDeviceRequest := openapiclient.CreateDeviceRequest{ DeviceCreateInMetroInput: &openapiclient.DeviceCreateInMetroInput{ Metro: "da", - Plan: "c3.small.x86", + Plan: "m3.small.x86", OperatingSystem: "ubuntu_20_04", Hostname: &hostname, }, } - deviceResp, _, err := TestApiClient.DevicesApi.CreateDevice(context.Background(), projectId).CreateDeviceRequest(metroDeviceRequest).Include(include).Exclude(exclude).Execute() + deviceResp, _, err := TestApiClient.DevicesApi.CreateDevice(context.Background(), projectId).CreateDeviceRequest(metroDeviceRequest).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `DevicesApi.CreateDevice``: %v\n", err) - return "" + return "", err } - return deviceResp.GetId() + return deviceResp.GetId(), nil } -func Is_Device_state_active(deviceId string) bool { +func IsDeviceStateActive(deviceId string) (bool, error) { + var err error + var resp *openapiclient.Device TestApiClient := TestClient() predefinedTime := 200 * time.Second // Adjust this as needed retryInterval := 10 * time.Second // Adjust this as needed startTime := time.Now() for time.Since(startTime) < predefinedTime { - resp, _, err := TestApiClient.DevicesApi.FindDeviceById(context.Background(), deviceId).Execute() + resp, _, err = TestApiClient.DevicesApi.FindDeviceById(context.Background(), deviceId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `DevicesApi.FindDeviceById``: %v\n", err) + return false, err } if resp.GetState() == "active" { - return true + return true, nil } // Sleep for the specified interval time.Sleep(retryInterval) } - return false + return false, err } -func Clean_test_device(deviceId string) { +func CleanTestDevice(deviceId string) error { forceDelete := true // bool | Force the deletion of the device, by detaching any storage volume still active. (optional) TestApiClient := TestClient() _, err := TestApiClient.DevicesApi.DeleteDevice(context.Background(), deviceId).ForceDelete(forceDelete).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `DevicesApi.DeleteDevice``: %v\n", err) + return err } + return nil } -func Clean_test_project(projectId string) { +func CleanTestProject(projectId string) error { TestApiClient := TestClient() r, err := TestApiClient.ProjectsApi.DeleteProject(context.Background(), projectId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ProjectsApi.DeleteProject``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + return err } + return nil }